This commit is contained in:
		
							parent
							
								
									25c0503504
								
							
						
					
					
						commit
						2a8dfb787e
					
				| @ -11,10 +11,7 @@ defmodule Utils do | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def alter_name(name, part) do | ||||
|     String.to_atom(Atom.to_string(name) <> part) | ||||
|   end | ||||
| 
 | ||||
|   def alter_name(name, part), do: :"#{name}#{part}" | ||||
|   def beb_broadcast(m, dest), do: for(p <- dest, do: safecast(p, m)) | ||||
| 
 | ||||
|   def register_name(name, pid, link \\ true) do | ||||
| @ -46,7 +43,7 @@ defmodule Utils do | ||||
|       IO.puts(msg) | ||||
|     end | ||||
|   end | ||||
|   | ||||
| 
 | ||||
|   defmacro or_state(val, do: expr) do | ||||
|     quote do | ||||
|       case unquote(val) do | ||||
|  | ||||
							
								
								
									
										242
									
								
								lib/server.ex
									
									
									
									
									
								
							
							
						
						
									
										242
									
								
								lib/server.ex
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| defmodule ServerMacros do | ||||
| 
 | ||||
|   def create_create_loop(name, do: match_exp, else: process_exp, after: after_exp) do | ||||
|   def create_create_loop(name, do: match_exp, else: process_exp) do | ||||
|     function_name = :"#{name}_loop" | ||||
| 
 | ||||
|     ast1 = quote do | ||||
| @ -8,21 +8,14 @@ defmodule ServerMacros do | ||||
|     end | ||||
|     ast2 = quote do | ||||
|       value -> | ||||
|         log("Got unexpected value: #{inspect(value)}") | ||||
|         Process.send_after(self(), value, t + 2000) | ||||
|         # TODO check spelling | ||||
|         log("Disreguarding: #{inspect(value)}") | ||||
|         # Process.send_after(self(), value, t + 2000) | ||||
|         unquote(function_name)(v, t) | ||||
|     end | ||||
| 
 | ||||
|     ast3 = ast1 ++ match_exp ++ ast2 | ||||
| 
 | ||||
|     after_exp = if after_exp == nil do | ||||
|       quote do | ||||
|         t -> :timeout | ||||
|       end | ||||
|     else | ||||
|       after_exp | ||||
|     end | ||||
| 
 | ||||
|     quote do | ||||
|       def unquote(function_name)(v, t) do | ||||
|         var!(v) = v | ||||
| @ -30,22 +23,18 @@ defmodule ServerMacros do | ||||
|         receive do | ||||
|           unquote(ast3) | ||||
|         after | ||||
|           unquote(after_exp) | ||||
|           t -> :timeout | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def create_create_loop(name, do: exp, else: else_exp) do | ||||
|     create_create_loop(name, do: exp, else: else_exp, after: nil) | ||||
|   end | ||||
| 
 | ||||
|   def create_create_loop(name, do: exp, after: after_exp) do | ||||
|     create_create_loop(name, do: exp, else: nil, after: after_exp) | ||||
|     create_create_loop(name, do: exp, else: else_exp) | ||||
|   end | ||||
| 
 | ||||
|   def create_create_loop(name, do: exp) do | ||||
|     create_create_loop(name, do: exp, else: nil, after: nil) | ||||
|     create_create_loop(name, do: exp, else: nil) | ||||
|   end | ||||
| 
 | ||||
|   defmacro create_loop(name, clauses) do | ||||
| @ -140,7 +129,7 @@ defmodule Server do | ||||
|         state = qurey_status(state) | ||||
|         game = state.games[game_id] | ||||
|         cond do | ||||
|           is_finished(game, game_id) -> | ||||
|           is_finished(state, game_id) -> | ||||
|             {_, score} = state.games[game_id] | ||||
|             safecast(pid_to_inform, {:make_move, game_id, :game_finished, score}) | ||||
|             state | ||||
| @ -155,8 +144,7 @@ defmodule Server do | ||||
| 
 | ||||
|   def try_to_play(state, game_id, move, pid_to_inform) do | ||||
|     name = state.name | ||||
|     # TODO create new hand | ||||
|     new_hand = 2 | ||||
|     new_hand = get_hand_for_game_state(state.games[game_id].game_state) | ||||
|     try_propose {:make_move, game_id, name, move, new_hand} | ||||
|     do | ||||
|       {:decision, {:make_move, ^game_id, ^name, ^move, ^new_hand}} -> | ||||
| @ -206,20 +194,36 @@ defmodule Server do | ||||
| 
 | ||||
