├── ggg.png ├── rebar ├── .rebar └── erlcinfo ├── src ├── web │ ├── black.png │ ├── board.png │ ├── empty.png │ ├── mark.png │ ├── star.png │ ├── white.png │ ├── board.js │ ├── test.js │ ├── play.js │ ├── serve.erl │ ├── undo.js │ ├── refresh.js │ ├── main.html │ ├── new_game.js │ ├── main_handler.erl │ ├── internal_handler.erl │ └── rpc.js ├── tester.erl ├── undo.erl ├── ggg.app.src ├── constants.erl ├── empty_get_server.save ├── ggg_app.erl ├── ggg_sup.erl ├── socket.erl ├── play_move.erl ├── connect.erl ├── board_user.erl ├── board.erl ├── draw.erl └── get_board.erl ├── .gitignore ├── rebar.config ├── start.sh ├── rebar.config.old └── README.md /ggg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/ggg.png -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/rebar -------------------------------------------------------------------------------- /.rebar/erlcinfo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/.rebar/erlcinfo -------------------------------------------------------------------------------- /src/web/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/black.png -------------------------------------------------------------------------------- /src/web/board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/board.png -------------------------------------------------------------------------------- /src/web/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/empty.png -------------------------------------------------------------------------------- /src/web/mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/mark.png -------------------------------------------------------------------------------- /src/web/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/star.png -------------------------------------------------------------------------------- /src/web/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zack-bitcoin/ggg/master/src/web/white.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /deps/ 2 | /ebin/ 3 | *.db 4 | *~ 5 | .#* 6 | \#* 7 | rebar 8 | rebar_source 9 | .rebar 10 | erl_crash.dump 11 | keys_backup -------------------------------------------------------------------------------- /src/web/board.js: -------------------------------------------------------------------------------- 1 | setInterval(board_display, 200); 2 | 3 | function board_display() { 4 | var src = document.getElementById("img"); 5 | src.src = "board.png?" + new Date().getTime(); 6 | } 7 | -------------------------------------------------------------------------------- /src/tester.erl: -------------------------------------------------------------------------------- 1 | -module(tester). 2 | -export([test/0]). 3 | 4 | test() -> 5 | S = connect:start(), 6 | play_move:doit(S, 4, 4), 7 | draw:draw(get_board:doit(S)), 8 | S. 9 | 10 | -------------------------------------------------------------------------------- /src/undo.erl: -------------------------------------------------------------------------------- 1 | -module(undo). 2 | -export([doit/1]). 3 | 4 | doit(S) -> 5 | Command = "undo\n", 6 | gen_tcp:send(S, list_to_binary(Command)), 7 | gen_tcp:send(S, list_to_binary(Command)). 8 | 9 | 10 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {deps, [ 2 | {jiffy, "0.14.7", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}}, 3 | {cowboy, "1.0.3", {git, "https://github.com/ninenines/cowboy.git", {tag, "1.0.3"}}} 4 | ]}. 5 | 6 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | ./rebar get-deps 2 | ./rebar compile 3 | echo "GO TO THIS WEBSITE -------> http://localhost:4040/main.html" 4 | # erl -pa ebin deps/*/ebin/ -eval "application:ensure_all_started(ggg), serve:start()" 5 | erl -pa ebin deps/*/ebin/ -eval "application:ensure_all_started(ggg)" 6 | -------------------------------------------------------------------------------- /rebar.config.old: -------------------------------------------------------------------------------- 1 | %% {erl_opts, [native, {hipe, [verbose]}, warnings_as_errors, debug_info]}. 2 | {deps, [ 3 | {jiffy, "0.14.7", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}}, 4 | {cowboy, "1.0.3", {git, "https://github.com/ninenines/cowboy.git", {tag, "1.0.3"}}} 5 | ]}. 6 | 7 | -------------------------------------------------------------------------------- /src/ggg.app.src: -------------------------------------------------------------------------------- 1 | {application, ggg, 2 | [ 3 | {description, ""}, 4 | {vsn, "1"}, 5 | {registered, []}, 6 | {applications, [ 7 | kernel, 8 | stdlib, 9 | ssl, 10 | cowboy, 11 | jiffy 12 | ]}, 13 | {modules, []}, 14 | {mod, { ggg_app, []}}, 15 | {env, []} 16 | ]}. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ggg 2 | GnuGoGui 3 | 4 | This is a for connecting gnugo to the browser so that you can play go against an AI. You need to have gnugo installed first to use this software. 5 | 6 | To change the difficulty, amount of ram used, etc, update the src/constants.erl file. 7 | 8 | to start the program: 9 | 10 | ``` 11 | sh start.sh 12 | ``` 13 | 14 |  -------------------------------------------------------------------------------- /src/web/test.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var test_var = document.createElement("div"); 4 | test_var.id = "test_var"; 5 | document.body.appendChild(test_var); 6 | console.log("test here "); 7 | function t2(x) { 8 | console.log("in t2"); 9 | console.log(x); 10 | var h = document.getElementById("test_var"); 11 | h.innerHTML = "test output: ".concat(x); 12 | } 13 | variable_get(["example"], t2); 14 | -------------------------------------------------------------------------------- /src/constants.erl: -------------------------------------------------------------------------------- 1 | -module(constants). 2 | -compile(export_all). 3 | port() -> 4040. 4 | gnu_port() -> 4041. 5 | wait_on_gnu() -> 120000.%if the AI takes more than 2 minutes to think, their move wont get updated, and you have to click the "refresh" button eventually. 6 | difficulty() -> 17. 7 | ram() -> 500.%in megabytes 8 | %location() -> "../../src/web". 9 | location() -> "src/web". 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/web/play.js: -------------------------------------------------------------------------------- 1 | function play(event) { 2 | var x = event.offsetX?(event.offsetX):event.pageX-document.getElementById("img").offsetLeft; 3 | var y = event.offsetY?(event.offsetY):event.pageY-document.getElementById("img").offsetTop; 4 | a = Math.floor(x/19) + 1; 5 | b = 19 - Math.floor(y/19); 6 | console.log(a); 7 | console.log(b); 8 | get(["play", a, b]); 9 | board_display(); 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/web/serve.erl: -------------------------------------------------------------------------------- 1 | -module(serve). 2 | -export([start/0]). 3 | start() -> 4 | Port = constants:port(), 5 | io:fwrite("start server\n"), 6 | D = [ 7 | {'_', [ 8 | {"/:file", main_handler, []}, 9 | {"/", internal_handler, []} 10 | ]} 11 | ], 12 | Dispatch = cowboy_router:compile(D), 13 | K = [{env, [{dispatch, Dispatch}]} ], 14 | {ok, _} = cowboy:start_http(http, 100, [{ip, {0,0,0,0}},{port, Port}], K). 15 | 16 | -------------------------------------------------------------------------------- /src/empty_get_server.save: -------------------------------------------------------------------------------- 1 | -module(). 2 | -behaviour(gen_server). 3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]). 4 | init(ok) -> {ok, []}. 5 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []). 6 | code_change(_OldVsn, State, _Extra) -> {ok, State}. 7 | terminate(_, _) -> io:format("died!"), ok. 8 | handle_info(_, X) -> {noreply, X}. 9 | handle_cast(_, X) -> {noreply, X}. 10 | handle_call(_, _From, X) -> {reply, X, X}. -------------------------------------------------------------------------------- /src/web/undo.js: -------------------------------------------------------------------------------- 1 | undo(); 2 | 3 | function undo() { 4 | var spend_button = document.createElement("BUTTON"); 5 | spend_button.id = "undo_button"; 6 | var spend_button_text = document.createTextNode("undo move"); 7 | spend_button.appendChild(spend_button_text); 8 | spend_button.onclick = function() { 9 | get(["undo"]); 10 | }; 11 | document.body.appendChild(document.createElement("br")); 12 | document.body.appendChild(spend_button); 13 | board_display(); 14 | } 15 | -------------------------------------------------------------------------------- /src/ggg_app.erl: -------------------------------------------------------------------------------- 1 | -module(ggg_app). 2 | 3 | -behaviour(application). 4 | 5 | %% Application callbacks 6 | -export([start/2, stop/1]). 7 | 8 | %% =================================================================== 9 | %% Application callbacks 10 | %% =================================================================== 11 | 12 | start(_StartType, _StartArgs) -> 13 | ssl:start(), 14 | application:start(inets), 15 | serve:start(), 16 | ggg_sup:start_link(). 17 | 18 | stop(_State) -> 19 | ok. 20 | -------------------------------------------------------------------------------- /src/web/refresh.js: -------------------------------------------------------------------------------- 1 | refresh(); 2 | 3 | function refresh() { 4 | var spend_button = document.createElement("BUTTON"); 5 | spend_button.id = "refresh_button"; 6 | var spend_button_text = document.createTextNode("refresh board"); 7 | spend_button.appendChild(spend_button_text); 8 | spend_button.onclick = function() { 9 | get(["refresh"]); 10 | }; 11 | document.body.appendChild(document.createElement("br")); 12 | document.body.appendChild(spend_button); 13 | board_display(); 14 | } 15 | -------------------------------------------------------------------------------- /src/web/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/ggg_sup.erl:
--------------------------------------------------------------------------------
1 | -module(ggg_sup).
2 | -behaviour(supervisor).
3 | %% API
4 | -export([start_link/0]).
5 | %% Supervisor callbacks
6 | -export([init/1]).
7 |
8 | %% Helper macro for declaring children of supervisor
9 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
10 | -define(children, [board, socket, board_user]).
11 | start_link() ->
12 | supervisor:start_link({local, ?MODULE}, ?MODULE, []).
13 | child_maker([]) -> [];
14 | child_maker([H|T]) -> [?CHILD(H, worker)|child_maker(T)].
15 | init([]) ->
16 | Children = child_maker(?children),
17 | {ok, { {one_for_one, 5, 10}, Children} }.
18 |
19 |
--------------------------------------------------------------------------------
/src/socket.erl:
--------------------------------------------------------------------------------
1 | -module(socket).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2, fetch/0,store/1]).
4 | init(ok) -> {ok, []}.
5 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
6 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
7 | terminate(_, _) -> io:format("died!"), ok.
8 | handle_info(_, X) -> {noreply, X}.
9 | handle_cast({store, S}, _) -> {noreply, S};
10 | handle_cast(_, X) -> {noreply, X}.
11 | handle_call(fetch, _From, X) -> {reply, X, X};
12 | handle_call(_, _From, X) -> {reply, X, X}.
13 | fetch() -> gen_server:call(?MODULE, fetch).
14 | store(S) -> gen_server:cast(?MODULE, {store, S}).
15 |
--------------------------------------------------------------------------------
/src/web/new_game.js:
--------------------------------------------------------------------------------
1 | new_game();
2 |
3 | function new_game2() {
4 | get(["new_game"]);
5 | }
6 |
7 | function new_game() {
8 | var spend_button = document.createElement("button");
9 | spend_button.id = 'new_game_button';
10 | var spend_button_text = document.createTextNode("new game");
11 | spend_button.appendChild(spend_button_text);
12 | //f = function() {get(["new_game"]);};
13 | spend_button.onclick = new_game2;
14 | spend_button.ontouchend = new_game2;
15 | //spend_button.addEventListener('touchend', new_game2, false);
16 | //spend_button.addEventListener('click', new_game2, false);
17 | document.body.appendChild(spend_button);
18 | board_display();
19 | }
20 |
--------------------------------------------------------------------------------
/src/play_move.erl:
--------------------------------------------------------------------------------
1 | -module(play_move).
2 | -export([doit/3, ai/1]).
3 |
4 | doit(S, X, Y) ->
5 | A = to_letter(X),
6 | B = integer_to_list(Y),
7 | C = A++B,
8 | Command = "black "++C++"\n",
9 | gen_tcp:send(S, list_to_binary(Command)).
10 |
11 | ai(S) ->
12 | gen_tcp:send(S, <<"genmove white\n">>).
13 |
14 | to_letter(1) -> "A";
15 | to_letter(2) -> "B";
16 | to_letter(3) -> "C";
17 | to_letter(4) -> "D";
18 | to_letter(5) -> "E";
19 | to_letter(6) -> "F";
20 | to_letter(7) -> "G";
21 | to_letter(8) -> "H";
22 | to_letter(9) -> "J";
23 | to_letter(10) -> "K";
24 | to_letter(11) -> "L";
25 | to_letter(12) -> "M";
26 | to_letter(13) -> "N";
27 | to_letter(14) -> "O";
28 | to_letter(15) -> "P";
29 | to_letter(16) -> "Q";
30 | to_letter(17) -> "R";
31 | to_letter(18) -> "S";
32 | to_letter(19) -> "T".
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/web/main_handler.erl:
--------------------------------------------------------------------------------
1 | -module(main_handler).
2 |
3 | -export([init/3, handle/2, terminate/3]).
4 | %example of talking to this handler:
5 | %httpc:request(post, {"http://127.0.0.1:3011/", [], "application/octet-stream", "echo"}, [], []).
6 | %curl -i -d '[-6,"test"]' http://localhost:3011
7 | handle(Req, _) ->
8 | {F, _} = cowboy_req:path(Req),
9 | S = list_to_binary(constants:location()),
10 | File = << S/binary, F/binary>>,
11 | {ok, _Data, _} = cowboy_req:body(Req),
12 | Headers = [{<<"content-type">>, <<"text/html">>},
13 | {<<"Access-Control-Allow-Origin">>, <<"*">>}],
14 | Text = read_file(File),
15 | {ok, Req2} = cowboy_req:reply(200, Headers, Text, Req),
16 | {ok, Req2, File}.
17 | read_file(F) ->
18 | {ok, File } = file:open(F, [read, binary, raw]),
19 | {ok, O} =file:pread(File, 0, filelib:file_size(F)),
20 | file:close(File),
21 | O.
22 | init(_Type, Req, _Opts) -> {ok, Req, []}.
23 | terminate(_Reason, _Req, _State) -> ok.
24 |
--------------------------------------------------------------------------------
/src/connect.erl:
--------------------------------------------------------------------------------
1 | -module(connect).
2 | -export([test/0,start/0,start/2,quit/1]).
3 |
4 | connect() -> connect(10).
5 | connect(0) -> fail;
6 | connect(N) ->
7 | Port = constants:gnu_port(),
8 | case gen_tcp:connect({127,0,0,1}, Port, [binary,{active, true}]) of
9 | {ok, Socket} -> Socket;
10 | {error, econnrefused} ->
11 | timer:sleep(50),
12 | connect(N-1)
13 | end.
14 |
15 | start() -> start(constants:difficulty(), constants:ram()).
16 | start(Level, Ram) ->
17 | GPort = constants:gnu_port(),
18 | P = integer_to_list(GPort),
19 | L = integer_to_list(Level),
20 | R = integer_to_list(Ram), %default is about 11.
21 | Command = "gnugo --mode gtp --gtp-listen "++P++" --level "++L++" --cache-size " ++ R,
22 | erlang:open_port({spawn, Command}, []),
23 | connect(10).
24 | quit(Socket) ->
25 | gen_tcp:send(Socket, <<"quit\n">>),
26 | gen_tcp:close(Socket).
27 | test() ->
28 | S = connect(),
29 | draw:draw(get_board:doit(S)).
30 |
--------------------------------------------------------------------------------
/src/web/internal_handler.erl:
--------------------------------------------------------------------------------
1 | -module(internal_handler).
2 | -export([init/3, handle/2, terminate/3, doit/1]).
3 | %example of talking to this handler:
4 | %curl -i -d '[-6,"test"]' http://localhost:3011
5 | handle(Req, State) ->
6 | {ok, Data, _} = cowboy_req:body(Req),
7 | true = is_binary(Data),
8 | A = jiffy:decode(Data),
9 | B = doit(A),
10 | D = jiffy:encode(B),
11 | Headers = [{<<"content-type">>, <<"application/octet-stream">>},
12 | {<<"Access-Control-Allow-Origin">>, <<"*">>}],
13 | {ok, Req2} = cowboy_req:reply(200, Headers, D, Req),
14 | {ok, Req2, State}.
15 | init(_Type, Req, _Opts) -> {ok, Req, no_state}.
16 | terminate(_Reason, _Req, _State) -> ok.
17 | doit([<<"new_game">>]) -> board_user:start();
18 | doit([<<"undo">>]) -> board_user:undo();
19 | doit([<<"refresh">>]) -> board_user:refresh();
20 | doit([<<"play">>, X, Y]) -> board_user:play(X, Y);
21 | doit(X) ->
22 | io:fwrite("don't know how to handle it \n"),
23 | io:fwrite(jiffy:encode(X)),
24 | io:fwrite("\n"),
25 | [<<"error">>].
26 |
--------------------------------------------------------------------------------
/src/web/rpc.js:
--------------------------------------------------------------------------------
1 | function getter(t, u, callback){
2 | t = JSON.stringify(t);
3 | var xmlhttp=new XMLHttpRequest();
4 | xmlhttp.onreadystatechange = callback;
5 | xmlhttp.open("POST",u,true);
6 | xmlhttp.send(t);
7 | return xmlhttp
8 | }
9 | var PORT = parseInt(document.URL.substring(17, 21), 10);
10 | function url(port, ip) { return "http://".concat(ip).concat(":").concat(port.toString().concat("/")); }
11 | function get(t, callback) {
12 | u = url(PORT, "localhost");
13 | return getter(t, u, callback);
14 | }
15 | function xml_check(x) { return ((x.readyState === 4) && (x.status === 200)); };
16 | function xml_out(x) { return x.responseText; }
17 | function refresh_helper(x, callback) {
18 | if (xml_check(x)) {callback(xml_out(x));}
19 | else {setTimeout(function() {refresh_helper(x, callback);}, 1000);}
20 | };
21 | my_status = "nil";
22 | function variable_get(cmd, callback) {
23 | var x = get(cmd);
24 | var_get(x, callback);
25 | }
26 | function var_get(x, callback) {
27 | refresh_helper(x, function(){
28 | p = JSON.parse(xml_out(x));
29 | callback(p);
30 | });
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/src/board_user.erl:
--------------------------------------------------------------------------------
1 | %interpret_draw is likely to crash. this gen_server exists so that the board gen_server wont die.
2 | -module(board_user).
3 | -behaviour(gen_server).
4 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2, start/0,refresh/0,play/2,undo/0]).
5 | init(ok) ->
6 | {ok, null}.
7 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
8 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
9 | terminate(_, _) ->
10 | io:format("died!"), ok.
11 | handle_info(_, X) -> {noreply, X}.
12 | handle_cast(refresh, _) ->
13 | refresh2(),
14 | {noreply, 0};
15 | handle_cast(undo, _) ->
16 | S = socket:fetch(),
17 | undo:doit(S),
18 | refresh2(),
19 | {noreply, 0};
20 | handle_cast({play, X, Y}, _) ->
21 | S = socket:fetch(),
22 | play_move:doit(S, X, Y),
23 | refresh2(),
24 | board:flush(),
25 | play_move:ai(S),
26 | board:wait_on_gnugo(),
27 | refresh2(),
28 | {noreply, 0};
29 | handle_cast(start, _) ->
30 | B = board:start(),
31 | draw:interpret_draw(B),
32 | {noreply, 0}.
33 | handle_call(_, _From, X) -> X.
34 | start() -> gen_server:cast(?MODULE, start).
35 | undo() -> gen_server:cast(?MODULE, undo).
36 | refresh() -> gen_server:cast(?MODULE, refresh).
37 | play(X, Y) -> gen_server:cast(?MODULE, {play, X, Y}).
38 |
39 | refresh2() ->
40 | B = board:board(),
41 | draw:interpret_draw(B).
42 |
43 |
--------------------------------------------------------------------------------
/src/board.erl:
--------------------------------------------------------------------------------
1 | -module(board).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2, start/0,board/0,wait_on_gnugo/0,flush/0]).
4 | init(ok) ->
5 | {ok, null}.
6 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
7 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
8 | terminate(_, _) -> io:format("died!"), ok.
9 | handle_info(_, X) -> {noreply, X}.
10 | handle_cast(flush, _) ->
11 | %flush(),
12 | dump(),
13 | {noreplay, 0};
14 | handle_cast(_, X) -> {noreply, X}.
15 | handle_call(wait, _From, _) ->
16 | S = socket:fetch(),
17 | receive_eq(S),
18 | {reply, 0, 0};
19 | handle_call(start, _From, _) ->
20 | S = connect:start(),
21 | socket:store(S),
22 | B = get_board:doit(S),
23 | {reply, B, 0};
24 | handle_call(board, _From, _) ->
25 | S = socket:fetch(),
26 | B = get_board:doit(S),
27 | {reply, B, 0};
28 | handle_call(_, _From, X) -> {reply, X, X}.
29 | start() -> gen_server:call(?MODULE, start).
30 | flush() -> gen_server:call(?MODULE, flush).
31 | board() -> gen_server:call(?MODULE, board).
32 | wait_on_gnugo() -> gen_server:call(?MODULE, wait, constants:wait_on_gnu()).
33 |
34 | receive_eq(S) ->
35 | receive
36 | {tcp, S, X} ->
37 | B = has_eq(X),
38 | if
39 | B -> ok;
40 | true -> receive_eq(S)
41 | end
42 | after
43 | constants:wait_on_gnu() -> fail
44 | end.
45 |
46 | has_eq(<<61, _/binary>>) -> true;
47 | has_eq(<<>>) -> false;
48 | has_eq(<<_, X/binary>>) -> has_eq(X).
49 |
50 | dump() ->
51 | receive
52 | _ ->
53 | dump()
54 | after 10 ->
55 |
56 | ok
57 | end.
58 |
--------------------------------------------------------------------------------
/src/draw.erl:
--------------------------------------------------------------------------------
1 | -module(draw).
2 | -export([test/0, draw/1, interpret_draw/1]).
3 | interpret_draw(B) ->
4 | draw(get_board:interpret(B)).
5 | draw(B) ->
6 | Lo = constants:location(),
7 | L = length(B),
8 | convert_rows(1, B),
9 | os:cmd("convert "++rows(L)++" -append "++Lo++"/temp_board.png"),
10 | os:cmd("mv "++Lo++"/temp_board.png "++Lo++"/board.png"),
11 | os:cmd("rm row*.png").
12 | format_number(N) ->
13 | lists:flatten(io_lib:format("~2.10.0B", [N])).
14 | rows(0) -> "";
15 | rows(N) ->
16 | R = rows(N-1),
17 | R ++ "row" ++ format_number(N) ++ ".png ".
18 | convert_rows(_, []) -> ok;
19 | convert_rows(N, [H|T]) ->
20 | os:cmd("convert " ++ make_row(H) ++ "+append row" ++ format_number(N) ++ ".png"),
21 | convert_rows(N+1, T).
22 | make_row([]) -> [];
23 | make_row([43|X]) -> constants:location() ++ "/star.png "++make_row(X);
24 | make_row([88|X]) -> constants:location() ++ "/black.png "++make_row(X);
25 | make_row([79|X]) -> constants:location() ++ "/white.png "++make_row(X);
26 | make_row([32|X]) -> constants:location() ++ "/empty.png "++make_row(X).
27 | test() ->
28 | B = [ " ",
29 | " ",
30 | " X ",
31 | " + + + ",
32 | " O ",
33 | " ",
34 | " ",
35 | " ",
36 | " ",
37 | " + + + ",
38 | " ",
39 | " ",
40 | " ",
41 | " ",
42 | " ",
43 | " + + + ",
44 | " ",
45 | " ",
46 | " "],
47 | draw(B).
48 |
--------------------------------------------------------------------------------
/src/get_board.erl:
--------------------------------------------------------------------------------
1 | -module(get_board).
2 | -export([doit/1, interpret/1]).
3 |
4 | doit(S) ->
5 | gen_tcp:send(S, <<"showboard\n">>),
6 | receive_loop(S, <<"">>).
7 | receive_loop(S, B) ->
8 | receive
9 | {tcp, S, X} ->
10 | C = <>,
11 | L = binary_to_list(C),
12 | Bool = full_board(L),
13 | if
14 | Bool -> L;
15 | true -> receive_loop(S, C)
16 | end
17 | after
18 | constants:wait_on_gnu() -> fail
19 | end.
20 |
21 |
22 |
23 | interpret(L) ->
24 | read2(read_board(strip_front(strip_captures(L)))).
25 | strip_captures([87,72,73,84,69|L]) -> %WHITE
26 | strip_captures2(L);
27 | strip_captures([66,76,65,67,75|L]) -> %BLACK
28 | strip_captures2(L);
29 | strip_captures([H|T]) -> [H|strip_captures(T)];
30 | strip_captures([]) -> [].
31 | strip_captures2([115,116,111,110,101,115|L]) -> %"stones"
32 | strip_captures(L);
33 | strip_captures2([_|T]) -> strip_captures2(T);
34 | strip_captures2([]) -> [].
35 |
36 | strip_front([65,32,66,32,67,32,68,32,69,32,70,32,71,32,72,32|T]) -> T; %A B C D E F G H
37 | strip_front([_|X]) -> strip_front(X).
38 |
39 |
40 |
41 |
42 |
43 | full_board(C) ->
44 | D = lists:reverse(C),
45 | full_2(D).
46 | full_2([84,32,83,32,82,32,81,32,80,32,79,32,78,32,77,32,76,32,75,32,74,32,72,32,71,32,70,32,69,32,68,32,67,32,66,32,65,32,32,32,10,49|_]) -> true; %the last line we care about looks like this: A B C D E F ...
47 | full_2([_|X]) -> full_2(X);
48 | full_2([]) -> false.
49 | read_board([Y|[_|X]]) when (Y < 58) and (Y > 48)-> %the digits 1-9.
50 | {Row, Rest} = lists:splitwith(fun(A) -> Y =/= A end, X),
51 | B = case hd(Row) of
52 | 32 -> Row;%32 is " "
53 | _ -> [32|Row]
54 | end,
55 | A = read_row(B),
56 | case Rest of
57 | [] -> [A];
58 | R -> [A|read_board(tl(tl(R)))]
59 | end;
60 | read_board([_|X]) -> read_board(X);
61 | read_board([]) -> [].
62 | read_row([]) -> [];
63 | read_row(R) ->
64 | case lists:splitwith(fun(A) -> A =/= hd(" ") end, R) of
65 | {_, [_|[D|X]]} -> [D|read_row(X)];
66 | {_,_} -> []
67 | end.
68 | read2([Row|T]) -> [read_row2(Row)|read2(T)];
69 | read2([]) -> [].
70 | read_row2([46|T]) -> [32|read_row2(T)]; % "."
71 | read_row2([C|T]) -> [C|read_row2(T)];
72 | read_row2([]) -> [].
73 |
--------------------------------------------------------------------------------