aboutsummaryrefslogtreecommitdiffstats
path: root/lib/gs/contribs/othello
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/gs/contribs/othello
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/gs/contribs/othello')
-rw-r--r--lib/gs/contribs/othello/Makefile100
-rw-r--r--lib/gs/contribs/othello/othello.erl236
-rw-r--r--lib/gs/contribs/othello/othello.gifbin0 -> 148 bytes
-rw-r--r--lib/gs/contribs/othello/othello.tool6
-rw-r--r--lib/gs/contribs/othello/othello_adt.erl539
-rw-r--r--lib/gs/contribs/othello/othello_board.erl642
-rw-r--r--lib/gs/contribs/othello/priv/marker.bm43
-rw-r--r--lib/gs/contribs/othello/priv/square.bm43
8 files changed, 1609 insertions, 0 deletions
diff --git a/lib/gs/contribs/othello/Makefile b/lib/gs/contribs/othello/Makefile
new file mode 100644
index 0000000000..b81b35fb55
--- /dev/null
+++ b/lib/gs/contribs/othello/Makefile
@@ -0,0 +1,100 @@
+#
+# %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%
+#
+
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(GS_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/gs-$(VSN)/contribs
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MODULES= \
+ othello \
+ othello_adt \
+ othello_board
+
+HRL_FILES=
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+TARGET_FILES= $(MODULES:%=../ebin/%.$(EMULATOR)) $(TARGET_TOOLBOX_FILES)
+
+TOOLNAME = othello
+
+EXTRA_FILES=
+TOOLBOX_FILES= $(TOOLNAME).tool $(TOOLNAME).gif
+TARGET_TOOLBOX_FILES= $(TOOLBOX_FILES:%=$(EBIN)/%)
+BITMAPS= priv/marker.bm priv/square.bm
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(TARGET_FILES)
+
+docs:
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(EBIN)/$(TOOLNAME).gif: $(TOOLNAME).gif
+ rm -f $@
+ cp $(TOOLNAME).gif $@
+
+$(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
+ rm -f $@
+ cp $(TOOLNAME).tool $@
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/othello
+ $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/othello
+ $(INSTALL_DIR) $(RELSYSDIR)/othello/priv
+ $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) $(RELSYSDIR)/othello/priv
+
+release_docs_spec:
+
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.
+
+
diff --git a/lib/gs/contribs/othello/othello.gif b/lib/gs/contribs/othello/othello.gif
new file mode 100644
index 0000000000..5970c50209
--- /dev/null
+++ b/lib/gs/contribs/othello/othello.gif
Binary files differ
diff --git a/lib/gs/contribs/othello/othello.tool b/lib/gs/contribs/othello/othello.tool
new file mode 100644
index 0000000000..47550a581d
--- /dev/null
+++ b/lib/gs/contribs/othello/othello.tool
@@ -0,0 +1,6 @@
+{version,"0.1"}.
+{{tool,"Othello"},
+ {start,{othello,start,[]}},
+ {icon,"othello.gif"},
+ {message,"Othello - The Game"},
+ {html,"http://www.armory.com/~iioa/othguide.html"}}.
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.
+
diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl
new file mode 100644
index 0000000000..0206ba2ded
--- /dev/null
+++ b/lib/gs/contribs/othello/othello_board.erl
@@ -0,0 +1,642 @@
+%%
+%% %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_board).
+-export([start/0,stop/0,init/0]).
+
+
+%%----------------------------------------------------------------------
+%% The Othello program now uses the gs graphical package instead of the
+%% pxw package.
+%%
+%% Differences are, explanation why and source of change in parenthesis:
+%%
+%% - Buttons looks different (gs feature)
+%% - The black box around "Black to draw" have been removed. (me)
+%% - The Colour and Level menues have been moved directly down to the
+%% 'Status' box. (usability update, my addition)
+%% - The mouse pointer does not change into a watch when the computer
+%% is thinking (not supported in gs)
+%% - Buttons does not flash when being beeped. (not supported in gs)
+%%
+%%
+%% /Peter
+%%
+%%----------------------------------------------------------------------
+
+
+-define(BGCOL,forestgreen).
+
+start() ->
+ spawn(othello_board,init,[]).
+
+stop() ->
+ ok.
+
+%% This is not an application so we don't have their way of knowing
+%% a private data directory where the GIF files are located (this directory).
+%% We can find GS and makes it relative from there /kgb
+
+-define(BitmapPath,"../contribs/othello/priv").
+
+setup_path() ->
+ GsPrivDir = code:priv_dir(gs),
+ Path = filename:join(GsPrivDir,?BitmapPath),
+ put(path,Path).
+
+path() -> get(path).
+
+
+
+%%
+%% The button area are the Quit, Rules buttons at the top of the window.
+%% The Status area is the black and white scores level and colour etc
+%% inbetween the buttons and the othello board.
+%% The board is the 8x8 board where othello battles are fought.
+%%
+init() ->
+ process_flag(trap_exit,true),
+ setup_path(),
+ S = gs:start(),
+ put(windowroot,S), % Ugly global store
+
+ %% Shell coordinates
+ W = 496,
+ H = 636,
+
+ %% Fix top window
+ Shell = gs:create(window, S, [{title,"Othello"},
+ {width, W},{height, H}]),
+
+
+ %% Setup window contents
+
+ setup_buttons(Shell,0,0,W,40), % Fix Menubar
+ setup_status_box(Shell,0,40,W,100), % Fix Status area
+ setup_board(Shell,0,140,496,496), % Combat board
+
+ GamePid = othello:new_game(white,black,1,first_time),
+
+ %% Default settings
+ Options = {white,black,1},
+ %%Wids = {Status,B,W,Dr,Le,Co},
+ Wids = {change,this,at,later,stage,ponto},
+ write_options(Options,Wids),
+
+ gs:config(Shell, {map, true}), %Make win visible
+
+ loop(computer,GamePid,Shell,Wids,Options).
+
+
+
+
+
+
+loop(User,GamePid,Shell,Wids,Options) ->
+ receive
+ {gs,ButtId, click,_ButtId1,[Button]} ->
+ GamePid1 = but_pressed(Button,ButtId,User,GamePid,Shell,
+ Wids,Options),
+ loop(User,GamePid1,Shell,Wids,Options);
+
+ {gs,_, click,_,[MenuItem,_MenuIndex]} ->
+ Ops = menu_selected(MenuItem,User,GamePid,Wids,Options),
+ loop(User,GamePid,Shell,Wids,Ops);
+
+ {'EXIT',GamePid,_} ->
+ loop(User,null,Shell,Wids,Options);
+
+ {'EXIT',_,_} ->
+ loop(User,GamePid,Shell,Wids,Options);
+
+ GameMsg ->
+ game_msg(GameMsg,User,GamePid,Shell,Wids,Options)
+ end.
+
+but_pressed("Quit",_ButtId,_User,_GamePid,_Shell,_Wids,_Op) ->
+ stop(),
+ exit(quit);
+but_pressed("Rules",_ButtId,_User,GamePid,_Shell,_Wids,_Op) ->
+ io:format("No rules, do as you wish~n",[]),
+ GamePid;
+but_pressed("Help",_ButtId,_User,GamePid,_Shell,_Wids,_Op) ->
+ io:format("Othello game~n",[]),
+ io:format("------------~n",[]),
+ io:format(" Put markers by clicking in squares~n",[]),
+ io:format(" Change level by clicking on it~n",[]),
+ io:format(" Change colour by clicking on it~n",[]),
+ io:format("~n",[]),
+ GamePid;
+but_pressed("Newgame",_ButtId,_User,GamePid,_Shell,Wids,Options) ->
+ new_game(GamePid,Wids,Options);
+but_pressed([],ButtId,User,GamePid,_Shell,_Wids,_Op)
+ when pid(GamePid),User == player ->
+ [C,R] = atom_to_list(ButtId),
+ GamePid ! {self(),position,othello_adt:pos(C-96,translate(R-48))},
+ GamePid;
+but_pressed([],ButtId,_User,GamePid,_Shell,_Wids,_Op) ->
+ [C,R] = atom_to_list(ButtId),
+ beep(othello_adt:pos(C-96,translate(R-48))),
+ GamePid;
+but_pressed(Button,ButtId,_User,GamePid,_Shell,_Wids,_Op) ->
+ io:format('Not implemented button pressed ~p, ~p!!!~n',[ButtId,Button]),
+ GamePid.
+
+menu_selected("Black",_User,_GamePid,Wids,Options) ->
+ Op0 = setelement(1,Options,white),
+ Op1 = setelement(2,Op0,white),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("White",_User,_GamePid,Wids,Options) ->
+ Op0 = setelement(1,Options,black),
+ Op1 = setelement(2,Op0,black),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("Black (begin)",_User,_GamePid,Wids,Options) ->
+ Op0 = setelement(1,Options,white),
+ Op1 = setelement(2,Op0,black),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("White (begin)",_User,_GamePid,Wids,Options) ->
+ Op0 = setelement(1,Options,black),
+ Op1 = setelement(2,Op0,white),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("Beginner",_User,_GamePid,Wids,Options) ->
+ Op1 = setelement(3,Options,1),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("Intermediate",_User,_GamePid,Wids,Options) ->
+ Op1 = setelement(3,Options,2),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("Advanced",_User,_GamePid,Wids,Options) ->
+ Op1 = setelement(3,Options,3),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected("Expert",_User,_GamePid,Wids,Options) ->
+ Op1 = setelement(3,Options,4),
+ write_options(Op1,Wids),
+ Op1;
+menu_selected(What,_User,_GamePid,_Wids,Options) ->
+ io:format('Menu item not implemented <~s>~n',[What]),
+ Options.
+
+game_msg(Msg,User,GamePid,Shell,Wids,Options) ->
+ case Msg of
+ {GamePid,new_mark,Pos,Colour} ->
+ new_mark(Pos,Colour),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ {GamePid,illegal_draw,Draw} ->
+ beep(Draw),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ {GamePid,player,Computer,Computer} ->
+ show_player(element(1,Wids),Computer),
+ cursor("watch"),
+ GamePid ! {self(),go_on_play},
+ loop(computer,GamePid,Shell,Wids,Options);
+
+ {GamePid,player,_Computer,Player} ->
+ show_player(element(1,Wids),Player),
+ cursor("top_left_arrow"),
+ GamePid ! {self(),go_on_play},
+ loop(player,GamePid,Shell,Wids,Options);
+
+ {GamePid,omit_draw,Player} ->
+ omit_draw(GamePid,Player),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ {GamePid,score,WhiteRes,BlackRes} ->
+ write_score(Wids,WhiteRes,BlackRes),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ {GamePid,draw,Draw} ->
+ write_draw(Wids,Draw),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ {GamePid,game_over,WhiteRes,BlackRes} ->
+ game_over(WhiteRes,BlackRes),
+ loop(User,GamePid,Shell,Wids,Options);
+
+ What ->
+ io:format('game_msg received: ~w~n',[What]),
+ loop(User,GamePid,Shell,Wids,Options)
+ end.
+
+
+new_game(GamePid,Wids,Options) when pid(GamePid) ->
+ exit(GamePid,kill),
+ new_game(Wids,Options);
+new_game(_,Wids,Options) ->
+ new_game(Wids,Options).
+
+new_game(_Wids,Options) ->
+ label("",lastdraw),
+ Computer = element(1,Options),
+ Start = element(2,Options),
+ Depth = element(3,Options),
+ othello:new_game(Computer,Start,Depth,restart).
+
+new_mark(Pos,Colour) ->
+ Col = othello_adt:col(Pos),
+ Row = othello_adt:row(Pos),
+ Name = [Col+96,translate(Row)+48],
+ Button = get(Name),
+ butbit(Button,Colour).
+
+beep(Draw) ->
+ Col = othello_adt:col(Draw),
+ Row = othello_adt:row(Draw),
+ Name = [Col+96,translate(Row)+48],
+ Button = get(Name),
+ bell(Button).
+
+show_player(_Status,white) ->
+ label("White to draw",todraw);
+show_player(_Status,black) ->
+ label("Black to draw",todraw).
+
+write_score(_Wids,WhiteRes,BlackRes) ->
+ label(integer_to_list(BlackRes),bscore),
+ label(integer_to_list(WhiteRes),wscore).
+
+write_draw(_Wids,Draw) ->
+ Col = othello_adt:col(Draw),
+ Row = othello_adt:row(Draw),
+ label(lists:flatten(io_lib:format('{~w,~w}',[Col,Row])), lastdraw).
+
+write_options(Options,Wids) ->
+ write_colour(Options,Wids),
+ write_level(Options,Wids).
+
+write_colour(Options,Wids) ->
+ write_colour(element(1,Options),element(2,Options),Wids).
+
+write_colour(black,white,_Wids) -> label("White (begin)",colour);
+write_colour(black,black,_Wids) -> label("White",colour);
+write_colour(white,black,_Wids) -> label("Black (begin)",colour);
+write_colour(white,white,_Wids) -> label("Black",colour).
+
+write_level(Options,_Wids) ->
+ case element(3,Options) of
+ 1 -> label("Beginner",level);
+ 2 -> label("Intermediate",level);
+ 3 -> label("Advanced",level);
+ 4 -> label("Expert",level)
+ end.
+
+cursor(_What) ->
+ done.
+%cursor(What) -> cursor(get(),What).
+
+%cursor([{[C,R],Button}|Buts],What) ->
+% set_widget(Button,"cursor",What),
+% cursor(Buts,What);
+%cursor([_|Buts],What) ->
+% cursor(Buts,What);
+%cursor([],_) ->
+% true.
+
+translate(1) -> 8;
+translate(2) -> 7;
+translate(3) -> 6;
+translate(4) -> 5;
+translate(5) -> 4;
+translate(6) -> 3;
+translate(7) -> 2;
+translate(8) -> 1.
+
+bitmap(grey) -> bitmap_path("square.bm");
+bitmap(black) -> bitmap_path("marker.bm");
+bitmap(white) -> bitmap_path("marker.bm").
+
+bitmap_path(Bitmap) ->
+ filename:join(path(),Bitmap).
+
+xy_position([[Letter,Digit],_,_]) ->
+ LettPos = Letter - 97,
+ X = LettPos*60 ,
+ Y = (8 - list_to_integer([Digit])) * 60,
+ {X+6,Y+6};
+xy_position(X) ->
+ io:format("xy_position: ~w~n",[{error,X}]).
+
+
+board() ->
+ [["a1",grey,nil],
+ ["b1",grey,nil],
+ ["c1",grey,nil],
+ ["d1",grey,nil],
+ ["e1",grey,nil],
+ ["f1",grey,nil],
+ ["g1",grey,nil],
+ ["h1",grey,nil],
+
+ ["a2",grey,nil],
+ ["b2",grey,nil],
+ ["c2",grey,nil],
+ ["d2",grey,nil],
+ ["e2",grey,nil],
+ ["f2",grey,nil],
+ ["g2",grey,nil],
+ ["h2",grey,nil],
+
+ ["a3",grey,nil],
+ ["b3",grey,nil],
+ ["c3",grey,nil],
+ ["d3",grey,nil],
+ ["e3",grey,nil],
+ ["f3",grey,nil],
+ ["g3",grey,nil],
+ ["h3",grey,nil],
+
+ ["a4",grey,nil],
+ ["b4",grey,nil],
+ ["c4",grey,nil],
+ ["d4",white,nil],
+ ["e4",black,nil],
+ ["f4",grey,nil],
+ ["g4",grey,nil],
+ ["h4",grey,nil],
+
+ ["a5",grey,nil],
+ ["b5",grey,nil],
+ ["c5",grey,nil],
+ ["d5",black,nil],
+ ["e5",white,nil],
+ ["f5",grey,nil],
+ ["g5",grey,nil],
+ ["h5",grey,nil],
+
+ ["a6",grey,nil],
+ ["b6",grey,nil],
+ ["c6",grey,nil],
+ ["d6",grey,nil],
+ ["e6",grey,nil],
+ ["f6",grey,nil],
+ ["g6",grey,nil],
+ ["h6",grey,nil],
+
+ ["a7",grey,nil],
+ ["b7",grey,nil],
+ ["c7",grey,nil],
+ ["d7",grey,nil],
+ ["e7",grey,nil],
+ ["f7",grey,nil],
+ ["g7",grey,nil],
+ ["h7",grey,nil],
+
+ ["a8",grey,nil],
+ ["b8",grey,nil],
+ ["c8",grey,nil],
+ ["d8",grey,nil],
+ ["e8",grey,nil],
+ ["f8",grey,nil],
+ ["g8",grey,nil],
+ ["h8",grey,nil]].
+
+
+omit_draw(GamePid,Player) ->
+% %% Find mouse coords first
+% %% This was not possible in gs
+
+ W = 200, H = 100, Root = get(windowroot),
+ Box = gs:create(window, Root, [{title,"OMIT"}, {width, W},{height, H}]),
+
+ mk_label_c(lists:flatten(io_lib:format('~w has to omit draw !',[Player])),
+ Box, W, 10),
+
+ mk_button_c("Ok", Box, W, H-40, 80, 30),
+
+ gs:config(Box, {map, true}), %Make win visible
+
+ receive
+ {gs,_, click,_,["Ok"]} ->
+ gs:destroy(Box),
+ GamePid ! {self(),continue}
+ end.
+
+game_over(WhiteRes,BlackRes) ->
+% %% Find mouse coords first
+% %% This was not possible in gs
+
+ W = 200, H = 160,
+ Root = get(windowroot),
+ Box = gs:create(window, Root, [{title,"GAME OVER"},
+ {width, W},{height, H}]),
+
+ mk_label_c("GAME OVER", Box, W, 10),
+
+ mk_label_c(lists:flatten(io_lib:format('White score: ~w',[WhiteRes])),
+ Box,W,40),
+ mk_label_c(lists:flatten(io_lib:format('Black score: ~w',[BlackRes])),
+ Box,W,70),
+
+ mk_button_c("Ok", Box, W, H-40, 80, 30),
+
+ gs:config(Box, {map, true}), %Make win visible
+
+ receive
+ {gs,_, click,_,["Ok"]} ->
+ gs:destroy(Box)
+ end.
+
+
+
+%% ----------------------------------------------------------------
+%% Library functions.
+%% ----------------------------------------------------------------
+
+bell(Widget) ->
+ %% gs does not support bells,
+ Widget.
+
+label(Text,Label) ->
+ gs:config(Label,[{label,{text,Text}}]).
+
+%% mk_label in centered version
+mk_label_c(Label,Parent,Width,Y) ->
+ W = 8*length(Label),
+ X = trunc((Width-W)/2),
+ gs:create(label,Parent,[{width,W}, {height, 20}, {x,X}, {y,Y},
+ {label, {text, Label}}]).
+
+
+
+
+setup_buttons(Shell,X,Y,W,H) ->
+ ButBox = gs:create(frame, Shell,[{x,X}, {y,Y},{bg,white},
+ {width,W}, {height,H}]),
+ C = gs:create(canvas,ButBox,[{x,X}, {y,Y}, {width, W}, {height, H},
+ {bg,white}]),
+ gs:create(line, C, [{coords, [{0,H-1},{W,H-1}]}]),
+
+
+ mk_button("Quit",ButBox, 10, 10, 70, 20),
+ mk_button("Rules",ButBox, 80, 10, 70, 20),
+ mk_button("Newgame",ButBox, 150, 10, 70, 20),
+ mk_button("Help",ButBox, 220, 10, 70, 20),
+%% mk_button("Level",ButBox, 290, 10, 70, 20),
+
+ done.
+
+
+
+
+
+%%----------------------------------------
+%% Sets up the middle window w. all the status info in.
+%% The labels are given names:
+%% bscore, wscore, lastdraw, todraw, level and colour to simplify
+%% their frequent setting
+%%
+setup_status_box(Shell,X,Y,W,H) ->
+ F = gs:create(frame, Shell,[{x,X}, {y,Y},
+ {width,W}, {height,H},{bg,white}]),
+ C = gs:create(canvas,F,[{x,0}, {y,0}, {width, W}, {height, H},{bg,white}]),
+ gs:create(line, C, [{coords, [{0,H-1},{W,H-1}]}]),
+
+ %% Left side
+ gs:create(label,F,[{align,w},{x,10}, {y,5}, {width, 100},
+ {label,{text, "Black score:"}},{bg,white}]),
+ gs:create(label,bscore,F,[{align,w},{x,110}, {y,5}, {width, 40},
+ {label,{text, "2"}},{bg,white}]),
+ gs:create(label,F,[{align,w},{x,10}, {y,35}, {width, 100},
+ {label,{text, "White score:"}},{bg,white}]),
+ gs:create(label,wscore,F,[{align,w},{x,110}, {y,35}, {width, 40},
+ {label,{text, "2"}},{bg,white}]),
+ gs:create(label,F,[{align,w},{x,10}, {y,65}, {width, 100},
+ {label,{text, "Last draw:"}},{bg,white}]),
+ gs:create(label,lastdraw,F,[{align,w},{x,110}, {y,65}, {width, 40},
+ {label,{text, ""}},{bg,white}]),
+
+
+ %% Right side
+ X2 = trunc(W/2)+10,
+ gs:create(label,todraw,F,[{align,w},{x,X2}, {y,5}, {width, 100},
+ {label,{text, "Black to draw:"}},{bg,white}]),
+
+ gs:create(label,F,[{align,w},{x,X2}, {y,35}, {width, 80},
+ {label,{text, "Level:"}},{bg,white}]),
+ setup_level_menu(F,X2+80,35),
+
+%% gs:create(label,level,F,[{align,w},{x,X2+80}, {y,35}, {width, 130},
+%% {label,{text, "Intermediate"}},{bg,white}]),
+ gs:create(label,F,[{align,w},{x,X2}, {y,65}, {width, 80},
+ {label,{text, "Colour:"}},{bg,white}]),
+ setup_col_menu(F,X2+80,65),
+
+%% gs:create(label,colour,F,[{align,w},{x,X2+80}, {y,65}, {width, 120},
+%% {label,{text, "black (begin)"}},{bg,white}]),
+
+ done.
+
+
+setup_col_menu(P,X,Y) ->
+ MB = gs:create(menubutton,colour,P,
+ [{x,X}, {y,Y}, {bw,3},
+ %%{width,W}, {height,H},
+ {align,w}, {bg,white},
+ {relief, raised},
+ {activefg,white}, {activebg,black},
+ {label, {text,"Colours"}}]),
+
+ M = gs:create(menu,MB,[]),
+ gs:create(menuitem,M,[{label,{text,"Black (begin)"}}]),
+ gs:create(menuitem,M,[{label,{text,"Black"}}]),
+ gs:create(menuitem,M,[{label,{text,"White (begin)"}}]),
+ gs:create(menuitem,M,[{label,{text,"White"}}]),
+ done.
+
+setup_level_menu(P,X,Y) ->
+ MB = gs:create(menubutton,level,P,
+ [{x,X}, {y,Y},
+ %%{width,W}, {height,H},
+ {relief, raised},
+ {activefg,white}, {activebg,black},
+ {align,w}, {bg,white},
+ {label, {text,"Colours"}}]),
+
+ M = gs:create(menu,MB,[]),
+ gs:create(menuitem,M,[{label,{text,"Beginner"}}]),
+ gs:create(menuitem,M,[{label,{text,"Intermediate"}}]),
+ gs:create(menuitem,M,[{label,{text,"Advanced"}}]),
+ gs:create(menuitem,M,[{label,{text,"Expert"}}]),
+ done.
+
+
+setup_board(Shell,X,Y,W,H) ->
+ F = gs:create(frame, Shell,[{x,X}, {y,Y},
+ {width,W}, {height,H},{bg,white}]),
+ display_board(F).
+
+
+mk_button(Label, Parent, X, Y, W, H) ->
+ gs:create(button,Parent,[{width,W}, {height, H}, {x,X}, {y,Y},
+ {label, {text, Label}}, {bg,white},
+ {activefg,white}, {activebg,black}]).
+
+%% Centers a button around Width
+mk_button_c(Label, Parent, Width, Y, W, H) ->
+ X = trunc((Width-W)/2),
+ gs:create(button,Parent,[{width,W}, {height, H}, {x,X}, {y,Y},
+ {label, {text, Label}}, {bg,white}]).
+
+
+butbit(Button,Col) ->
+ gs:config(Button,[
+ {label,{image,bitmap(Col)}},
+ {fg, Col},
+ {activefg,Col},
+ {label, {image, bitmap(Col)}}]),
+ Button.
+
+mk_board_butt(Top,Name,X,Y,Col) ->
+ B = gs:create(button,list_to_atom(Name), Top,
+ [{x,X}, {y,Y}, {width,60}, {height,60},
+ {padx,5},{pady,5},
+ {relief,flat},
+ {bg,?BGCOL}, {activebg,?BGCOL}]),
+ butbit(B,Col),
+ B.
+
+
+
+display_board(Top) ->
+ Board = board(),
+ display_board(Top,Board,1).
+
+display_board(_,_,65) -> true;
+display_board(Top,[H|T],Place) ->
+ [Name,Colour,_] = H,
+ {X,Y} = xy_position(H),
+ Button = mk_board_butt(Top,Name,X,Y,Colour),
+ %%Button = mk_button("",Name,Top,X,Y,60,60),
+ put(Name,Button),
+ %%Bitmap = bitmap(Colour),
+ %%butbit(Button,Bitmap),
+ %%set_widget(Button,"internalWidth","1"),
+ %%set_widget(Button,"internalHeight","1"),
+ %%borderWidth(2,Button),
+ display_board(Top,T,Place+1).
+
+
diff --git a/lib/gs/contribs/othello/priv/marker.bm b/lib/gs/contribs/othello/priv/marker.bm
new file mode 100644
index 0000000000..fe7f3df820
--- /dev/null
+++ b/lib/gs/contribs/othello/priv/marker.bm
@@ -0,0 +1,43 @@
+#define marker2_width 60
+#define marker2_height 60
+static unsigned char marker2_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+ 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+ 0xff, 0x3f, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, 0xff, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
+ 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xfe, 0xff, 0xff,
+ 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x7f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
+ 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xe0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0xc0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x7f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x00,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff,
+ 0xff, 0x3f, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x3f, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xcf, 0x1f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xc7, 0x0f, 0x00,
+ 0x00, 0xfc, 0xff, 0xff, 0xff, 0xe7, 0x07, 0x00, 0x00, 0xf8, 0xff, 0xff,
+ 0x7f, 0xf1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xbf, 0xfc, 0x03, 0x00,
+ 0x00, 0xf0, 0xff, 0xff, 0x59, 0xff, 0x01, 0x00, 0x00, 0xe0, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
+ 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/lib/gs/contribs/othello/priv/square.bm b/lib/gs/contribs/othello/priv/square.bm
new file mode 100644
index 0000000000..4e6880b330
--- /dev/null
+++ b/lib/gs/contribs/othello/priv/square.bm
@@ -0,0 +1,43 @@
+#define square_width 60
+#define square_height 60
+static unsigned char square_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};