
/*************************************************************************\
*                                                                         *
*   Reversi - zapocet z Umele Inteligence                                 *
*                                                Martin Vyhnalek          *
*                                                                         *
\*************************************************************************/

%
% dynamic pedicates and board, menu, key, move definitions
%
?- dynamic board_pos/2.
?- dynamic board_players/2.
?- dynamic board_score/2.

board_size( 8 ).
board_size1( 7 ).
board_loc( 26, 3 ).
board_items( 1, "[]" ).
board_items( 2, "##" ).
%board_items( 3, "--" ).
board_items( _, "  " ).
board_chars( "+-++",
             "| ||",
             "+-++",
             "+-++" ).

menu_geom( 0, 0, 80, _ ).
menu_chars( "+-+",
            "| |",
            "+-+" ).

key_stone( [10,32] ).
key_calc( "C" ).
key_swap( "S" ).
key_new( "N" ).
key_quit( "Q" ).
key_refresh( "R" ).
key_move( 1, "1" ).
key_move( 2, "2jJ" ).
key_move( 3, "3" ).
key_move( 4, "4hH" ).
key_move( 6, "6lL" ).
key_move( 7, "7" ).
key_move( 8, "8kK" ).
key_move( 9, "9" ).

move_delta( 1, -1, +1 ).
move_delta( 2,  0, +1 ).
move_delta( 3, +1, +1 ).
move_delta( 4, -1,  0 ).
move_delta( 6, +1,  0 ).
move_delta( 7, -1, -1 ).
move_delta( 8,  0, -1 ).
move_delta( 9, +1, -1 ).

%
% for debugging print Lists in short form
%
portray( [H|T] ) :-
    !, length( [H|T], N ), write( '[' ), print( H ), write( ',...' ),
    write( N ), write( 'x]' ), !.

%
% Line  = [ Value ...Nx ]
% Board = [ Line ...Nx ]
% Pos   = pos( Player, Depth, X, Y, S1, S2, Board, BoardPrefferedPoss )
%

%
% alphabeta algorithm
%
alphabeta( Pos, Alpha, Beta, GoodPos, Val ) :-
    moves( Pos, PosList ), !,
    (PosList == [], !, static_val( Pos, Val );
    best( PosList, Alpha, Beta, GoodPos, Val )), !.
best( [Pos|PosList], Alpha, Beta, GoodPos, GoodVal ) :-
    alphabeta( Pos, Alpha, Beta, _, Val ),
    (good( PosList, Alpha, Beta, Pos, Val, GoodPos, GoodVal );
    bounds( Alpha, Beta, Pos, Val, NewAlpha, NewBeta ),
    best( PosList, NewAlpha, NewBeta, Pos1, Val1 ),
    better( Pos, Val, Pos1, Val1, GoodPos, GoodVal )).
good( [], _, _, Pos, Val, Pos, Val ) :- !.
good( _, Alpha, Beta, Pos, Val, Pos, Val ) :-
    min_move( Pos ), Val >= Beta, !; max_move( Pos ), Val =< Alpha, !.
better( Pos, Val, _Pos1, Val1, Pos, Val ) :-
    min_move( Pos ), Val >= Val1, !; max_move( Pos ), Val =< Val1, !.
better( _Pos, _Val, Pos1, Val1, Pos1, Val1 ).
bounds( Alpha, Beta, Pos, Val, Val, Beta ) :-
    min_move( Pos ), Val >= Alpha, !.
bounds( Alpha, Beta, Pos, Val, Alpha, Val ) :-
    max_move( Pos ), Val =< Beta, !.
bounds( Alpha, Beta, _Pos, _Val, Alpha, Beta ).

%
% max_to_move, min_to_move, static_val predicates
%
max_move( pos(1,_,_,_,_,_,_,_) ).
min_move( pos(2,_,_,_,_,_,_,_) ).
static_val( pos(_P,_D,_X,_Y,_S1,0,_B,_BP), 1 ) :- !.
static_val( pos(_P,_D,_X,_Y,0,_S2,_B,_BP), 0 ) :- !.
static_val( pos(_P,_D,_X,_Y,S1,S2,_B,pref(Corner,Border)), V ) :-
    sv_corner( Corner, S1, S2, TS1, TS2 ),
    sv_border( Border, TS1, TS2, NS1, NS2 ),
    V is NS1 / NS2, !.