|       true -> | ||||
|         state = qurey_status(state) | ||||
|         safecast(pid_to_inform, {:game_state, game_id, state.games[game_id].game_state, state.games[game_id].hand[state.name]}) | ||||
|         if is_finished(state, game_id) do | ||||
|           {_, score} = state.games[game_id] | ||||
|           safecast(pid_to_inform, {:game_state, game_id, :game_finished, score}) | ||||
|         else | ||||
|           game = state.games[game_id] | ||||
|           safecast(pid_to_inform, {:game_state, game_id, game.game_state, game.hand[state.name]}) | ||||
|         end | ||||
|         state | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def get_hand_for_game_state(game_state) do | ||||
|     r1 = Enum.random(0..100) | ||||
|     if r1 <= 10 do | ||||
|       :+ | ||||
|     else | ||||
|       mx = game_state |> Enum.filter(fn m -> m != :+ end) |> Enum.max() | ||||
|       mn = max(mx - 20, 1) | ||||
|       mx = max(mx - 2, 4) | ||||
|       Enum.random(mn..mx) | ||||
|     end  | ||||
|   end | ||||
| 
 | ||||
|   def try_to_create_game(state, participants) do | ||||
|     game_ids = Map.keys(state.games) | ||||
|     latest = Enum.at(Enum.sort(game_ids), length(game_ids) - 1) | ||||
|     new_game_id = if latest do latest else 0 end + 1 | ||||
| 
 | ||||
|     # TODO: randomize game state | ||||
|     new_game_state = [1, 1] | ||||
|     # TODO: randomize Initial hand value | ||||
|     hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end) | ||||
|     new_game_state = Enum.to_list(0..Enum.random(3..8)) |> Enum.map(fn _ -> Enum.random(1..4) end) | ||||
|     hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, get_hand_for_game_state(new_game_state)) end) | ||||
| 
 | ||||
|     try_propose {:start_game, new_game_id, participants, new_game_state, hand} | ||||
|     do | ||||
| @ -252,7 +256,7 @@ defmodule Server do | ||||
| 
 | ||||
|   def set_modifed(state, game, val \\ false) do | ||||
|     or_state not is_finished(state, game) do | ||||
|       %{state | games: Map.put(state.games, game, %{state.games | modified: val})} | ||||
|       %{state | games: Map.put(state.games, game, %{state.games[game] | modified: val})} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -260,34 +264,174 @@ defmodule Server do | ||||
|   # Apply Game States | ||||
|   # | ||||
| 
 | ||||
|   def get_index(indexed_game_state, spos, index) do | ||||
|     index = spos + index | ||||
|     len = length(indexed_game_state) | ||||
|     cond do | ||||
|       index < 0 -> | ||||
|         len - 1 | ||||
|       index >= len -> | ||||
|         rem(index, len) | ||||
|       true -> | ||||
|         index  | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def simplify_game_state_pluses([], indexed_game_state), do: {false, indexed_game_state} | ||||
|   def simplify_game_state_pluses([{:+, i} | tl], indexed_game_state) do | ||||
|     before_i = get_index(indexed_game_state, i, -1) | ||||
|     after_i = get_index(indexed_game_state, i, 1) | ||||
| 
 | ||||
|     if before_i != after_i do  | ||||
|       {b, b_i} = Enum.at(indexed_game_state, before_i) | ||||
|       {a, a_i} = Enum.at(indexed_game_state, after_i) | ||||
| 
 | ||||
|       if b == a do | ||||
|         case b do | ||||
|           :+ -> simplify_game_state_pluses(tl, indexed_game_state) | ||||
|           n -> | ||||
|             list = | ||||
|               indexed_game_state |> | ||||
|               Enum.map(fn {x, ti} -> if ti == i, do: {{:merged, n + 1}, i}, else: {x, ti} end) |> | ||||
|               Enum.filter(fn {x, ti} -> cond do | ||||
|                   b_i == ti -> false | ||||
|                   a_i == ti -> false | ||||
|                   true -> true | ||||
|                 end | ||||
|               end) |> | ||||
|               reindex() | ||||
|             {true, expand_merge(list)} | ||||
|         end | ||||
|       else | ||||
|         simplify_game_state_pluses(tl, indexed_game_state) | ||||
|       end | ||||
|     else | ||||
|         simplify_game_state_pluses(tl, indexed_game_state) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def is_merged(item) do | ||||
|     case item do | ||||
|       {:merged, _} -> true | ||||
|       _ -> false | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def expand_merge(indexed_game_state) do | ||||
|     {{:merged, n}, i} = indexed_game_state |> Enum.find(fn {x, _} -> is_merged(x) end) | ||||
| 
 | ||||
