15
\$\begingroup\$

Given two lists of dice rolls for a battle in Risk, your program or function must output how many troops each player loses.

Background

You do not have to read this, for it is merely background. Skip to "Task" subheading to continue unabated.

In the game of Risk, one player can attack another player (in fact, this is necessary to win). The outcome of a battle is determined by the roll of dice. Every battle occurs as a succession of sub-battles in which each player can lose up to 2 of their army pieces.

In a sub-battle, the defender and attacker each roll several dice whose number may vary based on circumstances irrelevant to this challenge. The highest-valued die of the attacker is compared to the highest-valued die of the defender. If the attacker's die is higher than the defender's die, the defender loses one piece. Otherwise, the attacker loses one piece.

Then, if both players have at least two dice, the second-highest valued dice of the two players are compared. Again, if the attacker's die is higher than the defender's die, the defender loses one piece. Otherwise, the attacker loses one piece.

(Defender wins ties. If both defender and attacker roll a 4, then the attacker loses a piece.)

Dice Comparison

In this sub-battle from the Wikipedia article, the attacker's dice are red and the defender's dice are white. The highest of the attacker's dice is 4 and the highest of the defender's is 3. Since the attacker was higher, the defender loses a piece. The second-highest are 3 for the attacker and 2 for the defender. Since the attacker was again higher, the defender loses another piece. Thus in this sub-battle, the attacker loses no pieces and the defender loses 2 pieces.

Note that the third-highest pieces are not compared. This is because the defender has no more than two dice on a single sub-battle, so there are no third-highest pieces to compare ever.

Task

Given the unsorted dice rolls (integers in the range 1 to 6 inclusive) of both the attacker and the defender of a sub-battle of Risk in any convenient form, output the number of army pieces each player loses. The output may be in any convenient form, as long as it has different outputs to indicate the five possibilities. You must indicate what those different outputs are in your question.

The output is determined as follows: Start with def=0 and atk=0. If the greatest value of the list of dice rolls of the attacker is greater than the greatest value of the list of dice rolls of the defender, then increment def. Otherwise, increment atk.

If both lists of dice rolls have length at least 2, then: if the second-greatest value of the list of dice rolls of the attacker is greater than the second-greatest value of the list, then increment def and otherwise increment atk.

Finally, the program or function must output a unique identifier for each of the following 5 output possibilities:

  ╔═══╦═══╗
  ║atk║def║
  ╠═══╬═══╣
  ║ 1 ║ 0 ║
  ║ 0 ║ 1 ║
  ║ 2 ║ 0 ║
  ║ 1 ║ 1 ║
  ║ 0 ║ 2 ║
  ╚═══╩═══╝

Example

Defender: [3, 2] Attacker: [2, 4, 1] Max of defender is 3 and max of attacker is 4. 4>3, so def=1 Second of defender is 2 and second of attacker is 2. Not(2>2), so atk=1. The output could then be [1,1].

Test Cases

Defender
Attacker
Output (as [def,atk])
-----
[1]
[1]
[0,1]
-----
[6,6]
[1,1,1]
[0,2]
-----
[1,2]
[5,2,3]
[2,0]
-----
[5]
[3,4]
[0,1]
-----
[4]
[4,5]
[1,0]
-----
[1,3]
[1,2,3]
[1,1]
-----
[4]
[4,5,6]
[1,0]
-----
[4,5]
[6,2]
[1,1]
-----
[5]
[6,1,3]
[1,0]
-----
[5,5]
[4,4,1]
[0,2]
-----
[2,5]
[2,2]
[0,2]
-----
[6,6]
[4,4,3]
[0,2]
-----
[2,1]
[4,3]
[2,0]
-----
[4]
[1,5]
[1,0]
-----
[1]
[5,2]
[1,0]
-----
[6,2]
[4]
[0,1]
-----
[4,2]
[2,5,5]
[2,0]
-----
[2]
[6,6,2]
[1,0]
-----
[6]
[2,6]
[0,1]
-----
[3,1]
[1]
[0,1]
-----
[6,2]
[3,5,2]
[1,1]
-----
[4,2]
[1,1]
[0,2]
-----
[4,3]
[5,4,1]
[2,0]
-----
[5,6]
[1,2]
[0,2]
-----
[3,2]
[4,4]
[2,0]
-----
[2]
[6,3,4]
[1,0]
-----
[1,4]
[6,2,4]
[2,0]
-----
[4,2]
[2,5,4]
[2,0]
-----
[5]
[6,2,1]
[1,0]
-----
[3]
[2,5,4]
[1,0]
-----
[5,4]
[2]
[0,1]
-----
[6,3]
[2,6,5]
[1,1]
-----
[3,1]
[4]
[1,0]
-----
[4]
[6,6,5]
[1,0]
-----
[6,3]
[4,2]
[0,2]
-----
[1,6]
[5,4]
[1,1]
-----
[3,6]
[4,4]
[1,1]
-----
[5,4]
[5,1,1]
[0,2]
-----
[6,3]
[5,4]
[1,1]
-----
[2,6]
[1,2]
[0,2]
-----
[4,2]
[3,5,5]
[2,0]
-----
[1]
[1,2,1]
[1,0]
-----
[4,5]
[1,6]
[1,1]
-----
[1]
[3,5,1]
[1,0]
-----
[6,2]
[6,2]
[0,2]

