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 wins2
if player 2 wins3
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 theOrder
enum (More
,Less
, orSame
), depending on whether the first argument is greater, less, or equal to the second.