@@ 10,6 10,7 @@ type difficulty =
| Heroic (* 6 Epidemic cards *)
[@@deriving show]
+
type role =
(* - As an action, take any discarded Event card and store it on this card.
* - When you play the stored Event card, remove it from the game.
@@ 77,6 78,7 @@ type player_card =
| City of infection_city
[@@deriving show]
+
type player = {
role : role;
name : string;
@@ 84,6 86,7 @@ type player = {
location : infection_city;
} [@@deriving show]
+
type board_city = {
name : string;
natural_color : infection_color;
@@ 107,13 110,27 @@ module CityCompare = struct
include T
include Comparable.Make(T)
end
+
+
type board =
(infection_city, board_city, CityCompare.comparator_witness) Map.t
-let pp_board _ = "Board"
+
+let show_board board =
+ let board_city_to_string (_, {name; natural_color; num_red; num_blue; num_black; num_yellow; has_research_station; _}) =
+ let research_str = if has_research_station then "(R) " else "" in
+ let header = Printf.sprintf "============ %s%s (%s)" research_str name (show_infection_color natural_color) in
+ let body = Printf.sprintf "| %d Red | %d Blue | %d Black | %d Yellow" num_red num_blue num_black num_yellow in
+ header ^ "\n" ^ body
+ in
+ Map.to_alist board
+ |> List.map ~f:board_city_to_string
+ |> String.concat ~sep:"\n"
+
type infection_card = infection_city [@@deriving show]
+
type gamestate = {
players : player list;
board : board;
@@ 135,7 152,20 @@ type gamestate = {
is_yellow_cured : bool;
}
-let pp_gamestate _ = "Gamestate"
+
+let show_gamestate gs =
+ let player_string = List.map ~f:show_player gs.players |> String.concat ~sep:"\n" in
+ let board_string = show_board gs.board in
+ let turn_string = Printf.sprintf "Current Turn: %d. Number of outbreaks: %d. Actions remaining: %d. Research stations available: %d"
+ gs.curr_turn gs.num_outbreaks gs.actions_remaining gs.research_stations_remaining
+ in
+ let cube_string = Printf.sprintf "Red cubes: %d. Blue cubes: %d. Black cubes: %d. Yellow cubes: %d."
+ gs.available_red_cubes gs.available_blue_cubes gs.available_black_cubes gs.available_yellow_cubes
+ in
+ let cure_string = Printf.sprintf "CURES: Red %B. Blue %B. Black %B. Yellow %B."
+ gs.is_red_cured gs.is_blue_cured gs.is_black_cured gs.is_yellow_cured
+ in
+ String.concat ~sep:"\n" ["===== GAMESTATE ====="; player_string; board_string; turn_string; cube_string; cure_string]
let empty_board =
@@ 155,7 185,7 @@ let empty_board =
let cities = [
make_city_from(SanFrancisco, "San Francisco", Blue, [LosAngeles; Chicago; Tokyo; Manila]);
make_city_from(Chicago, "Chicago", Blue, [SanFrancisco; LosAngeles; MexicoCity; Atlanta; Montreal]);
- make_city_from(Atlanta, "Atlanta", Red, [Miami; Chicago; Washington]);
+ make_city_from(Atlanta, "Atlanta", Blue, [Miami; Chicago; Washington]);
make_city_from(Montreal, "Montreal", Blue, [Chicago; Washington; NewYork]);
make_city_from(Washington, "Washington", Blue, [Atlanta; Montreal; NewYork; Miami]);
make_city_from(NewYork, "NewYork", Blue, [Montreal; Washington; London; Madrid]);
@@ 261,7 291,7 @@ let empty_gamestate =
let rec shuffle = function
| [] -> []
- | [single] -> [single]
+ | [x] -> [x]
| lst ->
let (before, after) = List.partition_tf ~f:(fun _elt -> Random.bool ()) lst in
List.rev_append (shuffle before) (shuffle after)
@@ 296,15 326,55 @@ let shuffle_player_deck gs =
(** Gives each player _n_ cards from the Player deck, per the starting rules. *)
-let hand_out_cards gs = gs
+let hand_out_cards gs =
+ let {players=players; player_deck=cards; _} = gs in
+ let num_per_player = 6 - List.length players in
+ let draw_for_player (player_accum, deck_accum) player =
+ let (drawn, remaining) = List.split_n deck_accum num_per_player in
+ let updated_player = {player with hand=drawn} in
+ (updated_player::player_accum, remaining)
+ in
+ let (updated_players, updated_player_deck) = List.fold_left players ~init:([], cards) ~f:draw_for_player in
+ {gs with players=(List.rev updated_players); player_deck=updated_player_deck}
(** Infects 9 cities with varying severity, per the starting rules. *)
-let infect_cities gs = gs
+let infect_cities gs =
+ let {infection_deck; _} = gs in
+ let (cities, the_rest) = List.split_n infection_deck 9 in
+ let with_quantities = List.zip_exn cities [3;3;3;2;2;2;1;1;1] in
+ let infect_city this_gs (city_name, num_cubes) =
+ let {board; available_red_cubes; available_blue_cubes; available_black_cubes; available_yellow_cubes;_} = this_gs in
+ let b_city = Map.find_exn board city_name in
+ let {natural_color; num_red; num_blue; num_black; num_yellow;_} = b_city in
+ let new_board = match natural_color with
+ | Red -> Map.set board ~key:city_name ~data:{b_city with num_red=num_red + num_cubes}
+ | Blue -> Map.set board ~key:city_name ~data:{b_city with num_blue=num_blue + num_cubes}
+ | Black -> Map.set board ~key:city_name ~data:{b_city with num_black=num_black + num_cubes}
+ | Yellow -> Map.set board ~key:city_name ~data:{b_city with num_yellow=num_yellow + num_cubes}
+ in
+ match natural_color with
+ | Red -> {this_gs with available_red_cubes=available_red_cubes - num_cubes; board=new_board}
+ | Blue -> {this_gs with available_blue_cubes=available_blue_cubes - num_cubes; board=new_board}
+ | Black ->{this_gs with available_black_cubes=available_black_cubes - num_cubes; board=new_board}
+ | Yellow -> {this_gs with available_yellow_cubes=available_yellow_cubes - num_cubes; board=new_board}
+ in
+ let with_infected = List.fold_left with_quantities ~init:gs ~f:infect_city in
+ {with_infected with infection_deck=the_rest; infection_discard=(List.rev cities)}
(** Places the outbreak cards in the remaining Player deck, per the difficulty level. *)
-let place_outbreaks _difficulty gs = gs
+let place_outbreaks difficulty gs =
+ let {player_deck;_} = gs in
+ let num_outbreaks = match difficulty with
+ | Introductory -> 4
+ | Standard -> 5
+ | Heroic -> 6
+ in
+ let to_split_size = (List.length player_deck) / num_outbreaks in
+ let chunked = List.chunks_of player_deck ~length:to_split_size in
+ let new_player_deck = List.concat_map chunked ~f:(fun sublist -> shuffle (Epidemic::sublist)) in
+ {gs with player_deck=new_player_deck}
(** Places the first research center in Atlanta. *)
@@ 319,7 389,7 @@ let place_research_station place gs =
(** Gives us a Gamestate that's ready to play! *)
-let starting_game player_names difficulty =
+let starting_game ~player_names ~difficulty =
let transformations =
[
draw_players player_names;
@@ 335,4 405,3 @@ let starting_game player_names difficult
~init:empty_gamestate
~f:(fun accum x -> x accum)
transformations
-