sv_corner( [], S1, S2, S1, S2 ).
sv_corner( [1,_|T], S1, S2, NS1, NS2 ) :- !, TS1 is S1 + 30, sv_corner( T, TS1, S2, NS1, NS2 ).
sv_corner( [2,_|T], S1, S2, NS1, NS2 ) :- !, TS2 is S2 + 30, sv_corner( T, S1, TS2, NS1, NS2 ).
sv_corner( [0,1|T], S1, S2, NS1, NS2 ) :- !, TS2 is S2 + 30, sv_corner( T, S1, TS2, NS1, NS2 ).
sv_corner( [3,1|T], S1, S2, NS1, NS2 ) :- !, TS2 is S2 + 30, sv_corner( T, S1, TS2, NS1, NS2 ).
sv_corner( [0,2|T], S1, S2, NS1, NS2 ) :- !, TS1 is S1 + 30, sv_corner( T, TS1, S2, NS1, NS2 ).
sv_corner( [3,2|T], S1, S2, NS1, NS2 ) :- !, TS1 is S1 + 30, sv_corner( T, TS1, S2, NS1, NS2 ).
sv_corner( [_,_|T], S1, S2, NS1, NS2 ) :- sv_corner( T, S1, S2, NS1, NS2 ).
sv_border( [], S1, S2, S1, S2 ).
sv_border( [1|T], S1, S2, NS1, NS2 ) :- !, TS1 is S1 + 4, sv_border( T, TS1, S2, NS1, NS2 ).
sv_border( [2|T], S1, S2, NS1, NS2 ) :- !, TS2 is S2 + 4, sv_border( T, S1, TS2, NS1, NS2 ).
sv_border( [_|T], S1, S2, NS1, NS2 ) :- sv_border( T, S1, S2, NS1, NS2 ).

%
% moves( Pos, PosList ) predicate
%
moves( pos(_Player,3,_X,_Y,_S1,_S2,_Board,_BP), [] ) :- !.
moves( pos(Player,Depth,_X,_Y,S1,S2,Board,_BP), PosList ) :-
    get_opposite( Player, OP ), NDepth is Depth + 1,
%   write( [depth,is,Depth,!] ),
    m_check( Player, OP, NDepth, S1, S2, Board, Board, 0, 0, PosList ), !.

m_check( _P, _OP, _Depth, _S1, _S2, _Board, [], _X, _Y, [] ).
m_check( P, OP, Depth, S1, S2, Board, [[]|T], _X, Y, PosList ) :-
    !, NX is 0, NY is Y+1,
    m_check( P, OP, Depth, S1, S2, Board, T, NX, NY, PosList ).
