aboutsummaryrefslogtreecommitdiff
path: root/judge/guiplay.ml
blob: 50add3c6f2093146995864bfe359db2b9dc803dc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
open Core
open Graphics
open Unix
open Protocol

module A (G : GAME) : sig

  val run : unit -> unit

end = struct

  exception Unexpected of msg

  open G_util

  (* Init/Close *)
  let gui_init () =
    open_graph " 800x600";
    set_font "-misc-fixed-bold-r-normal--15-120-90--c-90-iso8859-1";
    auto_synchronize false;
    display_mode false;
    remember_mode true;
    fullscreen_msg "Starting up..."

  let gui_close () =
    close_graph ()

  (* The functions *)

  let dg t g pnx =
    clear_graph();
    text3 1 black t;
    hl();
    G.display_game g pnx;
    synchronize()

  let display_result r (p1n, p2n) = 
    let s = match r with
      | Won P1 -> p1n ^ " won"
      | Won P2 -> p2n ^ " won"
      | Tie -> "Tie"
      | Eliminated P1 -> p1n ^ " eliminated"
      | Eliminated P2 -> p2n ^ " eliminated"
      | _ -> assert false
    in
    fullscreen_msg (s ^ ". Press a key to exit.");
    ignore @@ read_key()

  let fwd ff g (send, recv) (p1n, p2n) =
    match G.s g with
    | TurnOf _ -> ff g (send, recv) (p1n, p2n)
    | s ->
      display_result s (p1n, p2n);
      send (match s with
        | Tie -> Tie
        | Won P1 when p1n = "AI" -> YouWin
        | Won P2 when p2n = "AI" -> YouWin
        | Won _ ->  YouLose
        | _ -> Eliminated);
      match (recv ()) with
        | FairEnough -> ()
        | x -> raise (Unexpected x)

  let rec human_turn g (send, recv) pnx =
    dg "Your turn !" g pnx;
    let rec x pmc =
      let st = wait_next_event [Button_down; Button_up; Mouse_motion; Key_pressed] in
      let act = G.gui_act_at g (st.mouse_x, st.mouse_y) in
      let g', ok = try G.play g act, true with _ -> g, false in
      let ok = ok && (match G.s g' with Eliminated _ -> false | _ -> true) in
      dg "Your turn !" (if ok then g' else g) pnx;
      if st.keypressed && st.key = 'q' then begin
        send (YouWin);
        fullscreen_msg "You abandon! Coward!"
      end else
        if pmc && not st.button && ok then begin
          send (Play act);
          fwd ai_turn g' (send, recv) pnx
        end else
          x st.button
    in x false
    
  and ai_turn g (send, recv) pnx =
    dg "AI's turn..." g pnx;
    send (YourTurn 30.0);
    match recv() with
      | Play x ->
        let g' = G.play g x in
        send OK;
        fwd human_turn g' (send, recv) pnx
      | x -> raise (Unexpected x)

  (* Arg parsing && Initialization *)

  let human_begin = ref false

  let start_proc player_dir =
    let b = Filename.concat player_dir "player" in
    let st = Unix.stat b in
    if not ((st.st_kind = S_REG || st.st_kind = S_LNK)
            && (st.st_perm land 0o100 <> 0)) then
    begin
      Format.eprintf "Could not find player binary in %s@." player_dir;
      exit 1
    end;
    let (ff_i, o) = pipe () in
    let (i, ff_o) = pipe () in
    let pid = fork() in
    if pid = 0 then begin
      chdir player_dir;
      dup2 ff_i stdin;
      dup2 ff_o stdout;
      execvp b [| b |];
    end;
    Format.eprintf "Started IA process, pid %d@." pid;
    i, o, pid


  let run () =
    let player_dir = ref "." in
    let args = [
      "-h", Arg.Set human_begin, "Human begins (default: AI begins";
    ] in
    Arg.parse args (fun s -> player_dir := s)
      "Usage: xx_guiplay [<option> ...] [<player directory>]";
    let player_dir =
      if Filename.is_relative !player_dir
        then Filename.concat (Unix.getcwd()) !player_dir
        else !player_dir
    in
    gui_init();
    let i, o, pid = start_proc player_dir in
    let ic = in_channel_of_descr i in
    let oc = out_channel_of_descr o in
    let send m = output_string oc (encode m ^ "\n"); flush oc in
    let recv () = decode (input_line ic) in
    send (Hello G.id);
    let pnc = if !human_begin then ("human", "AI") else ("AI", "human") in
    begin try
        match recv () with
        | Hello x when x = G.id ->
          if !human_begin
            then human_turn G.new_game (send, recv) pnc
            else ai_turn G.new_game (send, recv) pnc
        | x -> raise (Unexpected x)
      with
        | Unexpected x ->
          Format.eprintf "Unexpected message: %s@." (encode x)
    end;
    Unix.kill pid Sys.sigterm;
    gui_close()

end