diff --git a/apps/go_fish/lib/go_fish/controller.ex b/apps/go_fish/lib/go_fish/controller.ex index 454e6f2..5b4e374 100644 --- a/apps/go_fish/lib/go_fish/controller.ex +++ b/apps/go_fish/lib/go_fish/controller.ex @@ -17,6 +17,17 @@ defmodule GoFish.Controller do GenServer.call(__MODULE__, :get_players) end + def get_player_states() do + players = GoFish.Controller.get_players() + + player_states_list = + Enum.reduce(players, [], fn player, acc -> + [{player, GoFish.Player.get_state(player)} | acc] + end) + + Map.new(player_states_list) + end + def start_game(player_list) do GenServer.call(__MODULE__, {:start_game, player_list}) end @@ -33,8 +44,7 @@ defmodule GoFish.Controller do GenServer.cast(__MODULE__, :stop) end - - #Helper functions + # Helper functions # def name_to_id(name) do # String.to_atom(name) @@ -53,7 +63,7 @@ defmodule GoFish.Controller do end def most_books(list_of_tuples) do - most_books([hd(list_of_tuples),most_books(tl(list_of_tuples))]) + most_books([hd(list_of_tuples), most_books(tl(list_of_tuples))]) end def game_over_state(state) do @@ -64,14 +74,14 @@ defmodule GoFish.Controller do %{:players => [], :game_state => :uninitialized, :total_books => 0, :winner => :undetermined} end - # Callback def init(_arg) do {:ok, initial_game_state()} end def handle_call({:new_player, player_name}, _from, state) do - {:reply, {:new_player_added, player_name}, Map.update!(state, :players, fn x -> [player_name|x] end)} + {:reply, {:new_player_added, player_name}, + Map.update!(state, :players, fn x -> [player_name | x] end)} end def handle_call(:get_state, _from, state) do @@ -82,23 +92,27 @@ defmodule GoFish.Controller do {:reply, Map.get(state, :players, []), state} end - def handle_call({:start_game, player_list}, _from, state) when state.game_state == :uninitialized do + def handle_call({:start_game, player_list}, _from, state) + when state.game_state == :uninitialized do for name <- player_list do - if length(player_list)>2 do + if length(player_list) > 2 do GoFish.Player.draw_cards(name, 5) else GoFish.Player.draw_cards(name, 7) end end + GoFish.Player.give_turn_to(hd(player_list)) {:reply, :ok, Map.put(state, :game_state, :in_progress)} end def handle_call(:game_over, _from, state) when state.game_state == :in_progress do final_state = game_over_state(state) + for name <- state.players do GoFish.Player.stop(name) end + GoFish.Ocean.stop() {:reply, :game_terminated, final_state} end @@ -110,9 +124,11 @@ defmodule GoFish.Controller do def handle_cast(:book_made, state) when state.total_books == 12 do IO.puts("Final book") final_state = game_over_state(state) + for name <- state.players do GoFish.Player.stop(name) end + GoFish.Ocean.stop() {:noreply, final_state} end @@ -125,5 +141,4 @@ defmodule GoFish.Controller do def handle_cast(:stop, _state) do {:stop, :normal} end - end diff --git a/apps/go_fish_web/assets/css/go_fish.css b/apps/go_fish_web/assets/css/go_fish.css index bf1aa56..af92fa7 100644 --- a/apps/go_fish_web/assets/css/go_fish.css +++ b/apps/go_fish_web/assets/css/go_fish.css @@ -19,7 +19,9 @@ } /* highlight selected card */ -input[type="radio"]:checked+div{ background-color: #95C8FF; } +input[type="radio"]:checked+div { + background-color: #95C8FF; +} input.hide-radio-input { /* Add if not using autoprefixer */ @@ -54,3 +56,28 @@ input.hide-radio-input { display: inline; } +.modal { + display: block; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0, 0, 0); + /* Fallback color */ + background-color: rgba(0, 0, 0, 0.4); + /* Black w/ opacity */ +} + +.modal-content { + background: white; + margin: 15% auto; + padding: 20px; + border: 1px solid; + border-radius: 5px; + width: fit-content; + display: flex; + flex-direction: column; +} \ No newline at end of file diff --git a/apps/go_fish_web/lib/go_fish_web/controllers/choose_player_controller.ex b/apps/go_fish_web/lib/go_fish_web/controllers/choose_player_controller.ex new file mode 100644 index 0000000..a228c81 --- /dev/null +++ b/apps/go_fish_web/lib/go_fish_web/controllers/choose_player_controller.ex @@ -0,0 +1,10 @@ +defmodule GoFishWeb.ChoosePlayerController do + use GoFishWeb, :controller + + import GoFishWeb.GameView + + def index(conn, _) do + + render(conn, "index.html", players: GoFish.Controller.get_players()) + end +end diff --git a/apps/go_fish_web/lib/go_fish_web/controllers/game_controller.ex b/apps/go_fish_web/lib/go_fish_web/controllers/game_controller.ex index 9bbd2f7..b38e17a 100644 --- a/apps/go_fish_web/lib/go_fish_web/controllers/game_controller.ex +++ b/apps/go_fish_web/lib/go_fish_web/controllers/game_controller.ex @@ -1,25 +1,25 @@ defmodule GoFishWeb.GameController do use GoFishWeb, :controller - def index(conn, _params) do - if nil == Process.whereis(GoFish.Controller) do - redirect(conn, to: "/welcome") - else - players = GoFish.Controller.get_players() - player_states_list = - Enum.reduce(players, [], fn player, acc -> - [{player, GoFish.Player.get_state(player)} | acc] - end) + # def index(conn, _params) do + # if nil == Process.whereis(GoFish.Controller) do + # redirect(conn, to: "/welcome") + # else + # players = GoFish.Controller.get_players() + # player_states_list = + # Enum.reduce(players, [], fn player, acc -> + # [{player, GoFish.Player.get_state(player)} | acc] + # end) - player_states = Map.new(player_states_list) + # player_states = Map.new(player_states_list) - render( - conn, - "index.html", - player_states: player_states - ) - end - end + # render( + # conn, + # "index.html", + # player_states: player_states + # ) + # end + # end def string_to_atom_list(s) do s diff --git a/apps/go_fish_web/lib/go_fish_web/live/game_live.ex b/apps/go_fish_web/lib/go_fish_web/live/game_live.ex new file mode 100644 index 0000000..c02aacc --- /dev/null +++ b/apps/go_fish_web/lib/go_fish_web/live/game_live.ex @@ -0,0 +1,64 @@ +defmodule GoFishWeb.GameLive do + use GoFishWeb, :live_view + + import GoFishWeb.GameView + + def mount(_params, _, socket) do + if nil == Process.whereis(GoFish.Controller) do + {:ok, redirect(socket, to: "/welcome")} + else + # check every 0.1s if there is a change then send it + if connected?(socket), do: Process.send_after(self(), :update, 100) + + {:ok, + socket + |> assign(:players, GoFish.Controller.get_players()) + |> assign(:client_player, nil)} + end + end + + def mount(_params, _, %{"assigns" => %{"client_player" => client_player}} = socket) do + if nil == Process.whereis(GoFish.Controller) do + {:ok, redirect(socket, to: "/welcome")} + else + # check every 0.1s if there is a change then send it + if connected?(socket), do: Process.send_after(self(), :update, 100) + + + {:ok, + socket + |> assign(:player_state, GoFish.Player.get_state(String.to_atom(client_player))) + |> assign(:opponents, Map.delete(GoFish.Controller.get_players(), client_player)) + |> assign(:client_player, nil)} + end + end + + def mount(_params, _, %{"assigns" => %{"client_player" => player}} = socket) do + {:ok, + socket + |> assign(:player_state, GoFish.Player.get_state(player))} + end + + def handle_info(:update, %{"assigns" => %{"client_player" => client_player}} = socket) do + Process.send_after(self(), :update, 1) + player_state = GoFish.Player.get_state(client_player) + {:noreply, assign(socket, :player_state, player_state)} + end + + def handle_info(:update, socket) do + Process.send_after(self(), :update, 1) + {:noreply, socket} + end + + #FIXME seems like it is not handling this event properly + def handle_event("choose_player", %{"value" => client_player}, socket) do + {:noreply, + socket + |> assign(:client_player, client_player) + |> assign(:player_state, GoFish.Player.get_state(String.to_atom(client_player)) + |> assign(:opponents, Map.delete(GoFish.Controller.get_players(), client_player)) + ) + } + end + +end diff --git a/apps/go_fish_web/lib/go_fish_web/live/game_live.html.heex b/apps/go_fish_web/lib/go_fish_web/live/game_live.html.heex new file mode 100644 index 0000000..6c41cda --- /dev/null +++ b/apps/go_fish_web/lib/go_fish_web/live/game_live.html.heex @@ -0,0 +1,88 @@ +<%= if @client_player == nil do %> + +<% else %> +
+
+
+ +
+