Sample implementation

Python 2 or 3

def risk(atk_rolls,def_rolls):
    # set the rolls in descending order, e.g. [5,3,2]
    atk_rolls = sorted(atk_rolls,reverse = True)
    def_rolls = sorted(def_rolls,reverse = True)
    # minimum length.
    minlen = min(len(atk_rolls),len(def_rolls))
    atk_lost = 0
    def_lost = 0
    # compare the highest-valued rolls
    if atk_rolls[0]>def_rolls[0]:
        def_lost += 1
    else:
        atk_lost += 1
    if minlen == 2:
        # compare the second-highest-valued rolls
        if atk_rolls[1] > def_rolls[1]:
            def_lost += 1
        else:
            atk_lost += 1
    return [def_lost, atk_lost]    

Specifications

  • The input may be taken as any form that clearly encodes only the defender's rolls and the attacker's rolls.
  • The output may be in any form that provides a unique output for each of the five possibilities listed above.
  • The defender's rolls are a list of 1 or 2 integers in the set [1,2,3,4,5,6]. The attacker's rolls are a list of 1 to 3 integers in the set [1,2,3,4,5,6].
  • Since this is , shortest code in each language wins! Do not let answers in golfing languages discourage you from posting answers in other languages.
\$\endgroup\$
5
  • \$\begingroup\$ Saw this on the sandbox, nice question \$\endgroup\$ Jul 27, 2017 at 19:51
  • \$\begingroup\$ codegolf.meta.stackexchange.com/a/13456/61877 \$\endgroup\$ Jul 27, 2017 at 19:51
  • \$\begingroup\$ The attacker loses if its maximum roll is equal to the defender's highest roll, right? \$\endgroup\$
    – Mr. Xcoder
    Jul 27, 2017 at 20:02
  • 1
    \$\begingroup\$ Yes @Mr.Xcoder, the defender wins ties. \$\endgroup\$ Jul 27, 2017 at 20:03
  • \$\begingroup\$ Hence I deleted the comment :) \$\endgroup\$
    – Mr. Xcoder
    Jul 27, 2017 at 20:43

10 Answers 10

8
\$\begingroup\$

NAND gates, 237

Created with Logisim

Inputs are 3-bit unsigned binary, entered on the left. Outputs (2 bits) are on the right.

It is too large to fit on the screen and Logisim can't zoom, so the image is black-and-white. Sorry :(

Works for all test cases.

There is likely a better way to do this using some memory circuit, allowing large sections to be reused.

\$\endgroup\$
4
\$\begingroup\$

Jelly,  12  11 bytes

NṢ€>/Ṡḟ-o-S

A monadic link taking a list of Defender, Attacker rolls (each as lists), returning an integer between -2 and 2 inclusive (defender losses - attacker losses):

result : [def, atk]
    -2 : [  0,   2]
    -1 : [  0,   1]
     0 : [  1,   1]
     1 : [  1,   0]
     2 : [  2,   0]

Try it online! or see a test suite (which maps the results to the OP format).

How?

NṢ€>/Ṡḟ-o-S - Link: list [list Def, list Atk]
N           - negate all the rolls
 Ṣ€         - sort €ach of the lists of -1*rolls (max rolls are to the left now)
    /       - reduce by:
   >        -   is greater than?  (when len(Atk) > len(Def) leaves trailing negatives)
     Ṡ      - sign (maps all negatives to -1; zeros and ones of comparison unchanged)
       -    - literal -1
      ḟ     - filter discard (remove the -1s)
         -  - literal -1
        o   - logical or, vectorises (replaces the zeros with minus ones)
          S - sum
\$\endgroup\$
3
\$\begingroup\$

Husk, 10 bytes

M#eI¬¤z>Ö>

Try it online!

Input as two separate lists of rolls, output as in the op.

Explanation

¤z>Ö> sorts each list in descending order and then zips them comparing corresponding elements (and truncating the longer list).

M#eI¬ creates a 2-element list (e) with counts (#) of truthy values (through identity I) and falsy values (through logical negation ¬)

\$\endgroup\$
2
\$\begingroup\$

Retina, 82 bytes

%O^`.
((.)+).*(¶(?<-2>.)+)(?(2)(?!)).*
$1$3
O$`.
$.%`
\d
$*1D
(1+)D1*\1

1+D
A
O`.

Try it online! First line of input is attacker's dice, second is defender's dice. Returns (on separate lines) AA, AD, DD, A or D as appropriate.

\$\endgroup\$
2
\$\begingroup\$

