├── 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 | ![alt text](ggg.png?raw=true "beautiful") -------------------------------------------------------------------------------- /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 |
13 | 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 | --------------------------------------------------------------------------------