euchre-live

Euchre web-app for the socially distant family
git clone git://git.alexkarle.com/euchre-live.git
Log | Files | Refs | README | LICENSE

commit cf5347786d32a33e04bc968bfc81f73d05fa1c99 (patch)
parent 47619cb8ccf098a6071b8a66fbbe4a126bd253a4
Author: Alex Karle <alex@karle.co>
Date:   Tue, 14 Apr 2020 23:50:15 -0400

Euchre::Dealer: Add dealer_swap phase after ordering trump

This is the final phase in the strange and twisted dance that is
ordering trump. If you're in the first round of voting, you MUST vote
for the kitty card and that kitty card will go to the dealer.

To ensure that the dealer gets it, we add a new "dealer_swap" phase,
blocking all other players from doing anything (I knew the handle_msg
generic validation would come in handy!). We then wait for the dealer to
give us a card from their hand to exchange, and give them the
trump_nominee in return.

Smooth as butter. Added click handlers to debug.html to test it.

Diffstat:
Mlib/Euchre/Dealer.pm | 63++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mpublic/debug.html | 8+++++++-
2 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/lib/Euchre/Dealer.pm b/lib/Euchre/Dealer.pm @@ -107,6 +107,7 @@ sub handle_msg { # Gameplay order => [\&order, 'vote', "Not time for a vote", 1], + dealer_swap => [\&dealer_swap, 'dealer_swap', "Can't swap with the Kitty now", 1], play_card => [\&play_card, 'play', "Can't play cards yet", 1], ); @@ -323,13 +324,24 @@ sub order { # Accept the vote... $game->{trump} = $msg->{vote}; $game->{caller} = $p->{seat}; - $game->{phase} = 'play'; + if ($game->{pass_count} < 4) { + # Setting phase will block all other play actions until the + # dealer is done swapping. Do still broadcast so dealer knows! + # Piggy back on the handle_msg turn validation by temporarily + # setting "turn" to dealer. + $game->{phase} = 'dealer_swap'; + $game->{turn} = $game->{dealer}; + } else { + # Get right to it! + $game->{phase} = 'play'; + reset_turn($game); + } + if ($msg->{loner}) { my $partner_seat = ($p->{seat} + 2) % 4; $game->{out_player} = $partner_seat; $game->{tricks}->[$partner_seat] = 'X'; } - reset_turn($game); sort_hands($game); broadcast_gamestate($game); } else { @@ -375,19 +387,7 @@ sub play_card { } } - # Make sure they have the card, and update their hand - my $found = 0; - for (my $i = 0; $i < scalar @{$p->{hand}}; $i++) { - if ($p->{hand}->[$i] eq $msg->{card}) { - splice(@{$p->{hand}}, $i, 1); - $found = 1; - last; - } - } - if (!$found) { - send_error($p, "You don't have that card!"); - return; - } + take_card($p, $msg->{card}) or return; # Update the table and current player $game->{table}->[$seat] = $msg->{card}; @@ -441,6 +441,23 @@ sub signal_game_end { } +# Based on validation, we KNOW $p is the dealer +# msg.card = card to swap +sub dealer_swap { + my ($p, $msg) = @_; + + my $game = $p->{game}; + + # Exchange the cards + take_card($p, $msg->{card}) or return; + push @{$p->{hand}}, $game->{trump_nominee}; + + # Start the game + $game->{phase} = 'play'; + reset_turn($game); + broadcast_gamestate($game); +} + # XXX: The most simplest (bulkiest) message we can send is to just # broadcast the gamestate to all clients. This will be our temporary # debugging method / MVP. We can trim down the communication later @@ -511,4 +528,20 @@ sub sort_hands { } } +# Returns 0 or 1 on success +sub take_card { + my ($p, $card) = @_; + + # Make sure they have the card, and update their hand + for (my $i = 0; $i < scalar @{$p->{hand}}; $i++) { + if ($p->{hand}->[$i] eq $card) { + splice(@{$p->{hand}}, $i, 1); + return 1; + } + } + + send_error($p, "You don't have that card!"); + return 0; +} + 1; diff --git a/public/debug.html b/public/debug.html @@ -13,11 +13,13 @@ <div id="content"></div> <script> var ws = new WebSocket('ws://localhost:3000/play'); + var GAME_PHASE = '' ws.onmessage = function (event) { msg = JSON.parse(event.data); if (msg.msg_type !== 'pong') { console.log(msg) } if (msg.msg_type === 'game_state') { + GAME_PHASE = msg.game.phase; gameState = '<br>Game: ' + msg.game.id + '<br>' + 'Players: ' + msg.game.players + '<br>' + 'Spectators: ' + msg.game.spectators + '<br>' + @@ -85,7 +87,11 @@ ws.send(JSON.stringify({action:'order', vote: 'pass'})) } function play(card) { - ws.send(JSON.stringify({action:'play_card', card: card})) + if (GAME_PHASE === 'dealer_swap') { + ws.send(JSON.stringify({action:'dealer_swap', card: card})) + } else { + ws.send(JSON.stringify({action:'play_card', card: card})) + } } window.setInterval(() => { ws.send(JSON.stringify({action:'ping'})) }, 5000);