m_check( P, OP, Depth, S1, S2, Board, [[3|L]|T], X, Y, [NPos|PosList] ) :-
    move_delta( 1, DX1, DY1 ), move_delta( 2, DX2, DY2 ),
    move_delta( 3, DX3, DY3 ), move_delta( 4, DX4, DY4 ),
    move_delta( 6, DX6, DY6 ), move_delta( 7, DX7, DY7 ),
    move_delta( 8, DX8, DY8 ), move_delta( 9, DX9, DY9 ),
    (m_chk( P, OP, X, Y, DX1, DY1, Board, A1 ); A1 = 0),
    (m_chk( P, OP, X, Y, DX2, DY2, Board, A2 ); A2 = 0),
    (m_chk( P, OP, X, Y, DX3, DY3, Board, A3 ); A3 = 0),
    (m_chk( P, OP, X, Y, DX4, DY4, Board, A4 ); A4 = 0),
    (m_chk( P, OP, X, Y, DX6, DY6, Board, A6 ); A6 = 0),
    (m_chk( P, OP, X, Y, DX7, DY7, Board, A7 ); A7 = 0),
    (m_chk( P, OP, X, Y, DX8, DY8, Board, A8 ); A8 = 0),
    (m_chk( P, OP, X, Y, DX9, DY9, Board, A9 ); A9 = 0),
    Amount is A1+A2+A3+A4+A6+A7+A8+A9, Amount > 0, !,
    recorded( tmp_board, board(NBoard,NBP) ),
    X0 is X-1, Y0 is Y-1, X2 is X+1, Y2 is Y+1,
    nth0( Y, Board, OL1 ), nth0( Y, NBoard, NL1 ), nth0( X, NL1, P ),
    (nth0( X0, OL1, 0 ), !, nth0( X0, NL1, 3 ); true),
    (nth0( X2, OL1, 0 ), !, nth0( X2, NL1, 3 ); true),
    (nth0( Y0, Board, OL0 ), nth0( Y0, NBoard, NL0 ),
     (nth0( X0, OL0, 0 ), !, nth0( X0, NL0, 3 ); true),
     (nth0( X,  OL0, 0 ), !, nth0( X,  NL0, 3 ); true),
     (nth0( X2, OL0, 0 ), !, nth0( X2, NL0, 3 ); true); true),
    (nth0( Y2, Board, OL2 ), nth0( Y2, NBoard, NL2 ),
     (nth0( X0, OL2, 0 ), !, nth0( X0, NL2, 3 ); true),
     (nth0( X,  OL2, 0 ), !, nth0( X,  NL2, 3 ); true),
     (nth0( X2, OL2, 0 ), !, nth0( X2, NL2, 3 ); true); true),
    m_app( P, X, Y, DX1, DY1, NBoard, A1 ),
    m_app( P, X, Y, DX2, DY2, NBoard, A2 ),
    m_app( P, X, Y, DX3, DY3, NBoard, A3 ),
    m_app( P, X, Y, DX4, DY4, NBoard, A4 ),
    m_app( P, X, Y, DX6, DY6, NBoard, A6 ),
    m_app( P, X, Y, DX7, DY7, NBoard, A7 ),
    m_app( P, X, Y, DX8, DY8, NBoard, A8 ),
    m_app( P, X, Y, DX9, DY9, NBoard, A9 ),
    m_unify( Board, NBoard ), m_score( P, S1, S2, Amount, NS1, NS2 ),
    NPos = pos(OP,Depth,X,Y,NS1,NS2,NBoard,NBP),
    !, NX is X+1, m_check( P, OP, Depth, S1, S2, Board, [L|T], NX, Y, PosList ).
m_check( P, OP, Depth, S1, S2, Board, [[_|L]|T], X, Y, PosList ) :-
    !, NX is X+1, m_check( P, OP, Depth, S1, S2, Board, [L|T], NX, Y, PosList ).

m_score( 1, S1, S2, A, NS1, NS2 ) :- !, NS1 is S1+A+1, NS2 is S2-A.
m_score( 2, S1, S2, A, NS1, NS2 ) :- !, NS1 is S1-A, NS2 is S2+A+1.

m_unify( [], [] ) :- !.
m_unify( [[]|T1], [[]|T2] ) :- !, m_unify( T1, T2 ).
m_unify( [[V|L1]|T1], [[V|L2]|T2] ) :- !, m_unify( [L1|T1], [L2|T2] ).
m_unify( [[_|L1]|T1], [[_|L2]|T2] ) :- !, m_unify( [L1|T1], [L2|T2] ).

m_chk( P, OP, X, Y, DX, DY, Board, Amount ) :-
    NX is X + DX, NY is Y + DY, nth0( NY, Board, Line ), nth0( NX, Line, Val ),
    m_chk0( P, OP, Val, NX, NY, DX, DY, Board, Amount ), !.
m_chk0( P, OP, P,  X, Y, DX, DY, Board, 0 ) :- !.
m_chk0( P, OP, OP, X, Y, DX, DY, Board, A ) :-
    !, m_chk( P, OP, X, Y, DX, DY, Board, NA ), A is NA + 1.
/*
m_chk( P, OP, X, Y, DX, DY, Board, Amount ) :-
    NX is X + DX, NY is Y + DY, nth0( NY, Board, Line ), nth0( NX, Line, Val ),
    (Val == P, !, Amount = 0;
     Val == OP, !, m_chk( P, OP, NX, NY, DX, DY, Board, A ), Amount is A+1), !.
*/

m_app( P, X, Y, DX, DY, Board, 0 ) :- !.
m_app( P, X, Y, DX, DY, Board, A ) :-
    NX is X + DX, NY is Y + DY, nth0( NY, Board, Line ), nth0( NX, Line, P ),
    !, NA is A - 1, m_app( P, NX, NY, DX, DY, Board, NA ).

