Score a game of Load, Defend and Shoot

11

When I was a child, I used to play this game a lot.

Rules

There are two players (let's call them A and B), and each player uses his hands as guns. There are three possible moves:

  1. Hands up to load ammunition to your gun.

    Each gun starts empty. Loading increases the ammunition by one.

  2. Hands pointing to the other player to shoot.

    This decreases the ammunition by one. You must have at least one unit of ammo to shoot.

  3. Crossed arms to protect yourself from a shot.

Both players move simultaneously. If both players shoot at the same time, the bullets hit each other, and the game continues. The game ends when one player shoots while the other is loading ammunition.

Shooting and empty gun is considered cheating. If a player cheats while the other one performs a legal action, the cheater loses immediately. If both players cheat at the same time, the game continues.

Cheating attempts do not decrease ammunition, so it can never be negative.

Challenge

Given the moves made by players A and B, output which player won the game: 1 for player A, -1 for player B, and 0 for a draw. You can use any other triple of return values, but you need to state in your answer which ones you use.

The game may:

  • end without having to process all moves;
  • not end with the given moves, and thus it is considered a draw.

The input can be taken:

  • as strings
  • as arrays/lists of integers
  • in any other way that does not pre-process the input

Full program or functions allowed. Since this is , the shortest answer in bytes wins!

Test cases

A: "123331123"
B: "131122332"
    -----^                Player B shoots player A and wins.

Output: -1
A: "111322213312"
B: "131332221133"
    -------^              Player B cheats and loses.

Output: 1
A: "1333211232221"
B: "1213211322221"
    ----------^^          Both players cheat at the same time. The game continues.

Output: 0
A: "12333213112222212"
B: "13122213312232211"
         |       || ^---- Player A shoots player B and wins.
         ^-------^^------ Both players cheat at the same time. The game continues.

Output: 1

removed

Posted 2016-03-23T20:09:06.247

Reputation: 2 785

1Related KotH (interestingly, I've never played this variant of the game; I think the linked question was inspired by a friend who had, but it was long enough ago that I don't remember anymore). – Doorknob – 2016-03-23T20:12:00.753

Answers

6

Jelly, 33 32 24 bytes

Zæ%1.»0$+¥\>-‘żZḅ3Ff5,7Ḣ

This prints 5 instead of -1, and 7 instead of 1. Try it online! or verify all test cases.

How it works

Zæ%1.»0$+¥\>-‘żZḅ3Ff5,7Ḣ  Main link. Argument: A (digit list array)

Z                         Zip; group corresponding digits.
 æ%1.                     Map the digits in (-1.5, 1.5].
                          This replaces [1, 2, 3] with [1, -1, 0].
          \               Cumulatively reduce the pairs by doing the following.
     »0$                    Take the maximum of the left value and 0, i.e., replace
                            a -1 with a 0.
        +¥                  Add the modified left value to the right value.
                          This computes the available ammo after each action. An
                          ammo of -1 indicates a cheating attempt.
           >-             Compare the results with -1.
             ‘            Increment. And unilateral cheating attempt is now [1, 2]
                          or [2, 1], where 1 signals the cheater and 2 the winner.
              żZ          Pair each result with the corr., original digits.
                ḅ3        Convert each pair from base 3 to integer.
                          This maps [1, 2] and [2, 1] to 5 and 7.
                  F       Flatten the resulting, nested list.
                   f5,7   Discard all but 5's and 7's.
                       Ḣ  Grab the first element (5 or 7).
                          If the list is empty, this returns 0.

Dennis

Posted 2016-03-23T20:09:06.247

Reputation: 196 637

2

Pyth, 48 46 49 47 bytes

.xhfT|M.e,-FmgF.b/<dhkY2S2Q?}b_BS2-FbZ.b,NYCQ)0

Try it here!

Thanks to @isaacg for saving 2 4 bytes!

Takes input as a 2-tuple with the list of the moves of player A first and the moves of player B second. Output is the same as in the challenge.

Explanation

Short overview

  • First we group the moves of both players together, so we get a list of 2-tuples.
  • Then we map each of those tuples to another 2-tuple in the form [cheating win, fair win] with the possible values -1, 0, 1 for each of it, to indicate if a player won at this point (-1, 1) or if the game goes on (0)
  • Now we just need to get the first tuple which is not [0,0], and take the first non-zero element of it which indicates the winner

Code breakdown

.xhfT|M.e,-FmgF.b/<dhkY2S2Q?}b_BS2-FbZ.b,NYCQ)0  # Q = list of the move lists

                                      .b,NYCQ    # pair the elements of both input lists
       .e                                        # map over the list of pairs with 
                                                 # b being the pair and k it's index
            m             Q                      # map each move list d
               .b      2S2                       # map over [1,2], I can't use m because it's
                                                 # lambda variable conflicts with the one from .e
                  <dhk                           # d[:k+1]
                 /    Y                          # count occurences of 1 or 2 in this list
          -F                                     # (count of 1s)-(count of 2s), indicates cheating win
                           ?}b_BS2               # if b is (1,2) or (2,1)
                                  -Fb            # take the difference, indicates fair win
                                     Z           # else 0, no winner yet
         ,                                       # pair those 2 values
     |M                                          # For each resulting pair, take the first one if
                                                 # its not zero, otherwise the second one
   fT                                            # filter all zero values out
.xh                                              # try to take the first value which indicates the winner
                                             )0  # if thats not possible because the list is empty
                                                 # output  zero to indicate a draw

