War card game

Revision as of 17:44, 10 August 2021 by Wherrera (talk | contribs) (draft -> task)


War Card Game

Simulate the card game War. Use the Bicycle playing card manufacturer's rules. Show a game as played. User input is optional.

References:

Related tasks:


11l

Translation of: Python

<lang 11l>UInt32 seed = 0 F nonrandom(n)

  :seed = (1664525 * :seed + 1013904223) [&] FFFF'FFFF
  R Int(:seed >> 16) % n

F nonrandom_shuffle(&x)

  L(i) (x.len - 1 .< 0).step(-1)
     V j = nonrandom(i + 1)
     swap(&x[i], &x[j])

V SUITS = [‘♣’, ‘♦’, ‘♥’, ‘♠’] V FACES = [‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘10’, ‘J’, ‘Q’, ‘K’, ‘A’] V DECK = multiloop(FACES, SUITS, (f, s) -> f‘’s) V CARD_TO_RANK = Dict((0 .< DECK.len).map(i -> (:DECK[i], (i + 3) I/ 4)))

T WarCardGame

  [String] deck1, deck2, pending
  F ()
     V deck = copy(:DECK)
     nonrandom_shuffle(&deck)
     .deck1 = deck[0.<26]
     .deck2 = deck[26..]
  F gameover()
     ‘ game over who won message ’
     I .deck2.empty
        I .deck1.empty
           print("\nGame ends as a tie.")
        E
           print("\nPlayer 1 wins the game.")
     E
        print("\nPlayer 2 wins the game.")
     R 0B
  F turn()
     ‘ one turn, may recurse on tie ’
     I .deck1.empty | .deck2.empty
        R .gameover()
     V card1 = .deck1.pop(0)
     V card2 = .deck2.pop(0)
     V (rank1, rank2) = (:CARD_TO_RANK[card1], :CARD_TO_RANK[card2])
     print(‘#<10#<10’.format(card1, card2), end' ‘’)
     I rank1 > rank2
        print(‘Player 1 takes the cards.’)
        .deck1.extend([card1, card2])
        .deck1.extend(.pending)
        .pending.clear()
     E I rank1 < rank2
        print(‘Player 2 takes the cards.’)
        .deck2.extend([card2, card1])
        .deck2.extend(.pending)
        .pending.clear()
     E
        print(‘Tie!’)
        I .deck1.empty | .deck2.empty
           R .gameover()
        V card3 = .deck1.pop(0)
        V card4 = .deck2.pop(0)
        .pending.extend([card1, card2, card3, card4])
        print(‘#<10#<10’.format(‘?’, ‘?’)‘Cards are face down.’)
        R .turn()
     R 1B

V WG = WarCardGame() L WG.turn()

  L.continue</lang>
Output:
7♦        10♦       Player 2 takes the cards.
10♥       K♥        Player 2 takes the cards.
7♥        6♣        Player 1 takes the cards.
8♦        5♥        Player 1 takes the cards.
4♥        3♥        Player 1 takes the cards.
A♣        9♣        Player 1 takes the cards.
6♠        4♦        Player 1 takes the cards.
K♣        3♠        Player 1 takes the cards.
A♠        7♣        Player 1 takes the cards.
10♠       J♥        Player 2 takes the cards.
J♦        Q♣        Tie!
?         ?         Cards are face down.
6♦        Q♠        Player 2 takes the cards.
...
5♠        4♦        Player 1 takes the cards.
Q♣        K♥        Player 2 takes the cards.
10♣       9♠        Tie!
?         ?         Cards are face down.
8♥        10♥       Player 2 takes the cards.
8♣        J♣        Player 2 takes the cards.
5♦        5♣        Player 1 takes the cards.
5♠        3♥        Player 1 takes the cards.
4♦        3♣        Player 1 takes the cards.
5♦        7♦        Player 2 takes the cards.
5♣        7♥        Player 2 takes the cards.
5♠        6♥        Player 2 takes the cards.
3♥        A♥        Player 2 takes the cards.
4♦        8♠        Player 2 takes the cards.
3♣        4♠        Player 2 takes the cards.

Player 2 wins the game.

Go

Translation of: Wren

<lang go>package main

import (

   "fmt"
   "math/rand"
   "time"

)

var suits = []string{"♣", "♦", "♥", "♠"} var faces = []string{"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"} var cards = make([]string, 52) var ranks = make([]int, 52)

func init() {

   for i := 0; i < 52; i++ {
       cards[i] = fmt.Sprintf("%s%s", faces[i%13], suits[i/13])
       ranks[i] = i % 13
   }

}

func war() {

   deck := make([]int, 52)
   for i := 0; i < 52; i++ {
       deck[i] = i
   }
   rand.Shuffle(52, func(i, j int) {
       deck[i], deck[j] = deck[j], deck[i]
   })
   hand1 := make([]int, 26, 52)
   hand2 := make([]int, 26, 52)
   for i := 0; i < 26; i++ {
       hand1[25-i] = deck[2*i]
       hand2[25-i] = deck[2*i+1]
   }
   for len(hand1) > 0 && len(hand2) > 0 {
       card1 := hand1[0]
       copy(hand1[0:], hand1[1:])
       hand1[len(hand1)-1] = 0
       hand1 = hand1[0 : len(hand1)-1]
       card2 := hand2[0]
       copy(hand2[0:], hand2[1:])
       hand2[len(hand2)-1] = 0
       hand2 = hand2[0 : len(hand2)-1]
       played1 := []int{card1}
       played2 := []int{card2}
       numPlayed := 2
       for {
           fmt.Printf("%s\t%s\t", cards[card1], cards[card2])
           if ranks[card1] > ranks[card2] {
               hand1 = append(hand1, played1...)
               hand1 = append(hand1, played2...)
               fmt.Printf("Player 1 takes the %d cards. Now has %d.\n", numPlayed, len(hand1))
               break
           } else if ranks[card1] < ranks[card2] {
               hand2 = append(hand2, played2...)
               hand2 = append(hand2, played1...)
               fmt.Printf("Player 2 takes the %d cards. Now has %d.\n", numPlayed, len(hand2))
               break
           } else {
               fmt.Println("War!")
               if len(hand1) < 2 {
                   fmt.Println("Player 1 has insufficient cards left.")
                   hand2 = append(hand2, played2...)
                   hand2 = append(hand2, played1...)
                   hand2 = append(hand2, hand1...)
                   hand1 = hand1[0:0]
                   break
               }
               if len(hand2) < 2 {
                   fmt.Println("Player 2 has insufficient cards left.")
                   hand1 = append(hand1, played1...)
                   hand1 = append(hand1, played2...)
                   hand1 = append(hand1, hand2...)
                   hand2 = hand2[0:0]
                   break
               }
               fdCard1 := hand1[0] // face down card
               card1 = hand1[1]    // face up card
               copy(hand1[0:], hand1[2:])
               hand1[len(hand1)-1] = 0
               hand1[len(hand1)-2] = 0
               hand1 = hand1[0 : len(hand1)-2]
               played1 = append(played1, fdCard1, card1)
               fdCard2 := hand2[0] // face down card
               card2 = hand2[1]    // face up card
               copy(hand2[0:], hand2[2:])
               hand2[len(hand2)-1] = 0
               hand2[len(hand2)-2] = 0
               hand2 = hand2[0 : len(hand2)-2]
               played2 = append(played2, fdCard2, card2)
               numPlayed += 4
               fmt.Println("? \t? \tFace down cards.")
           }
       }
   }
   if len(hand1) == 52 {
       fmt.Println("Player 1 wins the game!")
   } else {
       fmt.Println("Player 2 wins the game!")
   }

}

func main() {

   rand.Seed(time.Now().UnixNano())
   war()

}</lang>

Output:

Sample game (abridged):

9♠	Q♣	Player 2 takes the 2 cards. Now has 27.
7♠	6♠	Player 1 takes the 2 cards. Now has 26.
3♠	2♣	Player 1 takes the 2 cards. Now has 27.
A♠	2♦	Player 1 takes the 2 cards. Now has 28.
K♠	Q♥	Player 1 takes the 2 cards. Now has 29.
6♥	7♦	Player 2 takes the 2 cards. Now has 24.
2♥	T♣	Player 2 takes the 2 cards. Now has 25.
3♦	4♠	Player 2 takes the 2 cards. Now has 26.
Q♦	K♣	Player 2 takes the 2 cards. Now has 27.
7♥	5♠	Player 1 takes the 2 cards. Now has 26.
T♠	K♥	Player 2 takes the 2 cards. Now has 27.
A♦	9♣	Player 1 takes the 2 cards. Now has 26.
5♦	5♥	War!
? 	? 	Face down cards.
5♣	2♠	Player 1 takes the 6 cards. Now has 29.

......

6♣	3♣	Player 1 takes the 2 cards. Now has 50.
3♥	T♥	Player 2 takes the 2 cards. Now has 3.
K♥	8♠	Player 1 takes the 2 cards. Now has 50.
Q♣	T♥	Player 1 takes the 2 cards. Now has 51.
3♦	3♥	War!
Player 2 has insufficient cards left.
Player 1 wins the game!

Julia

<lang julia># https://bicyclecards.com/how-to-play/war/

using Random

const SUITS = ["♣", "♦", "♥", "♠"] const FACES = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" ] const DECK = vec([f * s for s in SUITS, f in FACES]) const rdict = Dict(DECK[i] => div(i + 3, 4) for i in eachindex(DECK))

deal2(deck) = begin d = shuffle(deck); d[1:2:51], d[2:2:52] end

function turn!(d1, d2, pending)

   (isempty(d1) || isempty(d2)) && return false
   c1, c2 = popfirst!(d1), popfirst!(d2)
   r1, r2 = rdict[c1], rdict[c2]
   print(rpad(c1, 10), rpad(c2, 10))
   if r1 > r2
       println("Player 1 takes the cards.")
       push!(d1, c1, c2, pending...)
       empty!(pending)
   elseif r1 < r2
       println("Player 2 takes the cards.")
       push!(d2, c2, c1, pending...)
       empty!(pending)
   else # r1 == r2
       println("Tie!")
       (isempty(d1) || isempty(d2)) && return false
       c3, c4 = popfirst!(d1), popfirst!(d2)
       println(rpad("?", 10), rpad("?", 10), "Cards are face down.")
       return turn!(d1, d2, push!(pending, c1, c2, c3, c4))
   end
   return true

end

function warcardgame()

   deck1, deck2 = deal2(DECK)
   while turn!(deck1, deck2, []) end
   if isempty(deck2)
       if isempty(deck1)
           println("Game ends as a tie.")
       else
           println("Player 1 wins the game.")
       end
   else
       println("Player 2 wins the game.")
   end

end

warcardgame()

</lang>

Output:
5♦        3♥        Player 1 takes the cards.
8♥        K♥        Player 2 takes the cards.
5♠        K♦        Player 2 takes the cards.
3♦        6♥        Player 2 takes the cards.
9♣        J♠        Player 2 takes the cards.
8♦        2♦        Player 1 takes the cards.
J♣        5♥        Player 1 takes the cards.
3♠        4♥        Player 2 takes the cards.
9♥        A♣        Player 2 takes the cards.
9♠        9♦        Tie!
?         ?         Cards are face down.     
A♠        4♦        Player 1 takes the cards.
5♣        Q♠        Player 2 takes the cards.
6♦        8♠        Player 2 takes the cards.
4♣        10♦       Player 2 takes the cards.
4♠        2♥        Player 1 takes the cards.
Q♦        K♣        Player 2 takes the cards.
A♥        2♣        Player 1 takes the cards.
Q♣        2♠        Player 1 takes the cards.
10♥       6♣        Player 1 takes the cards.

... many other lines ...

10♥       Q♣        Player 2 takes the cards.
4♣        5♦        Player 2 takes the cards.
A♣        8♦        Player 1 takes the cards.
9♣        2♣        Player 1 takes the cards.
Q♥        Q♣        Tie!
?         ?         Cards are face down.
Q♠        5♦        Player 1 takes the cards.
8♥        4♣        Player 1 takes the cards.
Player 1 wins the game.

Nim

We use module "playing_cards" from task https://rosettacode.org/wiki/Playing_cards. <lang Nim>import strformat import playing_cards

const

 None = -1
 Player1 = 0
 Player2 = 1

type Player = range[None..Player2]

const PlayerNames: array[Player1..Player2, string] = ["Player 1", "Player 2"]

  1. ---------------------------------------------------------------------------------------------------

proc `<`(a, b: Card): bool =

 ## Compare two cards by their rank, Ace being the greatest.
 if a.rank == Ace: false
 elif b.rank == Ace: true
 else: a.rank < b.rank
  1. ---------------------------------------------------------------------------------------------------

proc displayRound(round: int; hands: openArray[Hand]; card1, card2: string; text: string) =

 ## Display text for a round.
 stdout.write &"Round {round:<4}     "
 stdout.write &"Cards: {hands[Player1].len:>2}/{hands[Player2].len:<2}     "
 stdout.write &"{card1:>3}    {card2:>3}    "
 echo text
  1. ---------------------------------------------------------------------------------------------------

proc outOfCards(player: Player) =

 ## Display a message when a player has run out of cards.
 echo &"{PlayerNames[player]} has run out of cards."
  1. ---------------------------------------------------------------------------------------------------

proc doRound(hands: var openArray[Hand]; num: Positive) =

 ## Execute a round.
 var stack1, stack2: seq[Card]
 var winner: Player = None
 while winner == None:
   let card1 = hands[Player1].draw()
   let card2 = hands[Player2].draw()
   stack1.add card1
   stack2.add card2
   if card1.rank != card2.rank:
     winner = if card1 < card2: Player2 else: Player1
     displayRound(num, hands, $card1, $card2, &"{PlayerNames[winner]} takes the cards.")
   else:
     # There is a war.
     displayRound(num, hands, $card1, $card2, "This is a war.")
     if hands[Player1].len == 0:
       winner = Player2
     elif hands[Player2].len == 0:
       winner = Player1
     else:
       # Add a hidden card on stacks.
       stack1.add hands[Player1].draw()
       stack2.add hands[Player2].draw()
       displayRound(num, hands, "  ?", "  ?", "Cards are face down.")
       # Check if each player has enough cards to continue the war.
       if hands[Player1].len == 0:
         Player1.outOfCards()
         winner = Player2
       elif hands[Player2].len == 0:
         Player2.outOfCards()
         winner = Player1
 # Update hands.
 var stack = stack1 & stack2
 stack.shuffle()
 hands[winner] = stack & hands[winner]


  1. ———————————————————————————————————————————————————————————————————————————————————————————————————

var deck = initDeck() deck.shuffle()

var hands = deck.deal(2, 26) var num = 0 while true:

 inc num
 hands.doRound(num)
 if hands[Player1].len == 0:
   echo "Player 2 wins this game."
   break
 if hands[Player2].len == 0:
   echo "Player 1 wins this game."
   break</lang>
Output:

Example of a short game.

Round 1        Cards: 25/25     10♣     5♠    Player 1 takes the cards.
Round 2        Cards: 26/24      3♦     7♦    Player 2 takes the cards.
Round 3        Cards: 25/25     10♦    10♥    This is a war.
Round 3        Cards: 24/24       ?      ?    Cards are face down.
Round 3        Cards: 23/23      A♦     4♥    Player 1 takes the cards.
Round 4        Cards: 28/22      4♠     J♦    Player 2 takes the cards.
Round 5        Cards: 27/23      9♠     Q♣    Player 2 takes the cards.
Round 6        Cards: 26/24      A♣     2♦    Player 1 takes the cards.
Round 7        Cards: 27/23      Q♦     3♠    Player 1 takes the cards.
Round 8        Cards: 28/22      5♥     3♥    Player 1 takes the cards.
Round 9        Cards: 29/21      2♥     2♠    This is a war.
Round 9        Cards: 28/20       ?      ?    Cards are face down.
Round 9        Cards: 27/19      4♦    10♠    Player 2 takes the cards.
Round 10       Cards: 26/24      K♠     6♣    Player 1 takes the cards.
Round 11       Cards: 27/23      8♥     7♣    Player 1 takes the cards.
Round 12       Cards: 28/22      4♣     5♦    Player 2 takes the cards.
Round 13       Cards: 27/23      8♣     8♦    This is a war.
Round 13       Cards: 26/22       ?      ?    Cards are face down.
Round 13       Cards: 25/21      9♦     6♠    Player 1 takes the cards.
Round 14       Cards: 30/20      K♥     9♥    Player 1 takes the cards.
Round 15       Cards: 31/19      J♠     7♥    Player 1 takes the cards.
Round 16       Cards: 32/18      J♣     K♦    Player 2 takes the cards.
Round 17       Cards: 31/19      2♣     3♣    Player 2 takes the cards.
Round 18       Cards: 30/20      A♥     6♥    Player 1 takes the cards.
Round 19       Cards: 31/19      A♠     6♦    Player 1 takes the cards.
Round 20       Cards: 32/18      8♠     5♣    Player 1 takes the cards.
Round 21       Cards: 33/17     10♣     7♦    Player 1 takes the cards.
Round 22       Cards: 34/16      5♠     3♦    Player 1 takes the cards.
Round 23       Cards: 35/15      Q♥     4♠    Player 1 takes the cards.
Round 24       Cards: 36/14     10♦     J♦    Player 2 takes the cards.
Round 25       Cards: 35/15      Q♠     9♠    Player 1 takes the cards.
Round 26       Cards: 36/14      A♦     Q♣    Player 1 takes the cards.
Round 27       Cards: 37/13      4♥     4♦    This is a war.
Round 27       Cards: 36/12       ?      ?    Cards are face down.
Round 27       Cards: 35/11      2♦    10♠    Player 2 takes the cards.
Round 28       Cards: 34/16      A♣     2♠    Player 1 takes the cards.
Round 29       Cards: 35/15      Q♦     7♠    Player 1 takes the cards.
Round 30       Cards: 36/14      3♠     2♥    Player 1 takes the cards.
Round 31       Cards: 37/13      5♥     5♦    This is a war.
Round 31       Cards: 36/12       ?      ?    Cards are face down.
Round 31       Cards: 35/11      6♣     J♣    Player 2 takes the cards.
Round 32       Cards: 34/16      K♠     K♦    This is a war.
Round 32       Cards: 33/15       ?      ?    Cards are face down.
Round 32       Cards: 32/14      7♣     2♣    Player 1 takes the cards.
Round 33       Cards: 37/13      K♣     J♦    Player 1 takes the cards.
Round 34       Cards: 38/12      6♠    10♦    Player 2 takes the cards.
Round 35       Cards: 37/13      J♥    10♥    Player 1 takes the cards.
Round 36       Cards: 38/12      8♣     2♦    Player 1 takes the cards.
Round 37       Cards: 39/11      9♦     9♣    This is a war.
Round 37       Cards: 38/10       ?      ?    Cards are face down.
Round 37       Cards: 37/9       9♥    10♠    Player 2 takes the cards.
Round 38       Cards: 36/14      K♥     4♦    Player 1 takes the cards.
Round 39       Cards: 37/13      7♥     6♣    Player 1 takes the cards.
Round 40       Cards: 38/12      J♠     5♥    Player 1 takes the cards.
Round 41       Cards: 39/11      A♥     4♣    Player 1 takes the cards.
Round 42       Cards: 40/10      6♥     J♣    Player 2 takes the cards.
Round 43       Cards: 39/11      A♠     3♥    Player 1 takes the cards.
Round 44       Cards: 40/10      6♦     5♦    Player 1 takes the cards.
Round 45       Cards: 41/9       8♠    10♦    Player 2 takes the cards.
Round 46       Cards: 40/10      5♣     6♠    Player 2 takes the cards.
Round 47       Cards: 39/11      7♦     8♦    Player 2 takes the cards.
Round 48       Cards: 38/12     10♣     9♦    Player 1 takes the cards.
Round 49       Cards: 39/11      3♦    10♠    Player 2 takes the cards.
Round 50       Cards: 38/12      5♠     4♥    Player 1 takes the cards.
Round 51       Cards: 39/11      4♠     9♥    Player 2 takes the cards.
Round 52       Cards: 38/12      Q♥     9♣    Player 1 takes the cards.
Round 53       Cards: 39/11      Q♠     6♥    Player 1 takes the cards.
Round 54       Cards: 40/10      9♠     J♣    Player 2 takes the cards.
Round 55       Cards: 39/11      Q♣     8♠    Player 1 takes the cards.
Round 56       Cards: 40/10      A♦    10♦    Player 1 takes the cards.
Round 57       Cards: 41/9       A♣     5♣    Player 1 takes the cards.
Round 58       Cards: 42/8       2♠     6♠    Player 2 takes the cards.
Round 59       Cards: 41/9       Q♦     7♦    Player 1 takes the cards.
Round 60       Cards: 42/8       7♠     8♦    Player 2 takes the cards.
Round 61       Cards: 41/9       3♠     3♦    This is a war.
Round 61       Cards: 40/8        ?      ?    Cards are face down.
Round 61       Cards: 39/7       7♣     9♥    Player 2 takes the cards.
Round 62       Cards: 38/12      8♥     4♠    Player 1 takes the cards.
Round 63       Cards: 39/11      K♦     9♠    Player 1 takes the cards.
Round 64       Cards: 40/10      2♣     J♣    Player 2 takes the cards.
Round 65       Cards: 39/11      3♣     2♠    Player 1 takes the cards.
Round 66       Cards: 40/10      K♠     6♠    Player 1 takes the cards.
Round 67       Cards: 41/9       J♦     7♠    Player 1 takes the cards.
Round 68       Cards: 42/8       K♣     8♦    Player 1 takes the cards.
Round 69       Cards: 43/7      10♥    10♠    This is a war.
Round 69       Cards: 42/6        ?      ?    Cards are face down.
Round 69       Cards: 41/5       8♣     2♥    Player 1 takes the cards.
Round 70       Cards: 46/4       2♦     9♥    Player 2 takes the cards.
Round 71       Cards: 45/5       K♥     3♠    Player 1 takes the cards.
Round 72       Cards: 46/4       4♦     7♣    Player 2 takes the cards.
Round 73       Cards: 45/5       7♥     2♣    Player 1 takes the cards.
Round 74       Cards: 46/4       6♣     J♣    Player 2 takes the cards.
Round 75       Cards: 45/5       5♥     2♦    Player 1 takes the cards.
Round 76       Cards: 46/4       J♠     9♥    Player 1 takes the cards.
Round 77       Cards: 47/3       A♥     7♣    Player 1 takes the cards.
Round 78       Cards: 48/2       4♣     4♦    This is a war.
Round 78       Cards: 47/1        ?      ?    Cards are face down.
Round 78       Cards: 46/0       A♠     J♣    Player 1 takes the cards.
Player 1 wins this game.

Perl

There are two players, 'one' and 'two'. This shows each players hand as the game progresses. <lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/War_Card_Game use warnings; use List::Util qw( shuffle );

my %rank; @rank{ 2 .. 9, qw(t j q k a) } = 1 .. 13; # for winner local $_ = join , shuffle

 map { my $f = $_; map $f.$_, qw( S H C D ) } 2 .. 9, qw( a t j q k );

substr $_, 52, 0, "\n"; # split deck into two parts my $war = ; my $cnt = 0; $cnt++ while print( /(.*)\n(.*)/ && "one: $1\ntwo: $2\n\n" ),

 s/^((.).)(.*)\n((?!\2)(.).)(.*)$/ my $win = $war; $war = ; # capture
   $rank{$2} > $rank{$5} ? "$3$1$4$win\n$6" : "$3\n$6$4$1$win" /e
 ||
 s/^(.{4})(.*)\n(.{4})(.*)$/ print "WAR!!!\n\n"; $war .= "$1$3";
   "$2\n$4" /e; # tie means war

print "player '", /^.{10}/ ? 'one' : 'two', "' wins in $cnt moves\n";</lang>

Output:
one: 8CqCaD5H6S2HjC9S7HjH8S4DqD5C6DkC4H9D3DqHtC7C8DtS6C4S
two: 5S8HaCaH2C6H3HaS7DjD3S2D5D9CkSkH9H4C2StDtHjSkD7SqS3C

one: qCaD5H6S2HjC9S7HjH8S4DqD5C6DkC4H9D3DqHtC7C8DtS6C4S8C5S
two: 8HaCaH2C6H3HaS7DjD3S2D5D9CkSkH9H4C2StDtHjSkD7SqS3C

one: aD5H6S2HjC9S7HjH8S4DqD5C6DkC4H9D3DqHtC7C8DtS6C4S8C5SqC8H
two: aCaH2C6H3HaS7DjD3S2D5D9CkSkH9H4C2StDtHjSkD7SqS3C

WAR!!!

one: 6S2HjC9S7HjH8S4DqD5C6DkC4H9D3DqHtC7C8DtS6C4S8C5SqC8H
two: 2C6H3HaS7DjD3S2D5D9CkSkH9H4C2StDtHjSkD7SqS3C

one: 2HjC9S7HjH8S4DqD5C6DkC4H9D3DqHtC7C8DtS6C4S8C5SqC8H6S2CaD5HaCaH
two: 6H3HaS7DjD3S2D5D9CkSkH9H4C2StDtHjSkD7SqS3C

... (skipped middle part to save lines)

one: kC7HkHqCqH9SjS5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3D
two: 8C7DaCqSaS5C8S3C

one: 7HkHqCqH9SjS5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C
two: 7DaCqSaS5C8S3C

WAR!!!

one: qCqH9SjS5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C
two: qSaS5C8S3C

WAR!!!

one: 9SjS5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C
two: 5C8S3C

one: jS5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C9S5C7HkH7DaCqCqHqSaS
two: 8S3C

one: 5StD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C9S5C7HkH7DaCqCqHqSaSjS8S
two: 3C

one: tD4D3S2HaD7S8H4CkS4SaHjD8D6H4H3HjC7CtH5DtC2DjH2C9D6D6C2S6SkDqD9H9C5HtS3DkC8C9S5C7HkH7DaCqCqHqSaSjS8S5S3C
two: 

player 'one' wins in 117 moves

Phix

Shuffles on pickup to significantly shorten the games <lang Phix>sequence deck = shuffle(tagset(52)),

        hands = {deck[1..26],deck[27..52]},
        pending = {}

function pop(integer hand)

   integer res
   {res, hands[hand]} = {hands[hand][1],hands[hand][2..$]}
   return res

end function

function show(integer c)

   integer r = remainder(c-1,13)+1,
           s = floor((c-1)/13)+1
   printf(1,"%s    ",{"23456789TJQKA"[r]&"SHDC"[s]})
   return r

end function

while true do

   if length(hands[1])=0 then
       if length(hands[2])=0 then
           printf(1,"Game ends as a tie.\n")
           exit
       end if
       printf(1,"Player 2 wins the game.\n")
       exit
   elsif length(hands[2])=0 then
       printf(1,"Player 1 wins the game.\n")
       exit
   end if
   integer c1 = pop(1),
           c2 = pop(2),
           r1 = show(c1),
           r2 = show(c2)
   if r1>r2 then
       printf(1,"Player 1 takes the cards.\n")
       hands[1] &= shuffle(c1&c2&pending)
       pending = {}
   elsif r1<r2 then
       printf(1,"Player 2 takes the cards.\n")
       hands[2] &= shuffle(c1&c2&pending)
       pending = {}
   else -- r1==r2
       printf(1,"Tie!\n")
       if length(hands[1])!=0 and length(hands[2])!=0 then
           pending &= shuffle(c1&c2&pop(1)&pop(2))
           printf(1,"??    ??    Cards are face down.\n")
       end if
   end if

end while</lang>

Output:
9H    3C    Player 1 takes the cards.
AD    KD    Player 1 takes the cards.
3D    KS    Player 2 takes the cards.
...
2H    9S    Player 2 takes the cards.
KC    7H    Player 1 takes the cards.
5C    JS    Player 2 takes the cards.
3S    3D    Tie!
??    ??    Cards are face down.
8D    2H    Player 1 takes the cards.
2C    JS    Player 2 takes the cards.
JD    5C    Player 1 takes the cards.
6D    2C    Player 1 takes the cards.
QD    JS    Player 1 takes the cards.
Player 1 wins the game.

Python

Translation of: Julia

<lang python>""" https://bicyclecards.com/how-to-play/war/ """

from numpy.random import shuffle

SUITS = ['♣', '♦', '♥', '♠'] FACES = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'] DECK = [f + s for f in FACES for s in SUITS] CARD_TO_RANK = dict((DECK[i], (i + 3) // 4) for i in range(len(DECK)))


class WarCardGame:

   """ card game War """
   def __init__(self):
       deck = DECK.copy()
       shuffle(deck)
       self.deck1, self.deck2 = deck[:26], deck[26:]
       self.pending = []
   def turn(self):
       """ one turn, may recurse on tie """
       if len(self.deck1) == 0 or len(self.deck2) == 0:
           return self.gameover()
       card1, card2 = self.deck1.pop(0), self.deck2.pop(0)
       rank1, rank2 = CARD_TO_RANK[card1], CARD_TO_RANK[card2]
       print("{:10}{:10}".format(card1, card2), end=)
       if rank1 > rank2:
           print('Player 1 takes the cards.')
           self.deck1.extend([card1, card2])
           self.deck1.extend(self.pending)
           self.pending = []
       elif rank1 < rank2:
           print('Player 2 takes the cards.')
           self.deck2.extend([card2, card1])
           self.deck2.extend(self.pending)
           self.pending = []
       else:  #  rank1 == rank2
           print('Tie!')
           if len(self.deck1) == 0 or len(self.deck2) == 0:
               return self.gameover()
           card3, card4 = self.deck1.pop(0), self.deck2.pop(0)
           self.pending.extend([card1, card2, card3, card4])
           print("{:10}{:10}".format("?", "?"), 'Cards are face down.', sep=)
           return self.turn()
       return True
   def gameover(self):
       """ game over who won message """
       if len(self.deck2) == 0:
           if len(self.deck1) == 0:
               print('\nGame ends as a tie.')
           else:
               print('\nPlayer 1 wins the game.')
       else:
           print('\nPlayer 2 wins the game.')
       return False


if __name__ == '__main__':

   WG = WarCardGame()
   while WG.turn():
       continue

</lang>

Output:
8♠        K♠        Player 2 takes the cards.
3♠        8♥        Player 2 takes the cards.
K♣        4♠        Player 1 takes the cards.
Q♦        J♣        Player 1 takes the cards.
5♦        6♦        Player 2 takes the cards.
A♥        Q♣        Player 1 takes the cards.
10♣       5♥        Player 1 takes the cards.
J♦        7♣        Player 1 takes the cards.
K♥        Q♠        Player 1 takes the cards.
2♦        2♣        Player 1 takes the cards.
10♠       9♥        Player 1 takes the cards.
9♠        3♦        Player 1 takes the cards.
A♠        A♦        Tie!
?         ?         Cards are face down.
3♥        8♦        Player 2 takes the cards.
5♣        2♠        Player 1 takes the cards.
J♠        4♦        Player 1 takes the cards.
2♥        7♦        Player 2 takes the cards.

... et cetera ...

A♣        4♣        Player 1 takes the cards.
7♣        3♣        Player 1 takes the cards.
9♠        A♦        Player 2 takes the cards.
6♦        Q♠        Player 2 takes the cards.
7♦        3♦        Player 1 takes the cards.
5♥        2♥        Player 1 takes the cards.
A♣        A♥        Player 2 takes the cards.
4♣        10♣       Player 2 takes the cards.
7♣        10♥       Player 2 takes the cards.
3♣        5♦        Player 2 takes the cards.
7♦        K♦        Player 2 takes the cards.
3♦        8♣        Player 2 takes the cards.
5♥        J♦        Player 2 takes the cards.
2♥        6♥        Player 2 takes the cards.

Player 2 wins the game.

Raku

The linked Bicycle cards site has slightly different rules for War! than how I used to play when I was but a lad. Implement it both ways.

Some rules are not nailed down very well. Here is how I interpreted it:

  • The values of the cards 2-10 are face value; Jack, Queen, King and Ace may effectively be treated as: 11, 12, 13 & 14.
  • Each player plays one card face up. The player whose card is the highest value takes both of the played cards and adds them to the bottom of his deck.
  • When one player runs out of cards and is not able to place enough cards to finish a round, he loses.
  • If both players play a card of the same value, it is then War!
    • Bicycle rules: each player then plays another card face down then another face up.
    • thundergnat rules: each player then plays three cards face down then another face up. (Tends to make for shorter games.)
    • If the final face-up cards are different, the player playing the higher value card takes all of the played cards and adds them to the bottom of his deck
    • If they are the same, continue with rounds of War! until one player plays a higher value war card or a player runs out of cards.
  • When the winning player picks up his cards. the cards are randomized when added to the bottom of his deck. (Cuts a typical game from multi thousands of rounds to multi hundreds of rounds)

Pass in which variant you want to play 2 down, (Bicycle), --war=2, 4 down (thundergnat), (default), --war=4 or 3 down (????) , --war=3. By default, there is a short delay (.1 seconds) between rounds so you can watch what is going on. Pass in a larger/smaller value to slow down or speed up how long the game takes. --sleep=0 or whatever.

In glorious ANSI color! (The output loses much when pasted in as text so show output as screenshot images.)

<lang perl6>unit sub MAIN (:$war where 2..4 = 4, :$sleep = .1);

my %c = ( # convenience hash of ANSI colors

   red   => "\e[38;2;255;10;0m",
   blue  => "\e[38;2;05;10;200m",
   black => "\e[38;2;0;0;0m"

);

my @cards = flat (flat

    <🂢 🂣 🂤 🂥 🂦 🂧 🂨 🂩 🂪 🂫 🂭 🂮 🂡
     🃒 🃓 🃔 🃕 🃖 🃗 🃘 🃙 🃚 🃛 🃝 🃞 🃑>.map({ "{%c<black>}$_" }),
    <🂲 🂳 🂴 🂵 🂶 🂷 🂸 🂹 🂺 🂻 🂽 🂾 🂱
     🃂 🃃 🃄 🃅 🃆 🃇 🃈 🃉 🃊 🃋 🃍 🃎 🃁>.map({ "{%c<red>}$_" })

).batch(13).map({ .flat Z 2..14 })».map: { .[1] but .[0] };

my $back = "{%c<blue>}🂠"; my @won = <👈 👉>;

sub shuffle (@cards) { @cards.pick: * } sub deal (@cards) { [@cards[0,*+2 … *], @cards[1,*+2 … *]] }

my ($rows, $cols) = qx/stty size/.words».Int; # get the terminal size note "Terminal is only $cols characters wide, needs to be at least 80, 120 or more recommended."

 and exit if $cols < 80;

sub clean-up {

   reset-scroll-region;
   show-cursor;
   print-at $rows, 1, ;
   print "\e[0m";
   exit(0)

}

signal(SIGINT).tap: { clean-up() }

my @index = ($cols div 2 - 5, $cols div 2 + 4); my @player = (deal shuffle @cards)».Array; my $lose = False;

sub take (@player, Int $cards) {

   if +@player >= $cards {
       return @player.splice(0, $cards);
   }
   else {
        $lose = True;
        return @player.splice(0, +@player);
   }

}

use Terminal::ANSI;

clear-screen; hide-cursor;

  1. Set background color

print "\e[H\e[J\e[48;2;245;245;245m", ' ' xx $rows * $cols + 1;

  1. Add header

print-at 1, $cols div 2 - 1, "{%c<red>}WAR!"; print-at 2, 1, '━' x $cols;

my $row = 3; my $height = $rows - $row - 2; set-scroll-region($row, $height);

  1. footer

print-at $height + 1, 1, '━' x $cols;

my $round = 0; my @round;

loop {

   @round = [@player[0].&take(1)], [@player[1].&take(1)] unless +@round;
   print-at $row, $cols div 2, "{%c<red>}┃";
   print-at $row, @index[0], @round[0;0] // ' ';
   print-at $row, @index[1], @round[1;0] // ' ';
   if $lose {
       if @player[0] < @player[1] {
           print-at $row, $cols div 2 + 1, @won[1] unless +@round[1] == 1;
           print-at $height + 3, $cols div 2 - 10, "{%c<red>} Player 1 is out of cards "
       } else {
           print-at $row, $cols div 2 - 2, @won[0] unless +@round[0] == 1;
           print-at $height + 3, $cols div 2 - 10, "{%c<red>} Player 2 is out of cards "
       }
   }
   if (@round[0].tail // 0) > (@round[1].tail // 0) {
       print-at $row, $cols div 2 - 2, @won[0];
       @player[0].append: flat (|@round[0],|@round[1]).pick: *;
       @round = ();
   }
   elsif (@round[0].tail // 0) < (@round[1].tail // 0) {
       print-at $row, $cols div 2 + 1, @won[1];
       @player[1].append: flat (|@round[0],|@round[1]).pick: *;
       @round = ();
   }
   else {
       @round[0].append: @player[0].&take($war);
       @round[1].append: @player[1].&take($war);
       print-at $row, @index[0] - $_ * 2, ($_ %% $war) ?? @round[0; $_] !! $back for ^@round[0];
       print-at $row, @index[1] + $_ * 2, ($_ %% $war) ?? @round[1; $_] !! $back for ^@round[1];
       next
   }
   last if $lose;
   print-at $height + 2, $cols div 2 - 4,  "{%c<blue>} Round {++$round} ";
   print-at $height + 2, $cols div 2 - 40, "{%c<blue>} Player 1: {+@player[0]} cards ";
   print-at $height + 2, $cols div 2 + 21, "{%c<blue>} Player 2: {+@player[1]} cards ";
   sleep $sleep if +$sleep;
   if $row >= $height { scroll-up } else { ++$row }

}

  1. game over

print-at $height + 2, $cols div 2 - 40, "{%c<blue>} Player 1: {+@player[0] ?? '52' !! "{%c<red>}0"}{%c<blue>} cards "; print-at $height + 2, $cols div 2 + 20, "{%c<blue>} Player 2: {+@player[1] ?? '52' !! "{%c<red>}0"}{%c<blue>} cards "; clean-up;</lang>

Sample outout Bicycle:

Pass in :war=2 on the command line. See Bicycle variation (offsite png image)

Sample outout using defaults:

See thundergnat variation (offsite png image)

Wren

Library: Wren-queue

I've assumed that if a player runs out of cards during a 'war', then the other player automatically wins the game. The Bicycle card company's rules don't appear to cover this eventuality

I've also assumed that if a player wins a round, his/her own cards (in the order played) are added back to the bottom of his/her hand before the other player's cards. <lang ecmascript>import "random" for Random import "/queue" for Deque

var rand = Random.new() var suits = ["♣", "♦", "♥", "♠"] var faces = ["2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A" ] var cards = List.filled(52, null) for (i in 0..51) cards[i] = "%(faces[i%13])%(suits[(i/13).floor])" var ranks = List.filled(52, 0) for (i in 0..51) ranks[i] = i % 13

var war = Fn.new {

   var deck = List.filled(52, 0)
   for (i in 0..51) deck[i] = i
   rand.shuffle(deck)
   var hand1 = Deque.new()
   var hand2 = Deque.new()
   for (i in 0..25) {
       hand1.pushFront(deck[2*i])
       hand2.pushFront(deck[2*i+1])
   }
   while (hand1.count > 0 && hand2.count > 0) {
       var card1 = hand1.popFront()
       var card2 = hand2.popFront()
       var played1 = [card1]
       var played2 = [card2]
       var numPlayed = 2
       while (true) {
           System.write("%(cards[card1])\t%(cards[card2])\t")
           if (ranks[card1] > ranks[card2]) {
               hand1.pushAllBack(played1)
               hand1.pushAllBack(played2)
               System.print("Player 1 takes the %(numPlayed) cards. Now has %(hand1.count).")
               break
           } else if (ranks[card1] < ranks[card2]) {
               hand2.pushAllBack(played2)
               hand2.pushAllBack(played1)
               System.print("Player 2 takes the %(numPlayed) cards. Now has %(hand2.count).")
               break
           } else {
               System.print("War!")
               if (hand1.count < 2) {
                   System.print("Player 1 has insufficient cards left.")
                   hand2.pushAllBack(played2)
                   hand2.pushAllBack(played1)
                   hand2.pushAllBack(hand1)
                   hand1.clear()
                   break
               }
               if (hand2.count < 2) {
                   System.print("Player 2 has insufficient cards left.")
                   hand1.pushAllBack(played1)
                   hand1.pushAllBack(played2)
                   hand1.pushAllBack(hand2)
                   hand2.clear()
                   break
               }
               played1.add(hand1.popFront()) // face down card
               card1 = hand1.popFront()      // face up card
               played1.add(card1)
               played2.add(hand2.popFront()) // face down card
               card2 = hand2.popFront()      // face up card
               played2.add(card2)
               numPlayed = numPlayed + 4
               System.print("? \t? \tFace down cards.")
           }
       }
   }
   if (hand1.count == 52) {
       System.print("Player 1 wins the game!")
   } else {
       System.print("Player 2 wins the game!")
   }

}

war.call()</lang>

Output:

Sample game (abridged):

Q♥	9♠	Player 1 takes the 2 cards. Now has 27.
3♦	T♦	Player 2 takes the 2 cards. Now has 26.
8♣	A♥	Player 2 takes the 2 cards. Now has 27.
3♠	Q♠	Player 2 takes the 2 cards. Now has 28.
J♠	4♥	Player 1 takes the 2 cards. Now has 25.
3♣	7♣	Player 2 takes the 2 cards. Now has 28.
9♦	2♠	Player 1 takes the 2 cards. Now has 25.
7♥	K♦	Player 2 takes the 2 cards. Now has 28.
5♥	A♠	Player 2 takes the 2 cards. Now has 29.
2♦	K♠	Player 2 takes the 2 cards. Now has 30.
5♠	5♣	War!
? 	? 	Face down cards.
4♣	T♣	Player 2 takes the 6 cards. Now has 33.
A♦	9♥	Player 1 takes the 2 cards. Now has 20.
T♥	9♣	Player 1 takes the 2 cards. Now has 21.
K♣	Q♣	Player 1 takes the 2 cards. Now has 22.
4♦	A♣	Player 2 takes the 2 cards. Now has 31.
7♠	7♦	War!
? 	? 	Face down cards.
8♦	J♣	Player 2 takes the 6 cards. Now has 34.

.....

T♠	7♦	Player 1 takes the 2 cards. Now has 10.
7♠	J♣	Player 2 takes the 2 cards. Now has 43.
4♣	4♥	War!
? 	? 	Face down cards.
2♠	2♣	War!
? 	? 	Face down cards.
3♦	9♠	Player 2 takes the 10 cards. Now has 48.
5♠	5♣	War!
? 	? 	Face down cards.
T♠	T♥	War!
Player 1 has insufficient cards left.
Player 2 wins the game!

XPL0

<lang XPL0>char Deck(52), \initial card deck (low 2 bits = suit)

       Stack(2, 52);           \each player's stack of cards (52 maximum)

int Inx(2), \index to last card (+1) for each stack

       Top,                    \index to compared cards, = stack top if not war
       Card, N, I, J, P, T;

char Suit, Rank;

proc MoveCard(To, From); \Move top card From Stack to bottom of To Stack int To, From; int Card, I; [Card:= Stack(From, 0); \take top Card from From Stack for I:= 0 to Inx(From)-2 do \shift remaining cards over

       Stack(From, I):= Stack(From, I+1);

if Inx(From) > 0 then \remove From card from its Stack

       Inx(From):= Inx(From)-1;

Stack(To, Inx(To)):= Card; \add Card to bottom of To Stack if Inx(To) < 52 then \remove From card from its Stack

       Inx(To):= Inx(To)+1;

];

[\\Suit:= "^C^D^E^F "; \IBM OEM card symbols aren't displayable on RC Suit:= "HDCS "; Rank:= "23456789TJQKA "; \T = 10 for Card:= 0 to 52-1 do \make a complete deck of cards

       Deck(Card):= Card;

for N:= 0 to 10_000 do \shuffle the deck by swapping random locations

       [I:= Ran(52);  J:= Ran(52);
       T:= Deck(I);  Deck(I):= Deck(J);  Deck(J):= T;
       ];

for N:= 0 to 52-1 do \deal deck into two stacks

       [Card:= Deck(N);
       I:= N/2;
       P:= rem(0);
       Stack(P, I):= Card;
       ];

Inx(0):= 52/2; Inx(1):= 52/2; \set indexes to last card +1

loop [for P:= 0 to 1 do \show both stacks of cards

               [for I:= 0 to Inx(P)-1 do
                       [Card:= Stack(P, I);  ChOut(0, Rank(Card>>2))];
               CrLf(0);
               for I:= 0 to Inx(P)-1 do
                       [Card:= Stack(P, I);  ChOut(0, Suit(Card&3))];
               CrLf(0);
               ];
       if Inx(0)=0 or Inx(1)=0 then quit;      \game over
       Top:= 0;                \compare card ranks (above 2-bit suits)
       loop    [if Stack(0, Top)>>2 = Stack(1, Top)>>2 then
                       [Text(0, "War!");  CrLf(0);
                       Top:= Top+2;            \play a card down and a card up
                       ]
               else if Stack(0, Top)>>2 > Stack(1, Top)>>2 then
                       [for I:= 0 to Top do    \move cards to Stack 0
                               [MoveCard(0, 0);  MoveCard(0, 1)];
                       quit;
                       ]
               else    [for I:= 0 to Top do    \move cards to Stack 1
                               [MoveCard(1, 1);  MoveCard(1, 0)];
                       quit;
                       ];
               ];
       T:= ChIn(1);            \wait for keystroke (no key echo)
       CrLf(0);
       ];

] ]</lang>

Output:
578Q465J29A9437JTT59A662QJ
CCDDCCSHSHHDDCHCSDHCDHSHHS
KK8A975Q2A38J87T63K342TQK4
HCCCSDDCCSSSDHSHDHDDHDCSSS

78Q465J29A9437JTT59A662QJ
CDDCCSHSHHDDCHCSDHCDHSHHS
K8A975Q2A38J87T63K342TQK4K5
CCCSDDCCSSSDHSHDHDDHDCSSSHC

8Q465J29A9437JTT59A662QJ
DDCCSHSHHDDCHCSDHCDHSHHS
8A975Q2A38J87T63K342TQK4K5K7
CCSDDCCSSSDHSHDHDDHDCSSSHCCC
War!

65J29A9437JTT59A662QJ
CSHSHHDDCHCSDHCDHSHHS
75Q2A38J87T63K342TQK4K5K788AQ94
DDCCSSSDHSHDHDDHDCSSSHCCCCDCDSC

5J29A9437JTT59A662QJ
SHSHHDDCHCSDHCDHSHHS
5Q2A38J87T63K342TQK4K5K788AQ9476
DCCSSSDHSHDHDDHDCSSSHCCCCDCDSCDC
War!
War!

9437JTT59A662QJ55JQ229AA3
DDCHCSDHCDHSHHSSDHCSCHSHS
8J87T63K342TQK4K5K788AQ9476
SDHSHDHDDHDCSSSHCCCCDCDSCDC

. . .

K38562446952A7A2K4J4T7KJQ39976Q893ATK8JTT5Q562AQ87
DDSDSHHSDDSSDDCCSDHCSCCCSSHSSCCCCHSCHHDDHHDCHDHHDH
J3
SC

38562446952A7A2K4J4T7KJQ39976Q893ATK8JTT5Q562AQ87KJ
DSDSHHSDDSSDDCCSDHCSCCCSSHSSCCCCHSCHHDDHHDCHDHHDHDS
3
C
War!

62446952A7A2K4J4T7KJQ39976Q893ATK8JTT5Q562AQ87KJ3385
SHHSDDSSDDCCSDHCSCCCSSHSSCCCCHSCHHDDHHDCHDHHDHDSDCSD