⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{collection|Go Fish}}
type pip = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace let pips = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten; Jack; Queen; King; Ace] type suit = Diamonds | Spades | Hearts | Clubs let suits = [Diamonds; Spades; Hearts; Clubs] type card = pip * suit let string_of_pip = function | Two -> "Two" | Three -> "Three" | Four -> "Four" | Five -> "Five" | Six -> "Six" | Seven -> "Seven" | Eight -> "Eight" | Nine -> "Nine" | Ten -> "Ten" | Jack -> "Jack" | Queen -> "Queen" | King -> "King" | Ace -> "Ace" let string_of_suit = function | Diamonds -> "Diamonds" | Spades -> "Spades" | Hearts -> "Hearts" | Clubs -> "Clubs" let string_of_card (pip, suit) = (Printf.sprintf "(%s-%s)" (string_of_pip pip) (string_of_suit suit)) let pip_of_card (pip, _) = (pip) let deck = List.concat (List.map (fun pip -> List.map (fun suit -> (pip, suit)) suits) pips) type rank_state = | Unknown (* Don't know if the opponent has any cards in that rank. *) | No_cards (* Opponent has no cards there; I took them away, or I asked yet. *) | Has_cards (* Opponent has cards there; they tried to get them off me and haven't booked them yet. *) | Booked (* Someone has booked the rank. *) let state_score = function | Booked -> 0 | No_cards -> 1 | Unknown -> 2 | Has_cards -> 3 let string_of_state = function | Booked -> "Booked" | No_cards -> "No_cards" | Unknown -> "Unknown" | Has_cards -> "Has_cards" let replace ((rank,_) as state) opp = let rec aux acc = function | (_rank,_)::tl when _rank = rank -> List.rev_append acc (state::tl) | hd::tl -> aux (hd::acc) tl | [] -> assert(false) in aux [] opp ;; class virtual abstract_player = object (s) val mutable virtual cards : card list val mutable virtual books : pip list method virtual ask_rank : unit -> pip method virtual give_rank : pip -> card list method virtual notify_booked : pip -> unit method virtual request_failed : pip -> unit method private cards_given rank = let matched, rest = List.partition (fun (pip,_) -> pip = rank) cards in if List.length matched = 4 then begin cards <- rest; books <- rank :: books; s#notify_booked rank; (Some rank) end else (None) method give_card (card : card) = let rank = pip_of_card card in cards <- card :: cards; s#cards_given rank method give_cards (_cards : card list) = let rank = match _cards with | [] -> invalid_arg "empty list" | hd::tl -> List.fold_left (fun rank1 (rank2,_) -> if rank1 <> rank2 then invalid_arg "!= ranks" else (rank1) ) (pip_of_card hd) tl in cards <- _cards @ cards; s#cards_given rank method give_rank rank = let give, _cards = List.partition (fun (pip, _) -> pip = rank) cards in cards <- _cards; (give) method books_length = (List.length books) method empty_hand = cards = [] method private dump_cards() = print_endline(String.concat ", " (List.map string_of_card cards)); end class human_player = object (s) inherit abstract_player val mutable cards = [] val mutable books = [] method ask_rank() = let ranks = List.fold_left (fun acc card -> let rank = pip_of_card card in if List.mem rank acc then (acc) else (rank::acc) ) [] cards in s#dump_cards(); Printf.printf "Ranks: %s\n%!" (String.concat ", " (List.map string_of_pip ranks)); let n = List.length ranks in Printf.printf "choose from 1 to %d\n%!" n; let get_int() = try read_int() with Failure "int_of_string" -> raise Exit in let rec aux() = let d = get_int() in if d <= 0 || d > n then aux() else (pred d) in let d = aux() in (List.nth ranks d) method notify_booked rank = Printf.printf "Rank [%s] is now booked\n%!" (string_of_pip rank); method request_failed rank = () end class ai_player = object (s) inherit abstract_player as parent val mutable cards = [] val mutable books = [] val mutable opponent = List.map (fun rank -> (rank, Unknown)) pips method private dump_state() = let f (pip, state) = Printf.sprintf "{%s:%s}" (string_of_pip pip) (string_of_state state) in print_endline(String.concat ", " (List.map f opponent)); method ask_rank() = let ranks = List.fold_left (fun acc card -> let rank = pip_of_card card in try let _,n = List.find (fun (_rank,_) -> _rank = rank) acc in (replace (rank, n+1) acc) with Not_found -> ((rank,1)::acc) ) [] cards in let f (rank,_) = (state_score(List.assoc rank opponent)) in let ranks = List.sort (fun a b -> (f b) - (f a)) ranks in (* DEBUG Printf.printf "Ranks: %s\n%!" (String.concat ", " (List.map string_of_pip ranks)); s#dump_state(); s#dump_cards(); *) opponent <- List.sort (fun _ _ -> Random.int 9 - Random.int 9) opponent; match ranks with | [] -> Jack | (x,_)::_ -> x method give_cards (_cards : card list) = let rank = pip_of_card(List.hd _cards) in opponent <- replace (rank, No_cards) opponent; (parent#give_cards _cards) method give_rank rank = opponent <- replace (rank, Has_cards) opponent; (parent#give_rank rank) method notify_booked rank = opponent <- replace (rank, Booked) opponent method request_failed rank = opponent <- replace (rank, No_cards) opponent end class random_player = object (s) inherit ai_player method ask_rank() = let ranks = List.fold_left (fun acc card -> let rank = pip_of_card card in if List.mem rank acc then (acc) else (rank::acc) ) [] cards in let n = List.length ranks in let d = Random.int n in (List.nth ranks d) end exception Empty_deck let card_to_player deck player op = match deck with | card::deck -> begin match player#give_card card with | None -> () | Some rank -> op#notify_booked rank end; (deck) | _ -> raise Empty_deck let n_cards_to_player n deck player op = let rec aux i deck = if i >= n then (deck) else let deck = card_to_player deck player op in aux (succ i) deck in aux 0 deck ;; let () = Random.self_init(); let deck = List.sort (fun _ _ -> Random.int 9 - Random.int 9) deck in let player_a = new human_player and player_b = new ai_player in let deck = n_cards_to_player 9 deck player_a player_b in let deck = n_cards_to_player 9 deck player_b player_a in let deck = ref deck in let empty_hand player1 player2 = if player1#empty_hand then deck := card_to_player !deck player1 player2 in let rec make_turn id1 id2 player1 player2 = print_newline(); (try empty_hand player1 player2; empty_hand player2 player1; with Empty_deck -> ()); if player1#books_length + player2#books_length <> 13 then begin let rank = player1#ask_rank() in Printf.printf "player %s asked for %ss\n%!" id1 (string_of_pip rank); let cards = player2#give_rank rank in match cards with | [] -> Printf.printf "player %s has no %ss\n%!" id2 (string_of_pip rank); player1#request_failed rank; (try deck := card_to_player !deck player1 player2; make_turn id2 id1 player2 player1 with Empty_deck -> ()) | cards -> let given = String.concat ", " (List.map string_of_card cards) in Printf.printf "player %s gives %s\n%!" id2 given; begin match player1#give_cards cards with | None -> () | Some rank -> Printf.printf "player %s booked [%s]\n%!" id1 (string_of_pip rank); player2#notify_booked rank; end; make_turn id1 id2 player1 player2 end in (try if Random.bool() then make_turn "a" "b" player_a player_b else make_turn "b" "a" player_b player_a; with Exit -> ()); Printf.printf "player a has %d books\n" (player_a#books_length); Printf.printf "player b has %d books\n" (player_b#books_length); ;;