Python 2, 83 75 bytes

x=0
k=map(sorted,input())
while all(k):x+=cmp(*map(list.pop,k))or 1
print-x

Try it online!

Output is defender losses - attacker losses

\$\endgroup\$
2
\$\begingroup\$

MATL, 23 bytes

oH2$S1&Y)Y&t1M>t~b,Y&sD

Try it online!

Not sure why defenders are allowed more dice than attackers, but maybe I am not that well versed in Risk. The core program is just >t~,sD, all the other bytes are there to allow for different input lengths, with a bit of sorting thrown in. Input is attacker followed by defender, output is attacker losses followed by defender losses.

o    % Convert input to numeric array, padding with zeroes 
H2$S % Sort row-wise (specified to prevent 1v1 sorting)
1&Y) % Split attacker/defender
Y&t  % Logical and to filter out excess dice. Duplicate for 'do twice' later.
1M>  % Get throws again, decide who won
t~   % And the inverse to decide who lost
b,   % Bubble filter to the top. Do twice:
  Y& % Apply filter
  sD % Sum of losses. Display.
\$\endgroup\$
2
\$\begingroup\$

JavaScript (SpiderMonkey), 97 83 78 bytes

d=>a=>{for(u=v=0;d.sort()>[]&a.sort()>[];)a.pop()>d.pop()?u++:v++
return[u,v]}

Try it online!

-4 bytes and fixed thanks to @ovs and @Craig Ayre
-1 byte thanks to @Shaggy

\$\endgroup\$
6
  • \$\begingroup\$ Doesn't work for one attacker against two defenders. \$\endgroup\$
    – Neil
    Jul 27, 2017 at 21:16
  • \$\begingroup\$ Oh hmm I didn't think about that. I'll fix it \$\endgroup\$
    – WaffleCohn
    Jul 27, 2017 at 22:29
  • 2
    \$\begingroup\$ This might work. \$\endgroup\$
    – ovs
    Jul 28, 2017 at 10:14
  • \$\begingroup\$ @ovs's solution passes all test cases, you can save a few bytes too (tio link was too large): d=>a=>{for(u=v=0;d.sort()>[]&a.sort()>[];)a.pop()>d.pop()?u++:v++;return[u,v]} \$\endgroup\$
    – Craig Ayre
    Jul 28, 2017 at 11:19
  • \$\begingroup\$ The first line break is unnecessary and costing you a byte. \$\endgroup\$
    – Shaggy
    Jul 28, 2017 at 13:40
1
\$\begingroup\$

Perl 5, 66 + 1 (-a) = 67 bytes

@A=sort split/ /,<>;$b+=@A?pop@A>$_?-1:1:0for reverse sort@F;say$b

Try it online!

Input:

Two lines. First line is defender (player 1), second is attacker (player 2). Individual rolls separated by spaces.

Output:

Indicates effective change in defender's strength vs. attacker.

Output Attacker Defender
   2      0        2        Defender wins both
   1      0        1        Defender wins the only roll
   0      1        1        Attacker wins first, defender wins second
  -1      1        0        Attacker wins the only roll
  -2      2        0        Attacker wins both rolls
\$\endgroup\$
2
  • \$\begingroup\$ "The program or function must output a unique identifier for each of the 5 output possibilities." Yours has two outputs for [1,1]. Please edit your answer to fix this ( just sort or sum) \$\endgroup\$ Jul 28, 2017 at 14:56
  • \$\begingroup\$ What's wrong with six? It's more specific. :) I changed it at a cost of 6 bytes. \$\endgroup\$
    – Xcali
    Jul 28, 2017 at 15:18
1
\$\begingroup\$

R, 46 bytes

function(x,y)s(s(y,T)[1:2]>s(x,T)[1:2])
s=sort

Try it online!

All this does is three sorts and one comparison... plus extracting the first two elements in the middle.

Input is two vectors of dice rolls.

Output encoded as follows:

╔═══╦═══╗
║atk║def║
╠═══╬═══╣
║ 1 ║ 0 ║ TRUE
║ 0 ║ 1 ║ FALSE
║ 2 ║ 0 ║ TRUE  TRUE
║ 1 ║ 1 ║ FALSE TRUE
║ 0 ║ 2 ║ FALSE FALSE
╚═══╩═══╝

Works because extraction in R does not recycle its argument, but pads the result with NA to get to the requested length.

\$\endgroup\$
0
\$\begingroup\$

Jelly, 30 bytes

0,0‘⁸Ṁ€</¤¦‘⁸ḟ"Ṁ€⁺</¤¦⁸L€Ṃ>1¤¡

Try it online!

Veeeeeeeery ungolfed! >_<

Outputs values exactly as in test cases.

\$\endgroup\$
1
  • \$\begingroup\$ Wow, this seems way too long even to me :P \$\endgroup\$
    – Mr. Xcoder
    Jul 27, 2017 at 20:23

Your Answer

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

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