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:
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.)
unit subMAIN (:$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 = <👈 👉>;subshuffle (@cards) { @cards.pick: * }subdeal (@cards) { [@cards[0,*+2 … *], @cards[1,*+2 … *]] }my ($rows, $cols) = qx/stty size/.words».Int; # get the terminal sizenote "Terminal is only $cols characters wide, needs to be at least 80, 120 or more recommended."andexitif $cols < 80;subclean-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;subtake (@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 colorprint"\e[H\e[J\e[48;2;245;245;245m", ' ' xx $rows * $cols + 1;# Add headerprint-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);# footerprint-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 }lastif $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 overprint-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;
Pass in :war=2 on the command line. See Bicycle variation (offsite png image)