War card game: Difference between revisions
Alextretyak (talk | contribs) (Added 11l) |
m (draft -> task) |
||
Line 2: | Line 2: | ||
[[Category:Games]] |
[[Category:Games]] |
||
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. |
Simulate the card game War. Use the Bicycle playing card manufacturer's rules. Show a game as played. User input is optional. |
Revision as of 17:44, 10 August 2021
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:
- Bicycle card company: War game site
- Wikipedia: War (card game)
Related tasks:
11l
<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
<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"]
- ---------------------------------------------------------------------------------------------------
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
- ---------------------------------------------------------------------------------------------------
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
- ---------------------------------------------------------------------------------------------------
proc outOfCards(player: Player) =
## Display a message when a player has run out of cards. echo &"{PlayerNames[player]} has run out of cards."
- ---------------------------------------------------------------------------------------------------
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]
- ———————————————————————————————————————————————————————————————————————————————————————————————————
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
<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;
- Set background color
print "\e[H\e[J\e[48;2;245;245;245m", ' ' xx $rows * $cols + 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);
- 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 }
}
- 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
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