|     b_i = get_index(indexed_game_state, i, - 1) | ||||
|     a_i = get_index(indexed_game_state, i, + 1) | ||||
| 
 | ||||
|     if b_i != a_i do | ||||
|       {b, b_i} = Enum.at(indexed_game_state, b_i) | ||||
|       {a, a_i} = Enum.at(indexed_game_state, a_i) | ||||
|       if a == b do | ||||
|         case b do | ||||
|           :+ -> indexed_game_state | ||||
|           {:merged, _} -> indexed_game_state | ||||
|           _ -> | ||||
|             indexed_game_state |> | ||||
|               Enum.map(fn {x, ti} -> if ti == i, do: {{:merged, n + 1}, i}, else: {x, ti} end) |> | ||||
|               Enum.filter(fn {x, ti} -> cond do | ||||
|                   b_i == ti -> false | ||||
|                   a_i == ti -> false | ||||
|                   true -> true | ||||
|                 end | ||||
|               end) |> | ||||
|               reindex() |> | ||||
|               expand_merge() | ||||
|         end | ||||
|       else | ||||
|         indexed_game_state | ||||
|       end | ||||
|     else | ||||
|       indexed_game_state | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def reindex(list, flat \\ true) do | ||||
|     list = if flat do | ||||
|       list |> Enum.map(fn {n, _} -> n end) | ||||
|     else | ||||
|       list | ||||
|     end | ||||
| 
 | ||||
|     [list, 0..(length(list) - 1)] |> Enum.zip() | ||||
|   end | ||||
| 
 | ||||
|   def remove_merged([], rec, _), do: rec | ||||
| 
 | ||||
|   def remove_merged([{:merged, n} | tl], rec, add) do | ||||
|     if add do | ||||
|       remove_merged(tl, rec ++ [n], false) | ||||
|     else | ||||
|       remove_merged(tl, rec, false) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def remove_merged([n | tl], rec, add), do:  | ||||
|     remove_merged(tl, rec ++ [n], add) | ||||
| 
 | ||||
|   def remove_merged(list) do | ||||
|     log("#{inspect(list)}") | ||||
|     remove_merged(list, [], true) | ||||
|   end | ||||
| 
 | ||||
|   def simplify_game_state(game_state) do | ||||
|     # TODO actualy do this | ||||
|     game_state | ||||
|     log("game_state: #{inspect(game_state)}") | ||||
|     indexed_game_state =  | ||||
|       game_state |> | ||||
|       reindex(false) | ||||
| 
 | ||||
|     {repeat, indexed_game_state} = | ||||
|       indexed_game_state |> | ||||
|       Enum.filter(fn x -> case x do  | ||||
|         {:+, _} -> true | ||||
|         _ -> false | ||||
|         end | ||||
|       end) |> | ||||
|       simplify_game_state_pluses(indexed_game_state) | ||||
| 
 | ||||
|     log("game_state2: #{inspect(indexed_game_state)}") | ||||
| 
 | ||||
|     if repeat do | ||||
|       indexed_game_state |>  | ||||
|         Enum.map(fn {v, _} -> v end) |> | ||||
|         remove_merged() |> | ||||
|         simplify_game_state() | ||||
|     else | ||||
|       indexed_game_state |> Enum.map(fn {v, _} -> v end) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def apply_game(state, {:make_move, game_id, player_name, pos_move, new_hand}) do | ||||
|     game = state.games[game_id] | ||||
|     case game do | ||||
|       {:finished, _} -> | ||||
|         raise :game_already_finished | ||||
|         raise "Game already finished" | ||||
|       :not_playing_in_game -> | ||||
|         %{state | instance: state.instance + 1 } | ||||
|       game -> | ||||
|         game_state = game.game_state | ||||
|         {b, e} = Enum.split(game_state, pos_move) | ||||
|         game_state = b ++ [ game.hand[player_name] ] ++ e | ||||
|         game_state = simplefy_game_state(game_state) | ||||
|         game_state = simplify_game_state(game_state) | ||||
|         hand = Map.put(game.hand, player_name, new_hand) | ||||
|         game = %{game| hand: hand, game_state: game_state } | ||||
|         # TODO decide if it's ending state | ||||
|         %{state| games: Map.put(state.games, game_id, game)} | ||||
| 
 | ||||
