List of all games

After asking here, OP is interested in listing all of the unique 2x2 games. The games here are game theory games in which there are two players and two strategies. Therefore, there are four possible results (see. Diagram). These results come with "wins" for each player. Payoff “pairs” are two wins for each player from certain combinations of strategies. Payments are given in whole numbers and cannot exceed 4.

For example, consider the following example of a 2x2 game (with a pair of wins it is written in brackets, and P1 and P2 denote players 1 and 2, respectively):

                  P2
            Right   Left

       Up   (2,2)   (3,4)
   P1         
       Down (1,1)   (4,3)

Here the winnings take the values ​​[(2,2), (3,4) | (1.1), (4.3)].

Now, obviously, many other games are possible (i.e., unique payoff matrices). If the gain for each player is set to 1,2,3,4 (which we can rearrange in 4! = 24 ways), then 24 * 24 games are possible. OP is interested in listing all of these games.

Here comes the thin part: two unique payoff matrices can, nevertheless, represent games, if they can be obtained from another using

i) column exchange (i.e. relabel Player A strategies)

ii) swap strings (i.e. iterate over player B's strategies)

iii) Player exchange (i.e. exchange of payout pairs and mirroring the matrix along the first diagonal)

OP posted the following code that correctly lists all 78 possible games in which there can be winnings for each (1,2,3,4).

, , : .. (1,2,3,3) 1 (1,2,3,4) 2. 4!/2! (1,2,3,3) , , .

    #!/usr/bin/groovy

    // Payoff Tuple (a,b) found in game matrix position.
    // The Tuple is immutable, if we need to change it, we create a new one.
    // "equals()" checks for equality against another Tuple instance.
    // "hashCode()" is needed for insertion/retrievel of a Tuple instance into/from
    // a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers.)

    class Tuple {

       final int a,b

       Tuple(int a,int b) {
          assert 1 <= a && a <= 4
          assert 1 <= b && b <= 4
          this.a = a
          this.b = b
       }

    #!/usr/bin/groovy

    // Payoff Tuple (a,b) found in game matrix position.
    // The Tuple is immutable, if we need to change it, we create a new one.
    // "equals()" checks for equality against another Tuple instance.
    // "hashCode()" is needed for insertion/retrievel of a Tuple instance into/from
    // a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers.)

    class Tuple {

       final int a,b

       Tuple(int a,int b) {
          assert 1 <= a && a <= 4
          assert 1 <= b && b <= 4
          this.a = a
          this.b = b
       }

       boolean equals(def o) {
          if (!(o && o instanceof Tuple)) {
             return false
          }
          return a == o.a && b == o.b
       }

       int hashCode() {
          return (a-1) * 4 + (b-1)
       }

       String toString() {
          return "($a,$b)"
       }

       Tuple flip() {
          return new Tuple(b,a)
       }
    }

    // "GameMatrix" is an immutable structure of 2 x 2 Tuples:
    // top left, top right, bottom left, bottom right
    // "equals()" checks for equality against another GameMatrix instance.
    // "hashCode()" is needed for insertion/retrievel of a GameMatrix instance into/from
    // a "Map" (in this case, the hashCode() actually a one-to-one mapping to the integers)

    class GameMatrix {

       final Tuple tl, tr, bl, br

       GameMatrix(Tuple tl,tr,bl,br) {
          assert tl && tr && bl && br
          this.tl = tl; this.tr = tr
          this.bl = bl; this.br = br
       }

       GameMatrix colExchange() {
          return new GameMatrix(tr,tl,br,bl)
       }

       GameMatrix rowExchange() {
          return new GameMatrix(bl,br,tl,tr)
       }

       GameMatrix playerExchange() {
          return new GameMatrix(tl.flip(),bl.flip(),tr.flip(),br.flip())
       }

       GameMatrix mirror() {
          // columnEchange followed by rowExchange
          return new GameMatrix(br,bl,tr,tl)
       }

       String toString() {
          return "[ ${tl},${tr} | ${bl},${br} ]"
       }

       boolean equals(def o) {
          if (!(o && o instanceof GameMatrix)) {
             return false
          }
          return tl == o.tl && tr == o.tr && bl == o.bl && br == o.br
       }

       int hashCode() {
          return (( tl.hashCode() * 16 + tr.hashCode() ) * 16 + bl.hashCode() ) * 16 + br.hashCode()     
       }

    }

    // Check whether a GameMatrix can be mapped to a member of the "canonicals", the set of 
    // equivalence class representatives, using a reduced set of transformations. Technically,
    // "canonicals" is a "Map" because we want to not only ask the membership question, but 
    // also obtain the canonical member, which is easily done using a Map. 
    // The method returns the array [ canonical member, string describing the operation chain ]
    // if found, [ null, null ] otherwise.

    static dupCheck(GameMatrix gm, Map canonicals) {
       // Applying only one of rowExchange, colExchange, mirror will
       // never generate a member of "canonicals" as all of these have player A payoff 4
       // at topleft, and so does gm
       def q     = gm.playerExchange()
       def chain = "player"
       if (q.tl.a == 4) {
       }
       else if (q.tr.a == 4) {
          q = q.colExchange(); chain = "column ∘ ${chain}"
       }
       else if (q.bl.a == 4) {
          q = q.rowExchange(); chain = "row ∘ ${chain}"
       }
       else if (q.br.a == 4) {
          q = q.mirror(); chain = "mirror ∘ ${chain}"
       }
       else {
          assert false : "Can't happen"
       }
       assert q.tl.a == 4
       return (canonicals[q]) ? [ canonicals[q], chain ] : [ null, null ]
    }

    // Main enumerates all the possible Game Matrixes and builds the
    // set of equivalence class representatives, "canonicals".
    // We only bother to generate Game Matrixes of the form
    // [ (4,_) , (_,_) | (_,_) , (_,_) ]
    // as any other Game Matrix can be trivially transformed into the
    // above form using row, column and player exchange.

    static main(String[] argv) {
       def canonicals = [:]
       def i = 1
       [3,2,1].permutations { payoffs_playerA ->
          [4,3,2,1].permutations { payoffs_playerB ->
             def gm = new GameMatrix(
                           new Tuple(4,                  payoffs_playerB[0]),
                           new Tuple(payoffs_playerA[0], payoffs_playerB[1]),
                           new Tuple(payoffs_playerA[1], payoffs_playerB[2]),
                           new Tuple(payoffs_playerA[2], payoffs_playerB[3])
                      )
             def ( c, chain ) = dupCheck(gm,canonicals)
             if (c) {
                System.out << "${gm} equivalent to ${c} via ${chain}\n"
             }
             else {
                System.out << "${gm} accepted as canonical entry ${i}\n"
                canonicals[gm] = gm
                i++
             }
          }
       }
    }

"assert 1 <= a && a <= 4", " 1 <= a && a <= 3", 4 a 3 . .

, , "int hashCode() {return (a-1) * 4 + (b-1)" if "(q.tl.a == 4) { }          else if (q.tr.a == 4) {" , .

, , , , , ( 1,2,3,4 1,2,3,3).


, .

enter image description here

+6
1

, Othello/Reversi, , , . , , , -, , -, , . , , -. , , , .

, , , , 4 (identity, h-flip, v-vlip, hv-flip) .

+1

All Articles