aboutsummaryrefslogtreecommitdiffstats
path: root/lib/gs/contribs/othello/othello_adt.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gs/contribs/othello/othello_adt.erl')
-rw-r--r--lib/gs/contribs/othello/othello_adt.erl539
1 files changed, 539 insertions, 0 deletions
diff --git a/lib/gs/contribs/othello/othello_adt.erl b/lib/gs/contribs/othello/othello_adt.erl
new file mode 100644
index 0000000000..d1d3ec950b
--- /dev/null
+++ b/lib/gs/contribs/othello/othello_adt.erl
@@ -0,0 +1,539 @@
+%%
+%% %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_adt).
+-compile(export_all).
+%%-------------------------------------------------------
+%% Use three main states for the strategy:
+%%
+%% BeginPlay: Stay in the inner square as long as possible.
+%% Use the possible_draws/3.
+%%
+%% MiddlePlay: Try to choose stable markers (?)
+%% Use stable/3
+%%
+%% EndPlay: Try to flip as many markers as possible
+%%
+%% The transition from Begin to Middle is obvious. From Middle
+%% to End however, is can be discussed.
+%%-------------------------------------------------------
+
+test(N,B) ->
+ X=new(B),
+ statistics(wall_clock),
+ test0(N,X),
+ {_,T} = statistics(wall_clock),
+ {time_was,T/N}.
+
+
+test0(0,_) -> true;
+test0(N,X) ->
+ possible_draws(black,X,begin_play),
+ test0(N-1,X).
+
+%%-------------------------------------------------------
+%% new/1 - returns a new board
+%%
+%% Uses a tuple for storing the board
+%%-------------------------------------------------------
+
+new(B) ->
+ Board = mk_board(B),
+ {ordsets:from_list([18,19,20,21,26,29,34,37,42,43,44,45]),Board}.
+
+mk_board(t) ->
+ Tup = list_to_tuple(gen_list(64,grey)),
+ Tup1 = setelement(28+1, Tup, white),
+ Tup2 = setelement(35+1, Tup1, white),
+ Tup3 = setelement(27+1, Tup2, black),
+ gen_score_board(),
+ setelement(36+1, Tup3, black).
+
+gen_list(0,_) -> [];
+gen_list(I,Def) -> [Def|gen_list(I-1,Def)].
+
+gen_score_board() -> put(score,list_to_tuple(gen_list(64,0))).
+
+%%-------------------------------------------------------
+%% pos(Col,Row) - returns a position describing column
+%% and row.
+%% Col and Row have the range 1 - 8.
+%%-------------------------------------------------------
+
+pos(Col,Row) -> ((Row - 1) bsl 3) + (Col - 1).
+
+%%-------------------------------------------------------
+%% col(Pos) - returns the column of the Pos position
+%%-------------------------------------------------------
+
+col(Pos) -> (Pos band 7) + 1.
+
+%%-------------------------------------------------------
+%% row(Pos) - returns the row of the Pos position
+%%-------------------------------------------------------
+
+row(Pos) -> (Pos bsr 3) + 1.
+
+%%-------------------------------------------------------
+%% is_draw(Pos,Colour,Board) - returns true if Pos is a
+%% correct draw.
+%%-------------------------------------------------------
+
+is_draw(Pos,Colour,{Bset,Board}) ->
+ case ordsets:is_element(Pos,Bset) of
+ true ->
+ case catch is_good(Colour,Pos,Board) of
+ true ->
+ true;
+ _ ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
+%%-------------------------------------------------------
+%% set(Pos,Colour,Board) - returns an updated board
+%%-------------------------------------------------------
+
+set(Pos,Colour,{Bset,Board}) ->
+ case ordsets:is_element(Pos,Bset) of
+ true ->
+ NewBoard = setelement(Pos+1,Board,Colour),
+ Empty = empty_neighbour(Pos,NewBoard),
+ NewBset = ordsets:union(Empty,ordsets:del_element(Pos,Bset)),
+ turn(Colour,Pos,{NewBset,NewBoard});
+ _ ->
+ {error,invalid_position}
+ end.
+
+empty_neighbour(Pos,Board) ->
+ ordsets:from_list(empty_neighbour(Pos,Board,deltas())).
+
+empty_neighbour(_,_,[]) -> [];
+empty_neighbour(Pos,Board,[H|T]) ->
+ case is_empty(Pos+H,dir(Pos,H),Board) of
+ true -> [Pos+H|empty_neighbour(Pos,Board,T)];
+ _ -> empty_neighbour(Pos,Board,T)
+ end.
+
+is_empty(_,false,_) -> false;
+is_empty(X,_,_Board) when X<0 -> false;
+is_empty(X,_,_Board) when X>63 -> false;
+is_empty(X,_,Board) ->
+ case element(X+1,Board) of
+ grey -> true; % Empty
+ _ -> false
+ end.
+
+%%-------------------------------------------------------
+%% get(Pos,Board) - returns the contents in Pos
+%%-------------------------------------------------------
+
+get(Pos,{_Bset,Board}) -> element(Pos+1,Board).
+
+%%-------------------------------------------------------
+%% pieces(Colour,Board) - returns the number of Colour
+%% pieces.
+%%-------------------------------------------------------
+
+pieces(Colour,{_Bset,Board}) ->
+ pieces(Colour,Board,0,0).
+
+pieces(Colour,Board,Pos,Count) when Pos < 64 ->
+ case element(Pos+1,Board) of
+ Colour ->
+ pieces(Colour,Board,Pos+1,Count+1);
+ _ ->
+ pieces(Colour,Board,Pos+1,Count)
+ end;
+pieces(_,_,_,Count) ->
+ Count.
+
+%%-------------------------------------------------------
+%% possible_draws(Colour, Board, State)
+%%
+%% Returns a list of possible draws regarding the current
+%% strategy state.
+%%-------------------------------------------------------
+
+possible_draws(Colour,{Bset,Board},begin_play) ->
+ Dset = ordsets:intersection(Bset,inner_square()),
+ possible_draws_0(Colour,Dset,Board);
+possible_draws(Colour,{Bset,Board},_) ->
+ possible_draws_0(Colour,Bset,Board).
+
+possible_draws(Colour,{Bset,Board}) ->
+ possible_draws_0(Colour,Bset,Board).
+
+possible_draws_0(_,[],_) -> [];
+possible_draws_0(Colour,[H|T],Board) ->
+ case catch is_good(Colour,H,Board) of
+ true -> [H|possible_draws_0(Colour,T,Board)];
+ false -> possible_draws_0(Colour,T,Board)
+ end.
+
+
+%%-------------------------------------------------------
+%% evaluate_board(Colour,Board) - returns the value of
+%% the board from Colours
+%% point of view.
+%%-------------------------------------------------------
+
+evaluate_board(Colour,{_Bset,Board}) ->
+ Score = get(score), % Initialized (zeroed) score board !!
+ Colour1 = swap(Colour),
+ Score1 = eval_board(Colour,Colour1,Score,Board,0),
+ Score2 = cnt_corner(0,Score1,Board,Colour,Colour1),
+ Score3 = cnt_corner(7,Score2,Board,Colour,Colour1),
+ Score4 = cnt_corner(56,Score3,Board,Colour,Colour1),
+ Score5 = cnt_corner(63,Score4,Board,Colour,Colour1),
+ count(Score5,0).
+% A = count(Score5,0),
+% io:format('Score = ~w~n',[A]),
+% A.
+
+eval_board(MyCol,OtCol,Score,Board,Pos) when Pos < 64 ->
+ case element(Pos+1,Board) of
+ MyCol ->
+ Score1 = setelement(Pos+1,Score,score(Pos)),
+ eval_board(MyCol,OtCol,Score1,Board,Pos+1);
+ OtCol ->
+ Score1 = setelement(Pos+1,Score,-score(Pos)),
+ eval_board(MyCol,OtCol,Score1,Board,Pos+1);
+ _ ->
+ eval_board(MyCol,OtCol,Score,Board,Pos+1)
+ end;
+eval_board(_,_,Score,_,_) ->
+ Score.
+
+cnt_corner(Corner,Score,Board,MyCol,OtCol) ->
+ case element(Corner+1,Board) of
+ MyCol ->
+ cnt_corn(Corner,setelement(Corner+1,Score,50),
+ Board,50,MyCol);
+ OtCol ->
+ cnt_corn(Corner,setelement(Corner+1,Score,-50),
+ Board,-50,OtCol);
+ _ ->
+ Score
+ end.
+
+cnt_corn(0,Score,Board,Value,Colour) ->
+ Score1 = cnt_corn(0,1,8,Score,Board,Value,Colour),
+ cnt_corn(0,8,1,Score1,Board,Value,Colour);
+cnt_corn(7,Score,Board,Value,Colour) ->
+ Score1 = cnt_corn(7,-1,8,Score,Board,Value,Colour),
+ cnt_corn(7,8,-1,Score1,Board,Value,Colour);
+cnt_corn(56,Score,Board,Value,Colour) ->
+ Score1 = cnt_corn(56,1,-8,Score,Board,Value,Colour),
+ cnt_corn(56,-8,1,Score1,Board,Value,Colour);
+cnt_corn(63,Score,Board,Value,Colour) ->
+ Score1 = cnt_corn(63,-1,-8,Score,Board,Value,Colour),
+ cnt_corn(63,-8,-1,Score1,Board,Value,Colour).
+
+cnt_corn(Pos,Dir,LineDir,Score,Board,Value,Colour) ->
+ case dir(Pos,Dir) of
+ Dir ->
+ NextEdge = Pos+Dir,
+ case element(NextEdge+1,Board) of
+ Colour ->
+ Score1 = setelement(NextEdge+1,Score,Value),
+ Score2 = cnt_line(NextEdge,LineDir,Score1,Board,
+ Colour,Value),
+ cnt_corn(NextEdge,Dir,LineDir,Score2,Board,Value,Colour);
+ _ ->
+ Score
+ end;
+ _ ->
+ Score
+ end.
+
+cnt_line(Pos,Dir,Score,Board,Colour,Value) ->
+ case dir(Pos,Dir) of
+ Dir ->
+ OnLinePos = Pos+Dir,
+ case element(OnLinePos+1,Board) of
+ Colour ->
+ Score1 = setelement(OnLinePos+1,Score,Value),
+ cnt_line(OnLinePos,Dir,Score1,Board,Colour,Value);
+ _ ->
+ Score
+ end;
+ _ ->
+ Score
+ end.
+
+count(Score,Pos) when Pos < 64 ->
+ element(Pos+1,Score) + count(Score,Pos+1);
+count(_,_) ->
+ 0.
+
+swap(white) -> black;
+swap(black) -> white.
+
+%%-------------------------------------------------------
+%% stable(Colour,Pos,Board) - returns a value 0-8
+%%
+%% A high value is regarded as more stable than a lower one.
+%% The stability means how many "friendly" neighbours there
+%% are, i.e markers of the same colour. Neighbours positions
+%% outside the board are regarded as friendly.
+%%-------------------------------------------------------
+
+stable(Colour,Pos,{_,Board}) ->
+ stable(deltas(),Colour,Pos,Board).
+
+stable([],_,_,_) -> 0;
+stable([H|T],Colour,Pos,Board) ->
+ stable_val(Colour,Pos,H,Board) + stable(T,Colour,Pos,Board).
+
+stable_val(_,H,D,_) when H+D<0 -> 1;
+stable_val(_,H,D,_) when H+D>63 -> 1;
+stable_val(black,H,D,Board) ->
+ case element((H+D)+1,Board) of
+ black -> 1;
+ _ -> 0
+ end;
+stable_val(white,H,D,Board) ->
+ case element((H+D)+1,Board) of
+ white -> 1;
+ _ -> 0
+ end.
+
+%%-------------------------------------------------------
+%% diff(Board,OldBoard) - return a list of the positions
+%% with changed pieces.
+%% [{Pos1,Colour1},...]
+%%-------------------------------------------------------
+
+diff(Board,OldBoard) -> diff(0,Board,OldBoard).
+
+diff(Pos,Board,OldBoard) when Pos < 64 ->
+ OldP = get(Pos,OldBoard),
+ case get(Pos,Board) of
+ OldP ->
+ diff(Pos+1,Board,OldBoard);
+ NewP ->
+ [{Pos,NewP}|diff(Pos+1,Board,OldBoard)]
+ end;
+diff(_,_,_) ->
+ [].
+
+%%-------------------------------------------------------
+%% all_pos(Board) - return a list of the positions colour.
+%% [{Pos1,Colour1},...]
+%%-------------------------------------------------------
+
+all_pos(Board) -> all_pos(0,Board).
+
+all_pos(Pos,Board) when Pos < 64 ->
+ [{Pos,get(Pos,Board)}|all_pos(Pos+1,Board)];
+all_pos(_,_) ->
+ [].
+
+%%-------------------------------------------------------
+%% Internal stuff
+%%-------------------------------------------------------
+
+deltas() -> [9,8,7,1,-1,-7,-8,-9].
+
+inner_square() ->
+ [18,19,20,21,26,27,28,29,34,35,36,37,42,43,44,45]. % Is already an ordset
+ % Save list traversing.
+% ordsets:list_to_set([18,19,20,21,26,27,28,29,34,35,36,37,42,43,44,45]).
+
+inv(black) -> white;
+inv(white) -> black.
+
+is_good(Colour,H,Board) ->
+ is_good_0(Colour,H,dir(H,-9),Board),
+ is_good_0(Colour,H,dir(H,-8),Board),
+ is_good_0(Colour,H,dir(H,-7),Board),
+ is_good_0(Colour,H,dir(H,-1),Board),
+ is_good_0(Colour,H,dir(H,1),Board),
+ is_good_0(Colour,H,dir(H,7),Board),
+ is_good_0(Colour,H,dir(H,8),Board),
+ is_good_0(Colour,H,dir(H,9),Board),
+ false.
+
+is_good_0(_,_,false,_) -> false;
+is_good_0(_,H,D,_) when integer(H), integer(D), H+D<0 -> false;
+is_good_0(_,H,D,_) when integer(H), integer(D), H+D>63 -> false;
+is_good_0(black,H,D,Board) when integer(H), integer(D) ->
+ case element((H+D)+1,Board) of
+ white -> is_good_1(black,H+D,dir(H+D,D),Board);
+ _ -> false
+ end;
+is_good_0(white,H,D,Board) when integer(H), integer(D) ->
+ case element((H+D)+1,Board) of
+ black -> is_good_1(white,H+D,dir(H+D,D),Board);
+ _ -> false
+ end.
+
+is_good_1(_,_,false,_) -> false;
+is_good_1(_,H,D,_) when integer(H), integer(D), H+D<0 -> false;
+is_good_1(_,H,D,_) when integer(H), integer(D), H+D>63 -> false;
+is_good_1(black,H,D,Board) when integer(H), integer(D) ->
+ case element((H+D)+1,Board) of
+ white -> is_good_1(black,H+D,dir(H+D,D),Board);
+ black -> throw(true);
+ _ -> false
+ end;
+is_good_1(white,H,D,Board) when integer(H), integer(D) ->
+ case element((H+D)+1,Board) of
+ black -> is_good_1(white,H+D,dir(H+D,D),Board);
+ white -> throw(true);
+ _ -> false
+ end.
+
+%%-------------------------------------------------------
+%% turn(Colour,Draw,Board) - returns an updated board
+%% turn all possible pieces
+%% on the board
+%% Neighbours are not changed !!
+%%-------------------------------------------------------
+
+turn(Colour,Draw,{Bset,Board}) ->
+ {Bset,turn(Colour,Draw,-9,
+ turn(Colour,Draw,-8,
+ turn(Colour,Draw,-7,
+ turn(Colour,Draw,-1,
+ turn(Colour,Draw,1,
+ turn(Colour,Draw,7,
+ turn(Colour,Draw,8,
+ turn(Colour,Draw,9,Board))))))))}.
+
+turn(Colour,H,D,Board) ->
+ case catch is_good_0(Colour,H,dir(H,D),Board) of
+ true ->
+ turn_0(Colour,H,D,Board);
+ false ->
+ Board
+ end.
+
+turn_0(_,H,D,B) when integer(H), integer(D), H+D<0 -> B;
+turn_0(_,H,D,B) when integer(H), integer(D), H+D>63 -> B;
+turn_0(black,H,D,Board) when integer(H), integer(D) ->
+ E = H+D,
+ case element(E+1,Board) of
+ white -> turn_0(black,H+D,D,swap(black,E,Board));
+ _ -> Board
+ end;
+turn_0(white,H,D,Board) when integer(H), integer(D) ->
+ E = H+D,
+ case element(E+1,Board) of
+ black -> turn_0(white,H+D,D,swap(white,E,Board));
+ _ -> Board
+ end.
+
+%%-------------------------------------------------------
+%% swap(Colour,Pos,Board) - returns an updated board
+%% turn a piece on the board
+%% Neighbours are not changed !!
+%%-------------------------------------------------------
+
+swap(Colour,Pos,Board) when integer(Pos) ->
+ setelement(Pos+1,Board,Colour).
+
+score(Pos) -> score1({col(Pos),row(Pos)}).
+
+score1({Column,1}) when Column >= 3, Column =< 6 -> 20;
+score1({Column,8}) when Column >= 3, Column =< 6 -> 20;
+score1({1,Line}) when Line >= 3, Line =< 6 -> 20;
+score1({8,Line}) when Line >= 3, Line =< 6 -> 20;
+score1({Column,2}) when Column >= 3, Column =< 6 -> -7;
+score1({Column,7}) when Column >= 3, Column =< 6 -> -7;
+score1({2,Line}) when Line >= 3, Line =< 6 -> -7;
+score1({7,Line}) when Line >= 3, Line =< 6 -> -7;
+score1({Column,Line}) when Column >= 3, Column =< 6,
+ Line >= 3, Line =< 6 -> 1;
+score1({1,1}) -> 100;
+score1({1,8}) -> 100;
+score1({8,1}) -> 100;
+score1({8,8}) -> 100;
+score1({2,1}) -> -30;
+score1({7,1}) -> -30;
+score1({1,2}) -> -30;
+score1({8,2}) -> -30;
+score1({1,7}) -> -30;
+score1({8,7}) -> -30;
+score1({2,8}) -> -30;
+score1({7,8}) -> -30;
+score1({2,2}) -> -50;
+score1({7,2}) -> -50;
+score1({2,7}) -> -50;
+score1({7,7}) -> -50.
+
+%%-------------------------------------------------------
+%% dir(Pos,Dir) - return Dir if allowed direction at Pos.
+%% else return false.
+%%-------------------------------------------------------
+
+dir(0,1) -> 1; % {1,1}
+dir(0,8) -> 8;
+dir(0,9) -> 9;
+dir(0,_) -> false;
+
+dir(7,-1) -> -1; % {8,1}
+dir(7,7) -> 7;
+dir(7,8) -> 8;
+dir(7,_) -> false;
+
+dir(56,-8) -> -8; % {1,8}
+dir(56,-7) -> -7;
+dir(56,1) -> 1;
+dir(56,_) -> false;
+
+dir(63,-9) -> -9; % {8,8}
+dir(63,-8) -> -8;
+dir(63,-1) -> -1;
+dir(63,_) -> false;
+
+dir(Pos,-1) when (Pos bsr 3) == 0 -> -1; % {_,1}
+dir(Pos,1) when (Pos bsr 3) == 0 -> 1;
+dir(Pos,7) when (Pos bsr 3) == 0 -> 7;
+dir(Pos,8) when (Pos bsr 3) == 0 -> 8;
+dir(Pos,9) when (Pos bsr 3) == 0 -> 9;
+dir(Pos,_) when (Pos bsr 3) == 0 -> false;
+
+dir(Pos,-9) when (Pos bsr 3) == 7 -> -9; % {_,8}
+dir(Pos,-8) when (Pos bsr 3) == 7 -> -8;
+dir(Pos,-7) when (Pos bsr 3) == 7 -> -7;
+dir(Pos,-1) when (Pos bsr 3) == 7 -> -1;
+dir(Pos,1) when (Pos bsr 3) == 7 -> 1;
+dir(Pos,_) when (Pos bsr 3) == 7 -> false;
+
+dir(Pos,-8) when (Pos band 7) == 0 -> -8; % {1,_}
+dir(Pos,-7) when (Pos band 7) == 0 -> -7;
+dir(Pos,1) when (Pos band 7) == 0 -> 1;
+dir(Pos,8) when (Pos band 7) == 0 -> 8;
+dir(Pos,9) when (Pos band 7) == 0 -> 9;
+dir(Pos,_) when (Pos band 7) == 0 -> false;
+
+dir(Pos,-9) when (Pos band 7) == 7 -> -9; % {8,_}
+dir(Pos,-8) when (Pos band 7) == 7 -> -8;
+dir(Pos,-1) when (Pos band 7) == 7 -> -1;
+dir(Pos,7) when (Pos band 7) == 7 -> 7;
+dir(Pos,8) when (Pos band 7) == 7 -> 8;
+dir(Pos,_) when (Pos band 7) == 7 -> false;
+
+dir(_Pos,Dir) -> Dir.
+