diff --git a/TODO.md b/TODO.md index 45da4f4..9ec9ad2 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ - CD: https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ - Put everyone's discards in front of their hand (suggested by Mom) -- Bug: Can't undo to get first discarded tile of the game from bot (human went last, missed a discarded tile, can't go back to beginning of game). If there are no human actions to go back to, Undo should return to beginning of game. +- If no undoable moves, Undo button should reset the game to get first discarded tile of the game from bot (human went last, missed a discarded tile, can't go back to beginning of game). - Bug: Undoing a win after a bot drew a tile hung bot (workaround: paused & unpaused bots) - Shrink tile sizes on mobile - Lobby not receiving bot player added @@ -33,7 +33,7 @@ - Display everyone's wind direction instead of staircase - Animate deal: 4 at a time goes into people's hand - Sanity check for (possible race condition) bug: rearranging hand leads to duplicate tiles. Last time it happened after peek tile got put into hand, and user drag & dropped that new tile. -- Remember sorted hand so it doesn't get reshuffled when losing internet connection +- Remember sorted hand in browser so it doesn't get reshuffled when losing internet connection ## Future rule enforcement - Winning tile was the last one picked up diff --git a/lib/mjw/core/seat.ex b/lib/mjw/core/seat.ex index 87e6c9e..bdbc4e0 100644 --- a/lib/mjw/core/seat.ex +++ b/lib/mjw/core/seat.ex @@ -211,16 +211,36 @@ defmodule Mjw.Seat do Enum.filter([seat.peektile, seat.wintile], & &1) end - # Doesn't check wintile because it can never be populated in an undo_state + defp restore_to_hand(%__MODULE__{} = seat, %__MODULE__{} = undo_state_seat, tile) + when undo_state_seat.peektile == tile do + %{seat | peektile: tile} + end + + # When restoring a tile to a hand during an Undo, the hand probably changed + # since then so it's not always easy to determine the ideal position. We can + # assume players sort their hands, so attempt to restore it next to the tile + # that would follow it by sort order. If not available it goes to the end. defp restore_to_hand(%__MODULE__{} = seat, %__MODULE__{} = undo_state_seat, tile) do - if undo_state_seat.peektile == tile do - %{seat | peektile: tile} - else - removed_from_list = - [:exposed, :concealed, :hiddengongs] - |> Enum.find(fn list -> tile in Map.get(undo_state_seat, list) end) + # Doesn't check wintile because it can never be populated in an undo_state + removed_from_list = + [:exposed, :concealed, :hiddengongs] + |> Enum.find(fn list -> tile in Map.get(undo_state_seat, list) end) - seat |> Map.update!(removed_from_list, fn list -> list ++ [tile] end) - end + seat + |> Map.update!(removed_from_list, fn list -> + sorted_list = (list ++ [tile]) |> Mjw.Tile.sort() + sorted_list_index = sorted_list |> Enum.find_index(&(&1 == tile)) + insert_before_tile = sorted_list |> Enum.at(sorted_list_index + 1) + + insert_before_index = + if insert_before_tile do + list |> Enum.find_index(&(&1 == insert_before_tile)) + else + length(list) + end + + Enum.slice(list, 0, insert_before_index) ++ + [tile] ++ Enum.slice(list, insert_before_index..-1//1) + end) end end diff --git a/lib/mjw/core/tile.ex b/lib/mjw/core/tile.ex index 05874c2..0221cf8 100644 --- a/lib/mjw/core/tile.ex +++ b/lib/mjw/core/tile.ex @@ -5,7 +5,7 @@ defmodule Mjw.Tile do @tile_format_regex ~r/^[ncbwd][a-z1-9]-[0-3]$/ @doc """ - Sort according to beauty, with special tiles last + Sort by suit and then number """ def sort(tiles) do Enum.sort_by(tiles, fn tile -> diff --git a/test/mjw/core/seat_test.exs b/test/mjw/core/seat_test.exs index 117c12a..67a2f3a 100644 --- a/test/mjw/core/seat_test.exs +++ b/test/mjw/core/seat_test.exs @@ -587,7 +587,7 @@ defmodule Mjw.SeatTest do result = Mjw.Seat.merge_for_undo(seat, undo_state_seat) - assert result == %{seat | hiddengongs: ["n3-0", "n4-0", "n3-1"]} + assert result == %{seat | hiddengongs: ["n3-0", "n3-1", "n4-0"]} end test "restores a tile removed from the peektile by the undoable action" do diff --git a/test/mjw/core/tile_test.exs b/test/mjw/core/tile_test.exs index 7b43aa1..c804c97 100644 --- a/test/mjw/core/tile_test.exs +++ b/test/mjw/core/tile_test.exs @@ -27,6 +27,7 @@ defmodule Mjw.TileTest do "we-0", "we-1", "b9-0", + "b8-0", "b9-1", "n1-3", "dp-0", @@ -40,6 +41,7 @@ defmodule Mjw.TileTest do "n1-3", "c1-0", "b1-3", + "b8-0", "b9-0", "b9-1", "we-0",