War card game: Difference between revisions
Thundergnat (talk | contribs) (→{{header|Raku}}: Add a Raku example) |
|||
Line 8: | Line 8: | ||
References: |
References: |
||
:* Bicycle card company |
:* Bicycle card company: [https://bicyclecards.com/how-to-play/war War game site] |
||
:* Wikipedia |
:* Wikipedia: [[wp:War_(card_game)|War (card game)]] |
||
Related tasks: |
Related tasks: |
||
Line 691: | Line 691: | ||
Player 2 wins the game. |
Player 2 wins the game. |
||
</pre> |
</pre> |
||
=={{header|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), 4 down (thundergnat) or 3 down (????). By default, there is a short delay (.1 seconds) beween 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. |
|||
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> |
|||
{{out|Sample outout Bicycle}} |
|||
Pass in <code>:war=2</code> on the command line. |
|||
See [https://github.com/thundergnat/rc/blob/master/img/war-2.png Bicycle variation] (offsite png image) |
|||
{{out|Sample outout using defaults}} |
|||
See [https://github.com/thundergnat/rc/blob/master/img/war-4.png thundergnat variation] (offsite png image) |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
Line 712: | Line 852: | ||
for (i in 0..51) deck[i] = i |
for (i in 0..51) deck[i] = i |
||
rand.shuffle(deck) |
rand.shuffle(deck) |
||
var hand1 = Deque.new() |
var hand1 = Deque.new()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; |
|||
var hand2 = Deque.new() |
var hand2 = Deque.new() |
||
for (i in 0..25) { |
for (i in 0..25) { |
Revision as of 22:07, 12 January 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:
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), 4 down (thundergnat) or 3 down (????). By default, there is a short delay (.1 seconds) beween 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.
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()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;
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!