(*********************************************** game.ml - Rules of the game itself Copyright (C) 2001 Brock Wilcox [awwaiid@deathonastick.org] Released under the terms of the Artistic License See Artistic.txt for details HISTORY / NOTES 2001.10.02.21.29 - Fixed it. Now I'll start creating the primitives for Gp - Links in Gp now too, btw. 2001.09.29.13.22 - Well, I'm back here again. I'm creating a powerful GP engine which I am now tying this into. That means any of the GP stuff that was part of this project before is being dropped. - I note that though code-rot there is an error somewhere and not even two player mode (which is the only one I want now) works. So I will be fixing that :) 2001.04.07.22.53 - Split board.ml and piece.ml into seperate files - Renamed to game.ml - Split off human.ml too, which gets human input 2001.02.25.06.19 - do_move now returns () and raises error - Added rand_move and rand_piece 2001.01.29.04.49 - Tweaked the human input a bit - All rules implemented 2000.11.02.14.00 - Most rules implemented - Only needs winner routine 2000.10.27.10.35 - Created ***********************************************) (* The game exceptions *) exception Illegal_move exception Error of string exception Found exception Unfound (* Convert a single number into a location pair *) let int_to_loc n = let x = n mod 7 in let y = n / 7 in (x, y) (* Print a loc *) let print_loc (x,y) = print_char '('; print_int x; print_char ','; print_int y; print_char ')' (* Print a move *) let print_move (l1,l2) = print_loc l1; print_string " -> "; print_loc l2 (* Whats the distance between two locs? *) let distance (x1,y1) (x2,y2) = let x = abs (x1 - x2) in let y = abs (y1 - y2) in if x > y then x else y (* Is the location legal? (within the bounds of the board) *) let is_legal_loc (x,y) = (x >= 0) && (x < 7) && (y >= 0) && (y < 7) (* Is the move legal for a given board? *) let is_move_legal board (loc1,loc2) = (is_legal_loc loc1) && (is_legal_loc loc2) && (Board.empty_at board loc2) && (distance loc1 loc2 <= 2) (* Is the move legal for the piece given a board *) let is_move_legal_for piece board (loc1,loc2) = (*print_string "Is Move Legal For:\n"; Board.print board; print_newline(); *) ((Board.at board loc1) == piece) && (is_move_legal board (loc1,loc2)) (* Get a list of legal moves for a specific player *) let legal_moves_for player board = let movelist = ref [] in for x = 0 to 6 do for y = 0 to 6 do if (Board.at board (x,y) != Piece.Blank) && (Board.at board (x,y)) = player then for i = -2 to 2 do for j = -2 to 2 do if is_move_legal_for player board ((x,y),(x+i,y+j)) then movelist := ((x,y),(x+i,y+j)) :: !movelist; done; done; done; done; !movelist (* Get a list of legal moves for both players *) let list_legal_moves board = let movelist = ref [] in for x = 0 to 6 do for y = 0 to 6 do if (Board.at board (x,y)) != Piece.Blank then for i = -2 to 2 do for j = -2 to 2 do if is_move_legal board ((x,y),(x+i,y+j)) then begin Piece.print (Board.at board (x,y)); print_string ": "; print_move ((x,y),(x+i,y+j)); print_string "\n"; movelist := ((x,y),(x+i,y+j)) :: !movelist; end; done; done; done; done; !movelist (* Is there a legal move for a player on the board? *) (* This is the first time I've ever used exceptions as rules *) let is_legal_move_on_for p b = try for x = 0 to 6 do for y = 0 to 6 do if (Board.at b (x,y)) != Piece.Blank then for i = -2 to 2 do for j = -2 to 2 do if is_move_legal_for p b ((x,y),(x+i,y+j)) then raise Found done; done; done; done; raise Unfound with | Found -> true | Unfound -> false (* Does the board have a legal move at all? *) let is_legal_move_on b = try for x = 0 to 6 do for y = 0 to 6 do if (Board.at b (x,y)) = Piece.Blank then raise Found done; done; raise Unfound with | Found -> true | Unfound -> false (* Flip the neighbors *) let change_neighbors_to piece board (x,y) = let b = ref board in let opp = Piece.opposite piece in for i = -1 to 1 do for j = -1 to 1 do if (is_legal_loc (x+i,y+j)) && (Board.at !b (x+i,y+j) = opp) then b := Board.update !b (x+i,y+j) piece; done done; !b (* Do a move, return the new board *) (* Raise IllegalMove if anything is wrong *) let do_move piece board move = let b = ref board in let (loc1,loc2) = move in (*print_string "Move: "; print_move move; print_newline();*) if is_move_legal_for piece !b move then begin b := Board.update !b loc2 piece; if (distance loc1 loc2) = 2 then b := Board.update !b loc1 Piece.Blank; change_neighbors_to piece !b loc2 end else raise Illegal_move (* Initialize a board *) let init_board board = let b = ref board in b := Board.update !b (0,0) Piece.X; b := Board.update !b (6,6) Piece.X; b := Board.update !b (0,6) Piece.O; Board.update !b (6,0) Piece.O (* Print whos turn it is *) let print_turn p = print_string "Player "; Piece.print p; print_string "'s turn.\n" (* Get the current score for a player on a board *) let score_for player board = let score = ref 0 in for i=0 to 6 do for j=0 to 6 do if Board.at board (i,j) = player then score := !score + 1; done; done; !score (* End of game.ml *)