% -*-prolog-*-
:- include('tplace.pl').

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mak_scores([[9, 2, 8, 7],
	    [2, 1, 3, 4],
	    [8, 3, 5, 6],
	    [7, 4, 6, 0]]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

make_score_sub2([], _, _, _).
make_score_sub2([Score|Scores], ScorePred, J1, I1) :-
    I2 is 9 - I1, J2 is 9 - J1,
    Pred1 =.. [ScorePred, I1, J1, Score],
    Pred2 =.. [ScorePred, I1, J2, Score],
    Pred3 =.. [ScorePred, I2, J1, Score],
    Pred4 =.. [ScorePred, I2, J2, Score],
    asserta(Pred1), asserta(Pred2), asserta(Pred3), asserta(Pred4),
    I3 is I1 + 1,
    make_score_sub2(Scores, ScorePred, J1, I3).

make_score_sub1([], _, _).
make_score_sub1([Line|Lines], ScorePred, J1) :-
    make_score_sub2(Line, ScorePred, J1, 1),
    J2 is J1 + 1,
    make_score_sub1(Lines, ScorePred, J2).

make_score(ScoresPred, ScorePred) :-
    Pred =.. [ScoresPred, Board],
    call(Pred),
    make_score_sub1(Board, ScorePred, 1).

:- initialization(
    (retractall(mak_score(_, _, _)),
     make_score(mak_scores, mak_score))
     ).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

/* 自分の石の数が最大になるように打つ */
player_most_sub1([], _, Result, Result).
player_most_sub1([(I, J, K)|Candidates], K1, Result1, Result2) :-
    (K > K1
     ->
     player_most_sub1(Candidates, K, [(I, J, K)], Result2)
     ;
     (K == K1
      ->
      player_most_sub1(Candidates, K1, [(I, J, K)|Result1], Result2)
      ;
      player_most_sub1(Candidates, K1, Result1, Result2))).

/* mak_score に従って、最大のスコアの場所に打つ */
player_mak(Board1, Stone, _, _, _, _, I, J) :-
    findall((I, J, K),
	    (member(I, [1, 2, 3, 4, 5, 6, 7, 8]),
	     member(J, [1, 2, 3, 4, 5, 6, 7, 8]),
	     flip_disc(Stone, Opponent),
	     place_disc(I, J, Stone, Opponent, Board1, _),
	     mak_score(I, J, K)),
	    Candidates1),
    player_most_sub1(Candidates1, 0, [], Candidates2),
    length(Candidates2, N),
    random(0, N, M),
    M1 is M+1,
    nth(M1, Candidates2, (I, J, _)),
    !.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

games_init(_, _).
games_end(_, _).
game_init(_, _).
game_end(_, _, _, _).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

connect_server(HostName,Address, InStream, OutStream) :-
     number_atom(Num, Address),
    socket('AF_INET', Socket),
    socket_connect(Socket, 'AF_INET'(HostName, Num), InStream, OutStream),
    asserta(player_stream(InStream,OutStream)).

/* それぞれ対応する述語を呼び出す */
games_sub(games_init(Who, Stone)) :- games_init(Who, Stone).
games_sub(games_end(Victories, Defeats)) :-
    games_end(Victories, Defeats),
    halt.
games_sub(game_init(Stone, Rest)) :- game_init(Stone, Rest).
games_sub(game_end(Board, Stone, Kifu, Result)) :-
    game_end(Board, Stone, Kifu, Result).
/* 思考ルーチンを呼び出して指し手を審判に通信する */
games_sub(turn(Board, Stone, N, Kifu, Rest, Start)) :-
    player_stream(InStream,OutStream),
    statistics(user_time,[Time1,_]),
    player_mak(Board, Stone, N, Kifu, Rest, Start, I, J),
    statistics(user_time,[Time2,_]),
    statistics(global_stack, [Used, Free]),
    Time is Time2 - Time1,
    format(OutStream, "~w.~n", [move(I, J, Time)]),
    flush_output(OutStream).

/* 審判に接続して試合を行う */
games :-
    argument_list([HostName,Address|REST]),
    !,
    repeat,
    (catch(connect_server(HostName,Address, InStream,OutStream), _, fail)
     ->
     true
     ;
     sleep(3),
     fail),
    !,
    repeat,
    read(InStream, Term),
    games_sub(Term),
    fail.

%:- initialization(games).
