let main () =
  let pieceName = function
      Board.Black -> "BLACK"
    | Board.White -> "WHITE"
  and depth = ref 5
  and midDepth = ref 0
  and endDepth = ref 0
  and blackPlayer = ref Othello.humanPlayer
  and whitePlayer = ref (Machine.machinePlayer 5 9 5)
  and iosName = ref "helga"
  and iosPass = ref "piggly"
  and opponent = ref ""
  and waitPlay = ref false		(* wait for a challenge *)
  and playRand = ref false
  and blackPlayerName = ref "HUMAN"
  and whitePlayerName = ref "MACHINE"
  and iosHost = ref "external.nj.nec.com"
  and iosPort = ref 5000
  and rated = ref false
  and printBoards = ref true
  and otherargs = ref [] in
  
  let playerFun name =
    match (String.uppercase name) with
      "RANDOM" -> Othello.randomPlayer
    | "HUMAN" -> Othello.humanPlayer
    | "MACHINE" ->
 	if !endDepth = 0 then endDepth := 2 * !depth;
	if !midDepth = 0 then midDepth := !endDepth + 4;
	(Machine.machinePlayer !depth !midDepth !endDepth)
    | "IOS" -> IosPlay.iosPlayer
    | _ -> raise (Arg.Bad ("Unknown player function: " ^ name)) in
  
  let setDepth d = depth := d
  and setMidDepth d = midDepth := d
  and setEndDepth d = endDepth := d
  and setBlack name = blackPlayerName := String.uppercase name
  and setWhite name = whitePlayerName := String.uppercase name
  and setName name = iosName := name
  and setPass pass = iosPass := pass
  and setPlay name = opponent := name
  and setHost name = iosHost := name
  and setPort port = iosPort := port in
  
  let spec = [ "-depth", Arg.Int setDepth, "Search depth for machine player";
	       "-midDepth", Arg.Int setMidDepth, "Midgame search depth";
	       "-endDepth", Arg.Int setEndDepth, "Endgame search depth";
	       "-black", Arg.String setBlack, "Black player function";
	       "-white", Arg.String setWhite, "White player function";
	       "-name", Arg.String setName, "Set IOS login name";
	       "-pass", Arg.String setPass, "IOS password";
	       "-play", Arg.String setPlay, "Who to challenge on IOS";
	       "-rand", Arg.Set playRand, "Challenge a random player";
	       "-wait", Arg.Set waitPlay, "Wait for someone to challenge me";
	       "-host", Arg.String setHost, "IOS hostname";
	       "-port", Arg.Int setPort, "IOS port";
	       "-print", Arg.Set printBoards, "Print board after each move";
	       "-noprint", Arg.Clear printBoards, "Don't print boards";
	       "-rated", Arg.Set rated, "Play rated game";
	       "-unrated", Arg.Clear rated, "Play unrated game"
	     ] in
  
  Arg.parse spec (function arg -> otherargs := !otherargs @ [arg])
    "Valid players are RANDOM, HUMAN, IOS, and MACHINE";

  blackPlayer := playerFun !blackPlayerName;
  whitePlayer := playerFun !whitePlayerName;

  let initBoard = ref (Board.initial()) in

  if !whitePlayerName = "IOS" || !blackPlayerName = "IOS" then begin
    IosPlay.init !iosHost !iosPort !iosName !iosPass !printBoards;
    printBoards := false;
    let my_color = ref Board.Black in
    if !opponent <> "" then
      let b, c = IosPlay.challengeSomeone !opponent !rated 15 in
      initBoard := b; my_color := c
    else if !playRand then
      let b, c = IosPlay.challengeAnyone !rated 15 in
      initBoard := b; my_color := c
    else if !waitPlay then
      let b, c = IosPlay.waitForMatch 15 in
      initBoard := b; my_color := c
    else begin
      print_string "You need to specify who to play against.\n";
      Arg.usage spec "Valid players are RANDOM, HUMAN, IOS, and MACHINE";
      exit 1
    end;
    if !my_color = Board.Black then begin (* then white should play IOS *)
      if !blackPlayerName = "IOS" then begin
	blackPlayer := playerFun !whitePlayerName;
	whitePlayer := playerFun !blackPlayerName
      end
    end else begin (* else black should play IOS *)
      if !whitePlayerName = "IOS" then begin
	whitePlayer := playerFun !blackPlayerName;
	blackPlayer := playerFun !whitePlayerName
      end
    end
  end;
      
  Random.init (int_of_float (Unix.time()));
  match (Othello.play !blackPlayer !whitePlayer !initBoard
	   !printBoards) with
    Othello.Winner (p, b, w) ->
      Printf.printf "%s won: (%d, %d).\n" (pieceName p) b w
  | Othello.Tie (b, w) -> Printf.printf "Tie game: (%d, %d).\n" b w
  | Othello.Resign (p, b, w) ->
      Printf.printf "%s resigned: (%d, %d).\n" (pieceName p) b w;;
 	
try      
  main ()
with Othello.Illegal_move(who, move) ->
  Printf.printf "Player %s made illegal move %s\n"
    (Board.string_of_piece who) (Board.string_of_move move)
