Two new actions, some typo fixes, discard pile fix.
3 files changed, 71 insertions(+), 11 deletions(-)

M src/panacea_lib/gameplay.ml
M src/panacea_lib/gamestate.ml
M src/panacea_lib/gamestate.mli
M src/panacea_lib/gameplay.ml +21 -1
@@ 12,6 12,11 @@ open Gamestate
  * Visibility into the decks is disallowed.
  *)
 
+
+(**
+ * Actions form the baselines of moves. I'm not sure yet if I'm including the
+ * use of Player Cards (usually totally free).
+ *)
 type action =
   | Drive of infection_city          (* Move to a city connected to the one you are in. *)
   | DirectFlight of infection_city   (* Discard a city card to move to the city named on the card.*)

          
@@ 19,13 24,20 @@ type action =
   | ShuttleFlight of infection_city  (* Move from a city with a research station to another with a research station. *)
   | BuildResearch of infection_city  (* Discard card matching city you're in, build a research station. *)
   | TreatDisease of infection_city * infection_color  (* Remove cubes *)
-  | ShareKnowledge of infection_city (* Give card to another player *)
+  | TakeShareKnowledge (* Take card from another player who has the city card you're in. *)
+  | GiveShareKnowledge of string (* Give city card you're in to specified player. *)
   | DiscoverCure of infection_color * infection_card list
 
 
 type move = (action * action * action * action)
 
 
+(*
+ * Note that we're not evaluating whether these moves are legal or not; we
+ * presume that they are. The actual "brains" of the bot will be responsible for
+ * only generating legal moves; this just advances the Gamestate according to
+ * them.
+ *)
 let apply_action gs action =
   let active_player = Gamestate.active_player gs in
   match action with

          
@@ 51,6 63,14 @@ let apply_action gs action =
       gs
       |> Gamestate.place_research_station ~city:city
       |> Gamestate.decrement_actions_remaining
+  | TreatDisease (city, color) ->
+    gs
+    |> Gamestate.decrement_disease_cube_at ~city:city ~color:color
+    |> Gamestate.decrement_actions_remaining
+  | TakeShareKnowledge ->
+    gs
+    |> Gamestate.take_current_city_card_from_another_player
+    |> Gamestate.decrement_actions_remaining
   | _ -> gs
 
 

          
M src/panacea_lib/gamestate.ml +44 -10
@@ 35,7 35,7 @@ type role =
    *)
   | ContingencyPlanner
 
-  (* - Move another player's paw as if it were yours.
+  (* - Move another player's pawn as if it were yours.
    * - As an action, move any pawn to a city with another pawn.
    *)
   | Dispatcher

          
@@ 48,7 48,7 @@ type role =
 
   (* - As an action, build a research center in the city you are in (no City card needed).
    * - Once per turn as an action, move from a research station to any city by discarding
-   *   by discarding any City card.
+   *   any City card.
    *)
   | OperationsExpert
 

          
@@ 58,7 58,7 @@ type role =
   | QuarantineSpecialist
 
   (* - As an action, you may give (or a player can take) any City card from your hand.
-   *   You must both be in the same city. The card dooes not have to match the city
+   *   You must both be in the same city. The card does not have to match the city
    *   you are in.
    *)
   | Researcher

          
@@ 434,13 434,17 @@ let starting_game ~player_names ~difficu
 
 let update_location city player = {player with location=city} 
 
-let discard_card card player =
+let lose_card card player =
   let new_hand = List.filter player.hand ~f:(fun x -> not (phys_equal x card)) in
   {player with hand=new_hand} 
 
-let discard_location_card player =
+
+let gain_card card player = {player with hand=(card::player.hand)} 
+
+
+let lose_location_card player =
   let location_card = City player.location in
-  discard_card location_card player
+  lose_card location_card player
 
 
 let update_player_named (name : string) (func : player -> player) : (player -> player) =

          
@@ 456,13 460,43 @@ let move_player_to ~player ~city gs =
 
 
 let discard_player_card ~player ~card gs =
-  let updated_players = List.map ~f:(update_player_named player (discard_card card)) gs.players in
-  {gs with players=updated_players}
+  let updated_players = List.map ~f:(update_player_named player (lose_card card)) gs.players in
+  let augmented_discard = card::gs.player_discard in
+  {gs with players=updated_players; player_discard=augmented_discard}
 
 
 let discard_player_card_at_location ~player gs =
-  let updated_players = List.map ~f:(update_player_named player discard_location_card) gs.players in
-  {gs with players=updated_players}
+  let player_struct = List.hd_exn @@ List.filter ~f:(fun p -> phys_equal p.name player) gs.players in
+  let updated_players = List.map ~f:(update_player_named player lose_location_card) gs.players in
+  let augmented_discard = (City player_struct.location)::gs.player_discard in
+  {gs with players=updated_players; player_discard=augmented_discard}
+
+
+let decrement_disease_cube_at ~city ~color gs =
+  let {board;_} = gs in
+  let b_city = Map.find_exn board city in
+  match color with
+  | Black ->
+      let updated_city = {b_city with num_black=b_city.num_black - 1} in
+      {gs with available_black_cubes=gs.available_black_cubes+1; board=(Map.set board ~key:city ~data:updated_city)}
+  | Blue ->
+      let updated_city = {b_city with num_blue=b_city.num_blue - 1} in
+      {gs with available_blue_cubes=gs.available_blue_cubes+1; board=(Map.set board ~key:city ~data:updated_city)}
+  | Red ->
+      let updated_city = {b_city with num_red=b_city.num_red - 1} in
+      {gs with available_red_cubes=gs.available_red_cubes+1; board=(Map.set board ~key:city ~data:updated_city)}
+  | Yellow ->
+      let updated_city = {b_city with num_yellow=b_city.num_yellow - 1} in
+      {gs with available_yellow_cubes=gs.available_yellow_cubes+1; board=(Map.set board ~key:city ~data:updated_city)}
+
+
+let take_current_city_card_from_another_player gs =
+  let my_turn = List.nth_exn gs.players gs.curr_turn in
+  let the_card = City my_turn.location in
+  let has_card = List.hd_exn @@ List.filter ~f:(fun p -> List.mem p.hand the_card ~equal:phys_equal) gs.players in
+  let updated_players = List.map ~f:(update_player_named my_turn.name (gain_card the_card)) gs.players in
+  let final_players = List.map ~f:(update_player_named has_card.name (lose_card the_card)) updated_players in
+  {gs with players=final_players}
 
 
 

          
M src/panacea_lib/gamestate.mli +6 -0
@@ 55,8 55,14 @@ val discard_player_card_at_location : pl
 (** Use an action of this player's turn. *)
 val decrement_actions_remaining : t -> t
 
+(** Removes a cube of a certain color at the chosen location. *)
+val decrement_disease_cube_at : city:infection_city -> color:infection_color -> t -> t
+
 (** Place a Research Station at this city. *)
 val place_research_station : city:infection_city -> t -> t
 
+(** Take a card for the current player's city from another player in that city who has it. *)
+val take_current_city_card_from_another_player : t -> t
+
 (** Get the name of the player who's turn it is. *)
 val active_player : t -> string