10
\$\begingroup\$

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
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Related 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). \$\endgroup\$
    – Doorknob
    Mar 23, 2016 at 20:12

4 Answers 4

6
\$\begingroup\$

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.
\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
5
  • \$\begingroup\$ m|Fd is the same as |M. \$\endgroup\$
    – isaacg
    Mar 23, 2016 at 22:59
  • \$\begingroup\$ @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 \$\endgroup\$
    – Denker
    Mar 23, 2016 at 23:10
  • \$\begingroup\$ ,1 2 is the same as S2 \$\endgroup\$
    – isaacg
    Mar 23, 2016 at 23:16
  • \$\begingroup\$ I've added another testcase ;) \$\endgroup\$
    – removed
    Mar 24, 2016 at 1:44
  • \$\begingroup\$ @isaacg Thanks again! Don't know how I missed that. \$\endgroup\$
    – Denker
    Mar 24, 2016 at 8:29
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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?

\$\endgroup\$
10
  • \$\begingroup\$ I've added another testcase ;) \$\endgroup\$
    – removed
    Mar 24, 2016 at 1:44
  • 1
    \$\begingroup\$ @WashingtonGuedes And mine works on this case thanks to my logic reordering! \$\endgroup\$
    – CAD97
    Mar 24, 2016 at 1:47
  • \$\begingroup\$ Can the ifs be made into ternarys? e.g. w==2&&m<1?r--:m++ \$\endgroup\$
    – Downgoat
    Mar 24, 2016 at 3:08
  • \$\begingroup\$ @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. \$\endgroup\$
    – CAD97
    Mar 24, 2016 at 3:13
  • 1
    \$\begingroup\$ @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--; \$\endgroup\$
    – MrPublic
    Mar 24, 2016 at 12:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.