diff options
Diffstat (limited to 'lib/gs/contribs/othello/othello.erl')
-rw-r--r-- | lib/gs/contribs/othello/othello.erl | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/lib/gs/contribs/othello/othello.erl b/lib/gs/contribs/othello/othello.erl new file mode 100644 index 0000000000..c66c9c2e79 --- /dev/null +++ b/lib/gs/contribs/othello/othello.erl @@ -0,0 +1,236 @@ +%% +%% %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. + + |