Hey <%= uppercase(@client_player) %>

+
+ <%= if (get_in(@player_state, :is_my_turn)) do %> + It's your turn!
+ <%= if !Enum.empty?(get_in(@player_states, :hand)) do %> + Ask the following player:
+ <%= for opponent <- @opponents do %> +
+ +
+ <% end %> + + For all their cards with the same value as:
+ <% end %> + <% end %> +
+ <%= for card <- get_in(@player_state, :hand) |> Enum.sort(&(&1.value >= + &2.value)) # Sort by value + do %> + + <% end %> +
+
+ +
+
+ <%= if (get_in(@player_state, :is_my_turn)) and Enum.empty?(get_in(@player_state, :hand)) do %> + + <% end %> +
Collected books:
+ <%= for book <- get_in(@player_state, :books) do %> + <%= book %>'s + <% end %> +
+
+
+
+<% end %> diff --git a/apps/go_fish_web/lib/go_fish_web/router.ex b/apps/go_fish_web/lib/go_fish_web/router.ex index 478b65a..e2f1196 100644 --- a/apps/go_fish_web/lib/go_fish_web/router.ex +++ b/apps/go_fish_web/lib/go_fish_web/router.ex @@ -1,6 +1,8 @@ defmodule GoFishWeb.Router do use GoFishWeb, :router + import Phoenix.LiveView.Router + pipeline :browser do plug :accepts, ["html"] plug :fetch_session @@ -16,9 +18,10 @@ defmodule GoFishWeb.Router do scope "/", GoFishWeb do pipe_through :browser + live "/", GameLive get "/welcome", WelcomeController, :index - get "/", GameController, :index get "/start_game", GameController, :start_game + get "/choose_player", ChoosePlayerController, :index get "/draw_card/:player", GameController, :draw_card get "/ask_for_card/", GameController, :ask_for_card end diff --git a/apps/go_fish_web/lib/go_fish_web/templates/choose_player/index.html.heex b/apps/go_fish_web/lib/go_fish_web/templates/choose_player/index.html.heex new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps/go_fish_web/lib/go_fish_web/templates/choose_player/index.html.heex @@ -0,0 +1 @@ + diff --git a/apps/go_fish_web/lib/go_fish_web/templates/layout/root.html.heex b/apps/go_fish_web/lib/go_fish_web/templates/layout/root.html.heex index b65db5a..3b738f6 100644 --- a/apps/go_fish_web/lib/go_fish_web/templates/layout/root.html.heex +++ b/apps/go_fish_web/lib/go_fish_web/templates/layout/root.html.heex @@ -8,6 +8,7 @@ <%= live_title_tag assigns[:page_title] || "GoFish", suffix: " ยท Phoenix Framework" %> +
diff --git a/apps/go_fish_web/lib/go_fish_web/views/choose_player_view.ex b/apps/go_fish_web/lib/go_fish_web/views/choose_player_view.ex new file mode 100644 index 0000000..6d73c46 --- /dev/null +++ b/apps/go_fish_web/lib/go_fish_web/views/choose_player_view.ex @@ -0,0 +1,5 @@ +defmodule GoFishWeb.ChoosePlayerView do + import GoFishWeb.GameView, only: [uppercase: 1] #TODO: refactor this + + use GoFishWeb, :view +end