Denker

Posted 2016-03-23T20:09:06.247

Reputation: 6 639

m|Fd is the same as |M. – isaacg – 2016-03-23T22:59:18.963

@isaacg Thanks! I always forget that M does splatting as well. Btw: The issue about conflicting lambda variables we discussed in chat is costing me several bytes here :P – Denker – 2016-03-23T23:10:27.403

,1 2 is the same as S2 – isaacg – 2016-03-23T23:16:11.730

I've added another testcase ;) – removed – 2016-03-24T01:44:46.740

@isaacg Thanks again! Don't know how I missed that. – Denker – 2016-03-24T08:29:33.657

1

Java, 226 212 200 196 194 bytes

-14 bytes by re-ordering logic

-12 bytes thanks to Mr Public pointing out how to use a ternary operation for the shooting logic

-4 bytes by cramming load logic into one short-circuiting if

-2 bytes because ==1 === <2 when input can only be 1,2,3

(a,b)->{for(int m=0,n=0,w,v,r=0,i=0,x;i<a.length;){w=a[i];v=b[i++];x=w==2?m<1?r--:m--:0;x=v==2?n<1?r++:n--:0;if(r!=0)return r;if(w<2&&++m>0&v==2)return -1;if(v<2&&++n>0&w==2)return 1;}return 0;}

Usage and indented version:

static BiFunction<Integer[], Integer[], Integer> game = (a,b) -> {
    for(int m=0,n=0,w,v,r=0,i=0,x;i<a.length;) {
        w=a[i];v=b[i++];
        // shoot
        x=w==2?m<1?r--:m--:0;
        x=v==2?n<1?r++:n--:0;
        if(r!=0)return r;
        // load
        if(w<2&&++m>0&v==2)return -1;
        if(v<2&&++n>0&w==2)return 1;
    }
    return 0;
};

public static void main(String[] args) {
    System.out.println(game.apply(new Integer[] {1,2,3,3,3,1,1,2,3}, new Integer[] {1,3,1,1,2,2,3,3,2}));
    System.out.println(game.apply(new Integer[] {1,1,1,3,2,2,2,1,3,3,1,2}, new Integer[] {1,3,1,3,3,2,2,2,1,1,3,3}));
    System.out.println(game.apply(new Integer[] {1,3,3,3,2,1,1,2,3,2,2,2,1}, new Integer[] {1,2,1,3,2,1,1,3,2,2,2,2,1}));
}

Not so straightforward implementation of the game rules anymore, but simple. Each cycle, does these operations:

  • Load moves into temp variables
  • If player shot
    • without ammo: bias cheater towards losing
    • with ammo: decrement ammo
  • If cheater is not 0, return the value because someone cheated
  • If player reloaded
    • increment ammo
    • if other player shot, return loss

x is a dummy variable used to make the compiler let me use a ternary expression.

Wait, Java is SHORTER than Python?

CAD97

Posted 2016-03-23T20:09:06.247

Reputation: 1 367

I've added another testcase ;) – removed – 2016-03-24T01:44:43.193

1@WashingtonGuedes And mine works on this case thanks to my logic reordering! – CAD97 – 2016-03-24T01:47:01.630

Can the ifs be made into ternarys? e.g. w==2&&m<1?r--:m++ – Downgoat – 2016-03-24T03:08:57.753

@Downgoat the else goes with the inner if so as you've written it the tertiary wouldn't work. However, I can probably do so with the inner if. I'll test it when I get a chance. – CAD97 – 2016-03-24T03:13:34.623

oh, then would w==2?m<1&&r--:m++ work? – Downgoat – 2016-03-24T03:14:38.940

1@CAD97 @Downgoat You can actually use ternary operators for the if-statements. For the first ternary, int x=w==2?m<1?r--:r:m--; then continue to use the x (as this is just a dummy variable to make the ternary operate) like x=v==2?n<1?r++:r:n--; – Mr Public – 2016-03-24T12:24:34.017

@MrPublic I had to change the order to get the logic to work, but thanks for pointing out how to convince the compiler to let us use a ternary! – CAD97 – 2016-03-24T17:22:25.103

Would m=n=r=i=0 work instead of putting 0 multiple times? – Blue – 2016-03-24T22:26:46.180

@Blue it works out to be 2 characters longer. Removing =0 in the initial declaration then adding m= for each variable leaves 0; to be added. (That was a bad explanation.) – CAD97 – 2016-03-24T22:29:50.927

@CAD97 ah, I forgot that Java doesn't particularly like the nested declarations (like the one I showed earlier). – Blue – 2016-03-24T22:36:40.637

1

Python, 217 bytes

def f(A,B):
 x=y=0;c=[-1,1,0]
 for i in range(len(A)):
  a=A[i];b=B[i]
  for s in[0,1]:
   if(a,b)==(2,1):return c[s]*c[x<1]
   if(a,b)==(2,3)and x<1:return-c[s]
   x-=c[a-1];x+=x<0;a,b,x,y=b,a,y,x
 return 0

Explanation: Takes A and B as lists of integers. Simply goes through each pair of moves, adds or subtracts 1 if needed and returns when someone cheats or wins. Does the same thing twice using another for loop, once for A's move and once for B's move. Adds 1 if x goes below 0 to -1.

Fricative Melon

Posted 2016-03-23T20:09:06.247

Reputation: 1 312