(* =============================================== *) (* == Concurrent chifoumi game == *) (* -- Compilation command line: ocamlc -thread -custom -o chifoumi unix.cma threads.cma chifoumi.ml \ -cclib -lunix -cclib -lthreads *) open Unix ;; (* == Standard utils *) let start_msg id = "Start game as player "^id ;; let debug = false let debug_msg msg = if debug then ( print_endline msg; flush Pervasives.stdout ) ;; let writeln oc s = output_string oc s; output_string oc "\n"; flush oc ;; (* == A play *) type plays = No_play | Quit | Play of int ;; let plays_of_int n = if n < 0 then No_play else if n < 6 then Play n else Quit let plays_of_string s = match s with "" -> No_play | "q" -> Quit | _ -> Play (int_of_string s) ;; let string_of_plays p = match p with No_play -> "" | Quit -> "q" | Play n -> string_of_int n ;; let int_of_plays p = match p with Play n -> n | _ -> 0 ;; (* == The game state *) type player_states = { mutable score : int; mutable play : plays } type game_states = { players : player_states array; mutable wsem : int; mutable rsem : int; m : Mutex.t; c : Condition.t } let new_state() = { players = [| { score = 0; play = No_play }; { score = 0; play = No_play } |]; wsem = 0; rsem = 2; m = Mutex.create (); c = Condition.create () } let get_play st id = st.players.(id).play ;; let get_score st id = st.players.(id).score ;; let get_players st = (get_score st 0), (get_play st 0), (get_score st 1), (get_play st 1) ;; let scoring st = match (get_play st 0), (get_play st 1) with Play 0, Play 5 -> 0, 6 | Play 5, Play 0 -> 1, 6 | Play n0, Play n1 -> if n0 < n1 then 1, n1 else if n1 < n0 then 0, n0 else 0, 0 | _ -> 0, 0 ;; let write_play st id p = while st.rsem < 2 do Condition.wait st.c st.m done; st.players.(id).play <- p; st.wsem <- st.wsem + 1; (if st.wsem = 2 then let id, n = scoring st in st.players.(id).score <- st.players.(id).score + n; st.rsem <- 0); Condition.signal st.c; Mutex.unlock st.m ;; let read_players st = while st.wsem < 2 do Condition.wait st.c st.m done; let res = get_players st in st.rsem <- st.rsem + 1; (if st.rsem = 2 then st.wsem <- 0); Condition.signal st.c; Mutex.unlock st.m; res ;; let players_msg (score0, play0, score1, play1) = Printf.sprintf " Players 1 : score = %d, play = %s Player 2 : score = %d, play = %s " score0 (string_of_plays play0) score1 (string_of_plays play1) ;; (* == One player service function *) (* -- Random player *) let get_ranplay () = plays_of_int (Random.int 7) let print_ranplay msg = () (* -- Stdin (human) player *) let check_bound n m = if (m < 0) or (n < m) then failwith "Out of bound" else m ;; let rec read_bound_int_or_q n = let s = read_line() in if s = "q" then s else ( try check_bound n (int_of_string s); s with _ -> (print_string "Try again: "; read_bound_int_or_q n) ) ;; let get_humplay () = print_string "Your play: "; flush Pervasives.stdout; plays_of_string (read_bound_int_or_q 5) let print_humplay msg = writeln Pervasives.stdout msg let player (st, id, get_play, print_play) = let rec loop() = let play = get_play () in let s = string_of_plays play in debug_msg (Printf.sprintf"input %d = %s" id s); write_play st id play; debug_msg (Printf.sprintf "Player%d registred" id); let res = read_players st in print_play (players_msg res); match res with _, Play _, _, Play _ -> loop () | _ -> writeln Pervasives.stdout (Printf.sprintf"Exit player%d" id) in loop () (* == launch the two players *) let start () = let state = new_state () in Mutex.lock state.m; let th1 = Thread.create player (state, 0, get_ranplay, print_ranplay) in let th2 = Thread.create player (state, 1, get_humplay, print_humplay) in debug_msg (start_msg "1"); debug_msg (start_msg "2"); Mutex.unlock state.m; Thread.join th1; Thread.join th2 ;; Random.self_init (); start ()