Find the outcome of a game of War

Python, 139 Bytes

c=d=0
for i in input():
 b=(c&(i=='fr'))-(d&(i=='rf'));p,q=i
 if b|(i=='ff')&c&d:print b;break
 c,d=(p=='r',i!='fg')[c],(q=='r',i!='gf')[d]

Takes input on stdin in the form of a list of 2-character strings (eg. ['rf','rr','rg','ff']). Outputs 1 if player 1 wins, -1 if player 2 wins, and 0 for a draw.

Explanation: First checks if anyone fired a bullet, if so the game ends. Then we determine if the players have either reloaded their guns or wasted their ammo.

This is my first codegolf post :)


JavaScript (ES6), 108 107 93 91 89 85 bytes

Saved 4 bytes with the help of Titus

Takes input as an array of 2-character strings describing the moves played by each player.

b=>b.map(c=>w=w||b&'312'[b=(s='0210231')[m='ffrfgrrggf'.search(c)]|s[m-2]&b,m],w=0)|w

Returns:

  • 1 if player 1 wins
  • 2 if player 2 wins
  • 3 for a draw

How it works

We maintain a bitmask b describing who has a loaded bullet:

  • bit #0: player 1 has a bullet
  • bit #1: player 2 has a bullet

We use the De Bruijn sequence 'ffrfgrrggf' to identify all 9 possible combinations of moves. We use OR and AND bitmasks to update b according to the move combination. We use a 3rd set of bitmasks which are AND'ed with b to determine the winner w. (The only three winning combinations being ff, fr and rf.)

It's worth noting that the OR and AND masks can be stored with the same pattern, shifted by two positions.

 Index in | Combination | Bullet   | Bullet  | Winner
 sequence |             | AND mask | OR mask | mask
----------+-------------+----------+---------+--------
    0     |     ff      |    0     |    0    |   3
    1     |     fr      |    0     |    2    |   1
    2     |     rf      |    0     |    1    |   2
    3     |     fg      |    2     |    0    |   0
    4     |     gr      |    1     |    2    |   0
    5     |     rr      |    0     |    3    |   0
    6     |     rg      |    2     |    1    |   0
    7     |     gg      |    3     |    0    |   0
    8     |     gf      |    1     |    0    |   0

Test cases

let f =

b=>b.map(c=>w=w||b&'312'[b=(s='0210231')[m='ffrfgrrggf'.search(c)]|s[m-2]&b,m],w=0)|w

console.log(f(["rg","fr"]));                            // 1
console.log(f(["rg","ff"]));                            // 1
console.log(f(["rr","ff"]));                            // 3
console.log(f(["rr","ff","rr","fg"]));                  // 3
console.log(f(["rr","fg","rf"]));                       // 2
console.log(f(["rf","gg","rr","fg","rr","fr"]));        // 1
console.log(f(["rr","gf","fr","rf","gg","rg","ff"]));   // 1


Perl 6, 71 62 bytes

{&[<=>](|map {m/r[..[r|g]]*.$^f/.to//∞},/[r|f]f/,/.f[r|f]/)}

Regex-based solution.

Takes input as a string in the form "rg fr".
The three possible outputs are the enum values More (player 1 won), Less ( player 2 won), Same (draw) – which turn into those words when printed, or into 1, -1, 0 when coerced to numbers.

Try it online!

How it works

  • map { m/r[..[r|g]]*.$^f/.to // ∞ }, /[r|f]f/, /.f[r|f]/

    Performs two regex matches on the input. After interpolation, the two regexes are:

    • r[..[r|g]]*.[r|f]f – Matches the first successful shot by player 2.
    • r[..[r|g]]*..f[r|f] – Matches the first successful shot by player 1.

    In each case, it returns the end position of the match (.to), or infinity if there was no match.

  • &[<=>](|   )

    Applies the <=> operator to the two match end positions. It returns a value from the Order enum (More, Less, or Same), depending on whether the first argument is greater, less, or equal to the second.

Tags:

Code Golf

Game