|         if length(game.game_state) > 15 do | ||||
|           %{state| games: Map.put(state.games, game_id, {:finished, Enum.sum(game.game_state)}), instance: state.instance + 1} | ||||
|         else | ||||
|           %{state| games: Map.put(state.games, game_id, game), instance: state.instance + 1} | ||||
|         end | ||||
|     end | ||||
|   end | ||||
|    | ||||
|   def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do | ||||
|     cond do | ||||
|       state.games[game_id] -> | ||||
|         raise :game_already_exists | ||||
|         raise "Game Already Exists" | ||||
|       state.name in participants -> | ||||
|         %{state |  | ||||
|           games: Map.put(state.games, game_id, %{ | ||||
| @ -306,7 +450,7 @@ defmodule Server do | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def apply_game(_, _), do: raise :do_not_know_how_to_apply_game_state | ||||
|   def apply_game(_, _), do: raise "Do not know how to apply game state" | ||||
| 
 | ||||
|   ############ | ||||
|   # Interface  | ||||
| @ -320,47 +464,53 @@ defmodule Server do | ||||
| 
 | ||||
|   def start_game(name, participants) do | ||||
|     safecast(name, {:start_game, participants, self()}) | ||||
|     start_game_loop(nil, 1000) | ||||
|     start_game_loop(nil, 10000) | ||||
|   end | ||||
| 
 | ||||
|   create_loop :get_game_state do | ||||
|     {:game_state, ^v, :not_playing} -> | ||||
|       IO.puts("Not Playing in that game") | ||||
|       log("Not Playing in that game") | ||||
|       {:not_playing} | ||||
|     {:game_state, ^v, game_state, hand} -> | ||||
|       IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}") | ||||
|       log("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}") | ||||
|       {:state, game_state, hand} | ||||
|     {:game_state, ^v, :not_playing} -> | ||||
|       log("Not Playing in that game") | ||||
|       {:not_playing} | ||||
|     {:game_state, ^v, :game_finished, score} -> | ||||
|       log("Game finsihed, #{score}") | ||||
|       {:game_finished, score} | ||||
|     {:game_state, ^v, :game_does_not_exist} -> | ||||
|       IO.puts("Got game does not exist") | ||||
|       log("Got game does not exist") | ||||
|       {:not_exists} | ||||
|   end | ||||
| 
 | ||||
|   def get_game_state(name, game_id) do | ||||
|     safecast(name, {:get_game_state, game_id, self()}) | ||||
|     get_game_state_loop(game_id, 1000) | ||||
|     get_game_state_loop(game_id, 10000) | ||||
|   end | ||||
| 
 | ||||
|   create_loop :make_move do | ||||
|     {:make_move, ^v, :game_does_not_exist} -> | ||||
|       IO.puts("Got game does not exist") | ||||
|       log("Got game does not exist") | ||||
|       {:not_exists} | ||||
|     {:make_move, ^v, :not_playing} -> | ||||
|       IO.puts("Not Playing in that game") | ||||
|       log("Not Playing in that game") | ||||
|       {:not_playing} | ||||
|     {:make_move, ^v, :game_finished, score} -> | ||||
|       IO.puts("Game finsihed, #{score}") | ||||
|       log("Game finsihed, #{score}") | ||||
|       {:game_finished, score} | ||||
|     {:make_move, ^v, :player_moved_before, game_state, hand} -> | ||||
|       IO.puts("Player moved_before, #{inspect(game_state)} #{inspect(hand)}") | ||||
|       log("Player moved_before, #{inspect(game_state)} #{inspect(hand)}") | ||||
|       {:player_moved_before, game_state, hand} | ||||
|     {:make_move, ^v, game_state, hand} -> | ||||
|       IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}") | ||||
|       log("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}") | ||||
|       {:state, game_state, hand} | ||||
|   end | ||||
| 
 | ||||
|   def make_move(name, game_id, move) do | ||||
|     safecast(name, {:make_move, game_id, move, self()}) | ||||
|     make_move_loop(game_id, 1000) | ||||
|     make_move_loop(game_id, 10000) | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user