%
% calc_move( P, X, Y ) predicate
%
calc_move( Player, X, Y ) :-
    recorded( tmp_board, board(Board,BP) ), make_act( Board, 0 ), !,
    board_score( S1, S2 ), tty_goto( 0, 20 ),
    time( alphabeta( pos(Player,0,_X,_Y,S1,S2,Board,BP), 0, 100,
               pos(_P,_D,X,Y,_S1,_S2,_Board,_BP), _Val ) ), !.

make_act( [], _ ).
make_act( [[]|T], K ) :- make_act( T, K ).
make_act( [[V|L]|T], K ) :- get_board( K, V ), NK is K+1, make_act( [L|T], NK ).

%
% initiate, make_template predicates
%
initiate :-
    board_size( N ), M is N * N - 1,
    K11 is (N//2-1)*(N+1), K12 is K11+1, K21 is K11+N, K22 is K21+1,
    K00 is K11-N-1, K03 is K00+3,
    K10 is K11-1,   K13 is K10+3,
    K20 is K21-1,   K23 is K20+3,
    K30 is K21+N-1, K33 is K30+3,
    (between( 0, M, K ),
        (recorded( K, _, Ref ), erase( Ref ), fail; recorda( K, 0 )),
    fail; true),
    (between( 0, M, K ),
        (between( K00, K03, K ), set_board( K, 3 );
         between( K10, K13, K ), set_board( K, 3 );
         between( K20, K23, K ), set_board( K, 3 );
         between( K30, K33, K ), set_board( K, 3 )),
    fail; true),
    set_pos( 0, 0 ), set_players( 1, 2 ), set_score( 0, 0 ),
    set_board( K11, 1 ), set_board( K12, 2 ),
    set_board( K21, 2 ), set_board( K22, 1 ),
    make_template, refresh.

make_template :-
    board_size( N ), M is N - 1, M1 is M - 1, length( Board, N ),
    mt1( Board, N ),
    nth0( 0, Board, Ln0 ), nth0( 1, Board, Ln1 ),
    nth0( M1, Board, LnM1 ), nth0( M, Board, LnM ),
    nth0( 0, Ln0, C00 ), nth0( 1, Ln1, B00 ),
    nth0( M, Ln0, C01 ), nth0( M1, Ln1, B01 ),
    nth0( 0, LnM, C10 ), nth0( 1, LnM1, B10 ),
    nth0( M, LnM, C11 ), nth0( M1, LnM1, B11 ),
    Corner = [C00,B00,C01,B01,C10,B10,C11,B11],
    nth0( 0, Board, [_I01,I02,I03,I04,I05,I06,I07,_I08] ),
    nth0( M, Board, [_IM1,IM2,IM3,IM4,IM5,IM6,IM7,_IM8] ),
    TBorder = [I02,I03,I04,I05,I06,I07,IM2,IM3,IM4,IM5,IM6,IM7],
    Board = [_|T], mt2( T, TBorder, Border ),
    (recorded( tmp_board, _, Ref ), erase( Ref ), fail; true),
    recorda( tmp_board, board(Board,pref(Corner,Border)) ), !.
mt1( [], _ ).
mt1( [H|T], N ) :- length( H, N ), mt1( T, N ).
mt2( [_], OldBorder, OldBorder ) :- !.
mt2( [[First|L]|T], OldBorder, NewBorder ) :-
    last( Last, L ), mt2( T, [First,Last|OldBorder], NewBorder ).


%
% set_board, set_pos, set_players, set_score, set_places predicates
%
set_board( K, V ) :-
    recorded( K, OldV, Ref ), erase( Ref ), recorda( K, V ),
    board_score( S1, S2 ), upd_score( S1, S2, OldV, V ), !.
get_board( K, V ) :-
    recorded( K, V ).
upd_score( S1, S2, 2, 1 ) :- NS1 is S1+1, NS2 is S2-1, set_score( NS1, NS2 ).
upd_score( S1, S2, 1, 2 ) :- NS1 is S1-1, NS2 is S2+1, set_score( NS1, NS2 ).
upd_score( S1, S2, 3, 1 ) :- NS1 is S1+1, set_score( NS1, S2 ).
upd_score( S1, S2, 3, 2 ) :- NS2 is S2+1, set_score( S1, NS2 ).
upd_score( _S1, _S2, _, 3 ).

get_opposite( 1, 2 ) :- !.
get_opposite( 2, 1 ) :- !.

set_pos( X, Y ) :-
    retractall( board_pos( _, _ ) ), assert( board_pos( X, Y ) ).

set_players( UID, CID ) :-
    retractall( board_players( _, _ ) ), assert( board_players( UID, CID ) ).

set_score( S1, S2 ) :-
    retractall( board_score( _, _ ) ), assert( board_score( S1, S2 ) ).
get_score( S1, S2 ) :- board_players( 1, 2 ), !, board_score( S1, S2 ).
get_score( S2, S1 ) :- !, board_score( S1, S2 ).

%
% show_board predicate
%
show_board :-
    board_size( N ), board_loc( BRX, BRY ), N1 is N - 1,
    board_chars( L0, L1, L2, L3 ),
    sb_frm_line( BRX, BRY, 0, N, L0 ), sb_val_line( BRX, BRY, 0, N, L1 ),
    (between( 1, N1, Y ),
        sb_frm_line( BRX, BRY, Y, N, L2 ), sb_val_line( BRX, BRY, Y, N, L1 ),
    fail; true),
    sb_frm_line( BRX, BRY, N, N, L3 ).

sb_frm_line( BRX, BRY, Y, N, [C0,C1,C2,C3] ) :-
    ABRY is BRY + 2 * Y, tty_goto( BRX, ABRY ),
    put( C0 ), put( C1 ), put( C1 ), N1 is N - 1,
    (between( 1, N1, _ ), put( C2 ), put( C1 ), put( C1 ), fail; true),
    put( C3 ), !.

sb_val_line( BRX, BRY, Y, N, [C0,_C1,C2,C3] ) :-
    ABRY is BRY + 2 * Y + 1, tty_goto( BRX, ABRY ),
    put( C0 ), sb_put_item( 0, Y, N ), N1 is N - 1,
    (between( 1, N1, X ), put( C2 ), sb_put_item( X, Y, N ), fail; true),
    put( C3 ), !.

sb_put_item( X, Y, N ) :-
    Key is X + Y * N, get_board( Key, Val ), board_items( Val, C ), put( C ), !.

%
% show_menu, show_msg predicate
%
show_menu :-
    show_it( "<SPACE>stone <h><j><k><l>moves <C>alc <S>wap <N>ew <Q>uit" ).

show_msg( user_not ) :-
    show_msg( "You cannot move. <OK>" ), !.
show_msg( comp_not ) :-
    show_msg( "I cannot move. <OK>" ), !.
show_msg( ilegal_pos ) :-
    show_msg( "Ilegal position. <OK>" ), !.
show_msg( balance ) :-
    get_score( US, CS ), US > CS, !, show_msg( "You won. <OK>" ), !.
show_msg( balance ) :-
    get_score( US, CS ), US < CS, !, show_msg( "I won. <OK>" ), !.
show_msg( balance ) :-
    show_msg( "Tie game. <OK>" ), !.
show_msg( S ) :-
    show_it( S ), get_single_char( _ ), !, show_menu.

show_it( T ) :-
    menu_geom( X, Y, SX, _ ), menu_chars( L0, L1, L2 ), Y1 is Y+1, Y2 is Y+2,
    show_it( X, Y, SX, L0 ), show_it( X, Y1, SX, L1 ), show_it( X, Y2, SX, L2 ),
    get_score( US, CS ), swritef( S, '| Score %w:%w', [US, CS] ),
    string_length( S, LenS ), XM is X+2, XS is X+SX-LenS-2,
    tty_goto( XS, Y1 ), write( S ), tty_goto( XM, Y1 ), put( T ), !.
show_it( X, Y, N, [C0,C1,C2] ) :-
    tty_goto(X,Y), put(C0), (between(3,N,_), put(C1), fail; true), put(C2).

%
% go, refresh, move_on, move_it, handle predicates
%
go :-
    tty_clear, initiate,
    repeat, move_on, get_single_char( C ), handle( C, Status ), Status == quit.

refresh :-
    show_menu, show_board, ttyflush.

move_on :-
    board_pos( X, Y ), board_loc( BX, BY ),
    TX is BX+3*X+1, TY is BY+2*Y+1, tty_goto( TX, TY ).

move_it( T ) :-
    board_pos( X, Y ), move_delta( T, DX, DY ), TNX is X + DX, TNY is Y + DY,
    mi_bound( TNX, NX ), mi_bound( TNY, NY ), set_pos( NX, NY ).
mi_bound( P, N ) :- board_size1( N ), P < 0.
mi_bound( P, 0 ) :- board_size1( N ), P > N.
mi_bound( P, P ).

handle( C, quit ) :- key_quit( L ), member( C, L ), tty_clear, !.
handle( C, ok ) :- key_new( L ), member( C, L ), tty_clear, initiate, !.
handle( C, ok ) :- key_refresh( L ), member( C, L ), tty_clear, refresh, !.
handle( C, ok ) :- key_stone( L ), member( C, L ), place_stone, !.
handle( C, ok ) :- key_calc( L ), member( C, L ), calculate_pos, !.
handle( C, ok ) :- key_swap( L ), member( C, L ), swap_players, !.
handle( C, ok ) :- key_move( T, L ), member( C, L ), move_it( T ), !.
%handle( C, ok ) :- tty_flash.

%
% place_stone, swap_players, calculate_pos predicates
%
place_stone :-
    board_players( 0, 0 ), !.
place_stone :-
    board_pos( X, Y ), board_players( UID, CID ),
    can_place( UID, CID, X, Y ), !, place_it( UID, CID, X, Y ),
    check_comp( UID, CID ).
place_stone :-
    show_msg( ilegal_pos ).

calculate_pos :-
    board_players( 0, 0 ), !.
calculate_pos :-
    board_players( UID, _ ), calc_move( UID, X, Y ), set_pos( X, Y ).

swap_players :-
    board_players( 0, 0 ), !.
swap_players :-
    board_players( UID, CID ), set_players( CID, UID ), comp_place.

check_comp( _UID, CID ) :-
    has_place( CID ), !, comp_place, !.
check_comp( UID, _CID ) :-
    has_place( UID ), !, show_msg( comp_not ), !;
    show_msg( balance ), set_players( 0, 0 ), !.

check_user( UID, _CID ) :-
    has_place( UID ), !.
check_user( _UID, CID ) :-
    has_place( CID ), !, show_msg( user_not ), comp_place, !;
    show_msg( balance ), set_players( 0, 0 ), !.

comp_place :-
    board_players( UID, CID ), calc_move( CID, X, Y ),
    place_it( CID, UID, X, Y ), check_user( UID, CID ), !.

%
% has_place( P ), can_place( P, OP, X, Y ), place_it( P, X, Y ) predicate
%
has_place( P ) :-
    board_size1( N ), get_opposite( P, OP ),
    between( 0, N, Y ), between( 0, N, X ), can_place( P, OP, X, Y ), !.

can_place( P, OP, X, Y ) :-
    board_size( N ), K is X + Y * N, get_board( K, 3 ),
    move_delta( _, DX, DY ), DK is DX + DY * N,
    pl_ok( P, OP, X,Y,K, DX,DY,DK, no, _Amount ), !.

place_it( P, OP, X, Y ) :-
    board_size( N ), K is X + Y * N, set_board( K, P ),
    move_delta( _, DX, DY ), DK is DX + DY * N,
    pl_ok( P, OP, X,Y,K, DX,DY,DK, ok, Amount ),
    between( 1, Amount, I ), AK is K + DK * I, set_board( AK, P ), fail.
place_it( _P, _OP, X, Y ) :-
    set_pos( X, Y ), refresh, !.

pl_ok( P, OP, X,Y,K, DX,DY,DK, Visited, Amount ) :-
    board_size1( N ), NX is X + DX, NY is Y + DY, NK is K + DK,
    between( 0, N, NX ), between( 0, N, NY ),
    pl_ok1( P, OP, NX,NY,NK, DX,DY,DK, Visited, Amount ), !.
pl_ok1( P, OP, X,Y,K, DX,DY,DK, ok, A ) :-
    get_board( K, 0 ), !, set_board( K, 3 ), fail.
pl_ok1( P, OP, X,Y,K, DX,DY,DK, yes, 0 ) :-
    get_board( K, P ).
pl_ok1( P, OP, X,Y,K, DX,DY,DK, _, A ) :-
    get_board( K, OP ), pl_ok( P, OP, X,Y,K, DX,DY,DK, yes, AA ), A is AA + 1.

%
% let's go.
%

?- go.

