Skip to Navigation

Prolog 5x5 tic-tac-toe code

  1. #!/usr/bin/pl -g "main." -s
  2. % 5x5 tic-tac-toe by Remigiusz 'lRem' Modrzejewski <http://lrem.net>
  3. % Distributed under the GPL, for more details see:  
  4. % http://lrem.net/pages/view/prolog_tic_tac_toe
  5.  
  6. boardsize(5).
  7. opponent(o,x).
  8. opponent(x,o).
  9. unfold(M, X, Y) :-
  10.     boardsize(S),
  11.     X is M mod S,
  12.     Y is (M-X)/S.
  13. % Initialize the board% {{{
  14. /*board(['.', '.', '.', '.', '.', '.',
  15.        '.', '.', '.', '.', '.', '.',
  16.        '.', '.', '.', '.', '.', '.',
  17.        '.', '.', '.', '.', '.', '.',
  18.        '.', '.', '.', '.', '.', '.',
  19.        '.', '.', '.', '.', '.', '.' ]).*/
  20. board(B) :-
  21.     boardsize(S),
  22.     F is S*S,
  23.     board(B, F).
  24. board([], 0) :- !.
  25. board(['.'|T], N) :-
  26.     N1 is N-1,
  27.     board(T, N1).
  28. % }}}
  29. % Show the board% {{{
  30. show(B) :- write(' 0123456'), nl, write(0), showloop(B, 0), write('0123456'), nl.
  31. showloop([], _).
  32. showloop([H|T], I) :-
  33.     boardsize(S),
  34.     I mod S =:= S-1,
  35.     L is (I-S+1)/S,
  36.     NL is (I+1)/S,
  37.     write(H), write(L), nl, write(NL),
  38.     I1 is I + 1,
  39.     showloop(T, I1), !.
  40. showloop([H|T], I) :-
  41.     write(H),
  42.     I1 is I + 1,
  43.     showloop(T, I1).
  44.  
  45. % }}}
  46. % Gets an index of array% {{{
  47. get([H|_], 0, H) :- !.
  48. get([_|T], N, R) :-
  49.     N1 is N-1,
  50.     get(T, N1, R).
  51. % }}}
  52. % Gets a position on board% {{{
  53. get(B, X, Y, R) :-
  54.     boardsize(S),
  55.     -1 < X, X < S, % Check whether inside the board
  56.     -1 < Y, Y < S,
  57.     N is X + S*Y,
  58.     get(B, N, R).
  59. % }}}
  60. % Sets an index of array% {{{
  61. set([_|T], 0, X, [X|T]) :- !.
  62. set([H|T], N, X, [H|R]) :-
  63.     N1 is N-1,
  64.     set(T, N1, X, R).
  65. % }}}
  66. % Sets a position on board% {{{
  67. set(B, X, Y, M, NB) :-
  68.     boardsize(S),
  69.     N is X + S*Y,
  70.     set(B, N, M, NB).
  71. % }}}
  72. % Counts how much points player P gets for the mark% {{{
  73. points(B, X, Y, P, R) :-
  74.     get(B, X, Y, M), M == '.', % Asserting it's legal to put it there
  75.     points(B, X, Y, P, 1, 0, R1),
  76.     points(B, X, Y, P, 0, 1, R2),
  77.     points(B, X, Y, P, 1, 1, R3),
  78.     points(B, X, Y, P, 1, -1, R4),
  79.     R is R1 + R2 + R3 + R4.
  80. points(B, X, Y, P, DX, DY, R) :-
  81.     points(B, X, Y, P, DX, DY, 1, R1),
  82.     MDX is -DX, MDY is -DY,
  83.     points(B, X, Y, P, MDX, MDY, 1, R2),
  84.     RS is R1 + R2 + 1,
  85.     points(RS, R).
  86. points(_, _, _, _, _,  _,  3, 0) :- !. % Search for half-lines no longer than 2
  87. points(B, X, Y, P, DX, DY, D, R) :-
  88.     X1 is X + DX*D,
  89.     Y1 is Y + DY*D,
  90.     get(B, X1, Y1, M),
  91.     M == P,
  92.     D1 is D+1,
  93.     points(B, X, Y, P, DX, DY, D1, R1),
  94.     R is R1 + 1, !.
  95. points(_, _, _, _, _,  _,  _, 0).
  96. points(1, 0) :- !.
  97. points(N, R) :- R is N-2.
  98. % }}}
  99. %Counts open lines in  the neighbourhood{{{
  100. nonblocking('.', _).
  101. nonblocking(A, A).
  102. open(B, X, Y, P, R) :-
  103.     get(B, X, Y, M), M == '.', % Asserting starting point is open
  104.     open(B, X, Y, P, 1, 0, R1),
  105.     open(B, X, Y, P, 0, 1, R2),
  106.     open(B, X, Y, P, 1, 1, R3),
  107.     open(B, X, Y, P, 1, -1, R4),
  108.     R is R1 + R2 + R3 + R4.
  109. open(B, X, Y, P, DX, DY, R) :-
  110.     open(B, X, Y, P, DX, DY, 1, R1),
  111.     MDX is -DX, MDY is -DY,
  112.     open(B, X, Y, P, MDX, MDY, 1, R2),
  113.     RS is R1 + R2 + 1,
  114.     open(RS, R).
  115. open(_, _, _, _, _,  _,  3, 0) :- !. % Search for half-lines no longer than 2
  116. open(B, X, Y, P, DX, DY, D, R) :-
  117.     X1 is X + DX*D,
  118.     Y1 is Y + DY*D,
  119.     get(B, X1, Y1, M),
  120.     nonblocking(M, P),
  121.     D1 is D+1,
  122.     open(B, X, Y, P, DX, DY, D1, R1),
  123.     R is R1 + 1, !.
  124. open(_, _, _, _, _,  _,  _, 0).
  125. open(1, 0) :- !.
  126. open(N, R) :- R is N-2.
  127. %}}}
  128. %The value function {{{
  129. value(B, P, M, R) :-
  130.     unfold(M, X, Y),
  131.     points(B, X, Y, P, RPM),
  132.     open(B, X, Y, P, ROM),
  133.     opponent(P, O),
  134.     points(B, X, Y, O, RPO),
  135.     open(B, X, Y, O, ROO),
  136.     R is 9*RPM + 9*RPO + 3*ROM + 1*ROO.
  137. nice(B, P, M) :-
  138.     value(B, P, M, R),
  139.     R > 17.
  140. %}}}
  141. %Moves generator{{{
  142. free(B, M) :-
  143.     get(B, M, R),
  144.     R == '.'.
  145. genmoves(B, P, ML) :-
  146.     genmoves(B, P, 0, ML, MC),
  147.     %write([MC, 'nice moves']), nl,
  148.     MC > 0, !.
  149. genmoves(B, P, ML) :-
  150.     %write('finding all free'), nl,
  151.     findfree(B, 0, ML).
  152. %genmoves(_, _, 36, [], 0) :- !.
  153. genmoves(_, _, N, [], 0) :-
  154.     boardsize(S),
  155.     N =:= S*S, !.
  156. genmoves(B, P, N, [N|T], MC) :-
  157.     nice(B, P, N),
  158.     N1 is N+1,
  159.     genmoves(B, P, N1, T, MC1),
  160.     MC is MC1+1, !.
  161. genmoves(B, P, N, T, MC) :-
  162.     N1 is N+1,
  163.     genmoves(B, P, N1, T, MC).
  164. findfree([], _, []).
  165. findfree([H|T], N, [N|RT]) :-
  166.     H == '.',
  167.     N1 is N+1,
  168.     findfree(T, N1, RT), !.
  169. findfree([H|T], N, RT) :-
  170.     N1 is N+1,
  171.     findfree(T, N1, RT).
  172. %}}}
  173. %Openings base{{{
  174. minimax(B, _, _, 12, 0) :-
  175.     boardsize(5),
  176.     free(B, 12), !.
  177. /*minimax(B, _, _, 7, 0) :-
  178.     boardsize(5),
  179.     free(B, 7), !.*/
  180. %}}}
  181. %The minimax search {{{
  182. %Board, player, depth, next best move, value
  183. minimax(B, P, 0, _, 0) :- !.
  184. minimax(B, P, D, M, V) :-
  185.     genmoves(B, P, ML),
  186.     choose(B, P, D, ML, M, V).
  187. choose(_, _, _, [], _, -999).
  188. choose(B, P, D, [H|T], M, V) :-
  189.     value(B, P, H, V1),
  190.     set(B, H, P, NB),
  191.     opponent(P, O),
  192.     D1 is D-1,
  193.     minimax(NB, O, D1, _, V2),
  194.     VH is V1 - V2,
  195.     choose(B, P, D, T, MT, VT),
  196.     max(VH, H, VT, MT, V, M).
  197. max(VH, H, VT, MT, VH, H) :-
  198.     VH > VT, !.
  199. max(_, _, VT, MT, VT, MT).
  200. %}}}
  201. turn(B, x, RX, RO) :-
  202.     show(B),
  203.     write('x coord:'), read(X),
  204.     write('y coord:'), read(Y),
  205.     points(B, X, Y, x, RX1),
  206.     set(B, X, Y, x, NB),
  207.     turn(NB, o, RX2, RO),
  208.     RX is RX1 + RX2, !.
  209.  
  210. turn(B, o, RX, RO) :-
  211.     show(B),
  212.     %write('x coord:'), read(X),
  213.     %write('y coord:'), read(Y),
  214.     minimax(B, o, 4, M, _),
  215.     unfold(M, X, Y),
  216.     points(B, X, Y, o, RO1),
  217.     set(B, X, Y, o, NB),
  218.     turn(NB, x, RX, RO2),
  219.     RO is RO1 + RO2, !.
  220.  
  221. turn(_, _, 0, 0).
  222.  
  223. main :-
  224.     board(B),
  225.     turn(B, x, RX, RO),
  226.     write([x, RX, points, o, RO, points]), nl,
  227.     /*set(B, 2, 0, o, NB1),
  228.     set(NB1, 2, 1, o, NB2),
  229.     points(NB2, 2, 2, o, R),
  230.     write(R), nl,
  231.     show(NB2),*/
  232.     halt.
  233. main :-
  234.     write(nowai),
  235.     halt.