%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1996-2009. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(othello). -export([start/0,new_game/4,start1/5]). %%---------------------------------------------------------------------- %% The Othello program now uses the gs graphical package instead of the %% pxw package. See module othello_board for details %% %%---------------------------------------------------------------------- start() -> othello_board:start(). new_game(Computer,Player,Depth,Init) -> spawn_link(othello,start1,[self(),Computer,Player,Depth,Init]). start1(Win,Computer,Player,Depth,Init) -> Board = othello_adt:new(t), random:seed(), init_display(Board,Win,Init), play(Computer,Player,Board,Depth,Win,1). play(Computer,Player,Board,Depth,Win,NoDs) -> tell_win(Win,Computer,Player), case catch continue(Player,Board) of {game_over,Result} -> game_over(Board,Player,Result,Win); {omit_draw,Player} -> omit(Player,Win), play(Computer,swap(Player),Board,Depth,Win,NoDs); ok -> Draw = choose_draw(Computer,Player,Board,Depth,Win,NoDs), Win ! {self(),draw,Draw}, Board1 = othello_adt:set(Draw,Player,Board), display(Board1,Board,Win), play(Computer,swap(Player),Board1,Depth,Win,NoDs+1) end. continue(Player,Board) -> Draws = game_over(Player,Board), not_allowed(Draws,Player), ok. choose_draw(Computer,Computer,Board,Depth,_Win,NoDs) -> % Depth > 0 !! {Draw,_Value} = alpha_beta(Depth,Board,-11000,11000,Computer,NoDs), % io:format('Choosen draw is {~w,~w} : (~w)~n', % [othello_adt:col(Draw),othello_adt:row(Draw),Value]), % io:format('=====================~n',[]), Draw; choose_draw(Computer,Player,Board,Depth,Win,NoDs) -> receive {Win,position,Draw} -> flush(Win), case othello_adt:is_draw(Draw,Player,Board) of false -> Win ! {self(),illegal_draw,Draw}, choose_draw(Computer,Player,Board,Depth,Win,NoDs); true -> Draw end end. flush(Win) -> receive {Win,position,_} -> flush(Win) after 1 -> true end. tell_win(Win,Computer,Player) -> Win ! {self(),player,Computer,Player}, receive {Win,go_on_play} -> true end. alpha_beta(0,Board,_,_,Player,_) -> {-1,othello_adt:evaluate_board(Player,Board)}; alpha_beta(Depth,Board,Alpha,Beta,Player,NoDs) -> case compute(Player,Board,NoDs) of [] -> Player1 = swap(Player), case compute(Player1,Board,NoDs) of [] -> dead_lock(Board,Player); PosDraws1 -> choose(PosDraws1,Board,Depth-1,-Beta,-Alpha,-1, Player1,NoDs) end; PosDraws -> choose(PosDraws,Board,Depth-1,-Beta,-Alpha,-1,Player,NoDs) % A = choose(PosDraws,Board,Depth-1,-Beta,-Alpha,-1,Player,NoDs), % io:format('Alpha-Beta (~w) ==> ~w~n',[Depth,A]), % A end. choose([Draw|Draws],Board,Depth,Alpha,Beta,Record,Player,NoDs) -> Player1 = swap(Player), Board1 = othello_adt:set(Draw,Player,Board), % io:format('Alpha <~w> Beta <~w> ~n',[Alpha,Beta]), {_,Value} = alpha_beta(Depth,Board1,Alpha,Beta,Player1,NoDs+1), Value1 = -Value, cutoff(Draw,Value1,Depth,Alpha,Beta,Draws,Board,Record,Player,NoDs); choose([],_,_,Alpha,_,Draw,_,_) -> {Draw,Alpha}. cutoff(Draw,Value,_,_,Beta,_,_,_,_,_) when Value >= Beta -> {Draw,Value}; cutoff(Draw,Value,Depth,Alpha,Beta,Draws,Board,_,Player,NoDs) when Alpha < Value, Value < Beta -> choose(Draws,Board,Depth,Value,Beta,Draw,Player,NoDs); cutoff(Draw,Value,Depth,Alpha,Beta,Draws,Board,Record,Player,NoDs) when Value == Alpha, NoDs < 13 -> choose(Draws,Board,Depth,Alpha,Beta,random_choice(Draw,Record), Player,NoDs); cutoff(_Draw,Value,Depth,Alpha,Beta,Draws,Board,Record,Player,NoDs) when Value =< Alpha -> choose(Draws,Board,Depth,Alpha,Beta,Record,Player,NoDs). compute(Player,Board,NoOfDraws) when NoOfDraws < 13 -> case othello_adt:possible_draws(Player,Board,begin_play) of [] -> othello_adt:possible_draws(Player,Board,playing); Draws -> Draws end; compute(Player,Board,_) -> othello_adt:possible_draws(Player,Board,playing). %%---------------------------------------------------------- %% Randomly choose between two draws with the same value. %%---------------------------------------------------------- random_choice(Draw,Draw1) -> case random:uniform(2) of 1 -> Draw; 2 -> Draw1 end. dead_lock(Board,Player) -> case win_or_loose(Board,Player) of 0 -> {-1,0}; Value when Value > 0 -> {-1,10000}; _ -> {-1,-10000} end. win_or_loose(Board,Player) -> Player1 = swap(Player), othello_adt:pieces(Player,Board) - othello_adt:pieces(Player1,Board). game_over(Player,Board) -> case othello_adt:possible_draws(Player,Board,playing) of [] -> Player1 = swap(Player), case othello_adt:possible_draws(Player1,Board,playing) of [] -> throw({game_over,{{Player,othello_adt:pieces(Player,Board)}, {Player1,othello_adt:pieces(Player1,Board)}}}); _ -> [] % Player`s Draws !! end; Draws -> Draws end. game_over(_Board,_Player,Result,Win) -> Win ! {self(),game_over,white_res(Result),black_res(Result)}. white_res({{white,Res},_}) -> Res; white_res({_,{white,Res}}) -> Res. black_res({{black,Res},_}) -> Res; black_res({_,{black,Res}}) -> Res. not_allowed([],Player) -> throw({omit_draw, Player}); not_allowed(_,_Player) -> ok. omit(Player,Win) -> Win ! {self(),omit_draw,Player}, receive {Win,continue} -> ok end. init_display(_Board,_Win,first_time) -> true; init_display(Board,Win,_) -> display(Board,Win). display(Board,Win) -> All = othello_adt:all_pos(Board), display1(All,Win), Win ! {self(),score,othello_adt:pieces(white,Board), othello_adt:pieces(black,Board)}. display(Board,OldB,Win) -> Diff = othello_adt:diff(Board,OldB), display1(Diff,Win), Win ! {self(),score,othello_adt:pieces(white,Board), othello_adt:pieces(black,Board)}. display1([{Pos,Colour}|Diff],Win) -> Win ! {self(),new_mark,Pos,Colour}, display1(Diff,Win); display1(_,_) -> true. swap(white) -> black; swap(black) -> white.