Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -1,7 +1,7 @@
⎕IO0 t1 b1 c{Z[?Z0=]} ⍝ extract turn/board; cpu's move
y{3::'no' 'move (1-9): ' 0=[p12]: p 20 0} ⍝ your move
m{((-,)t)@(0,{1=t: y c})} ⍝ apply current player's move to board
w{/3=|+/(0 0B)(0 0B)BB3 3b} ⍝ has game been won?
d{' '' '(,' ',)/3 3'.XO'[0 1 ¯1b]} ⍝ display board
o{0b: 'XO'[1=t],' wins' 'tie'} ⍝ determine and print game outcome
g{o dm((w0~b))10¯1} ⍝ game; move & display until won or full
{⎕IO B T W WM0(90)¯1 0(7 56 448 73 146 292 273 8492) ⍝ board; turn; win flag; winning trios
_{B[{1=T:{3::'no''move (1-9): ' ⍝ your move
B[P¯1+12]=0:P20 0}
Z[?Z0=B]}]TT-T ⍝ cpu's move; switch turn
' '(,' ',)/3 3'.XO'[0 1 ¯1B] ⍝ show board
}{(~0B)W/3=|B+.WM} ⍝ repeat until won or full
W:'XO'[1=T],' wins''tie'} ⍝ print result

View file

@ -0,0 +1 @@
B[]val

View file

@ -0,0 +1 @@
B[]val

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@
VALUE ERROR

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@
20 0

View file

@ -0,0 +1 @@
{3::'no'20 0}

View file

@ -0,0 +1 @@
B[p¯1+12]

View file

@ -0,0 +1 @@
⎕signal 3

View file

@ -0,0 +1 @@
::

View file

@ -1 +1 @@
g{Sd m w S: 'XO'[1=t S],' wins' ~0b S: 'tie' S}10¯1
{{B[1=T:youcpu]T T-T display}{tied won} won:winnertie}

View file

@ -0,0 +1 @@
⎕signal

View file

@ -0,0 +1 @@
⎕signal

View file

@ -0,0 +1,7 @@
g{⎕io T0 ¯1c{Z[?Z0=]} ⍝ turn; cpu's move
y{3::'no''move (1-9):'0=[p¯1+12]:p20 0} ⍝ your move
m{{T-T}T@({1=T:yc})} ⍝ apply move to board; switch turn
w{/3=|+/(0 0B)(0 0B)BB3 3} ⍝ has game been won?
d{' '(,' ',)/3 3'.XO'[0 1 ¯1]} ⍝ display board
o{w:'XO'[1=T],' wins''tie'} ⍝ determine game outcome
o dm(w0~)90} ⍝ move & display until won or full

View file

@ -0,0 +1 @@
Sd mw S:'XO'[1=T],' wins'~0S:'tie'S}90

View file

@ -0,0 +1,8 @@
⎕IO B WM0(2 90)(7 56 448 73 146 292 273 8492) ⍝ the board and winning trios
{_{~:{3::'no''move (1-9): ' ⍝ your move
(B)[M¯1+12]:20 0B[0;M]1}
B[1;Z[?Z~B]]1} ⍝ cpu's move
_{(,' ',)/⎕AV[3 3(⎕AV'.XO')ׯ1B~B]} ⍝ show board after each cpu move
W/3=|B[;]+.WMF511=2B ⍝ test win and full conditions
_{⎕OFF' wins',{W:'XO'[]'the cat'}}(WF) ⍝ when game is over, exit and print winner
~}{0}1 ⍝ now it's the other player's turn

View file

@ -0,0 +1 @@
{if: then else}

View file

@ -0,0 +1 @@
7 56 448 73 146 292 273 84

View file

@ -0,0 +1,10 @@
7 56 448 73 146 292 273 8492
0 0 1 0 0 1 1 0
0 0 1 0 1 0 0 0
0 0 1 1 0 0 0 1
0 1 0 0 0 1 0 0
0 1 0 0 1 0 1 1
0 1 0 1 0 0 0 0
1 0 0 0 0 1 0 1
1 0 0 0 1 0 0 0
1 0 0 1 0 0 1 0

View file

@ -0,0 +1 @@
/3=|B[;]+.WINMASKS

View file

@ -0,0 +1 @@
WINMASKS

View file

@ -0,0 +1 @@
/3=|+/(0 0M)(0 0M)MM3 3B

View file

@ -0,0 +1 @@
{}{}

View file

@ -0,0 +1,124 @@
with Ada.Text_IO, Ada.Numerics.Discrete_Random;
-- can play human-human, human-computer, computer-human or computer-computer
-- the computer isn't very clever: it just chooses a legal random move
procedure Tic_Tac_Toe is
type The_Range is range 1 .. 3;
type Board_Type is array (The_Range, The_Range) of Character;
package Rand is new Ada.Numerics.Discrete_Random(The_Range);
Gen: Rand.Generator; -- required for the random moves
procedure Show_Board(Board: Board_Type) is
use Ada.Text_IO;
begin
for Row in The_Range loop
for Column in The_Range loop
Put(Board(Row, Column));
end loop;
Put_Line("");
end loop;
Put_Line("");
end Show_Board;
function Find_Winner(Board: Board_Type) return Character is
-- if 'x' or 'o' wins, it returns that, else it returns ' '
function Three_Equal(A,B,C: Character) return Boolean is
begin
return (A=B) and (A=C);
end Three_Equal;
begin -- Find_Winner
for I in The_Range loop
if Three_Equal(Board(I,1), Board(I,2), Board(I,3)) then
return Board(I,1);
elsif Three_Equal(Board(1,I), Board(2,I), Board(3,I)) then
return Board(1,I);
end if;
end loop;
if Three_Equal(Board(1,1), Board(2,2), Board (3,3)) or
Three_Equal(Board(3,1), Board(2,2), Board (1,3)) then
return Board(2,2);
end if;
return ' ';
end Find_Winner;
procedure Do_Move(Board: in out Board_Type;
New_Char: Character; Computer_Move: Boolean) is
Done: Boolean := False;
C: Character;
use Ada.Text_IO;
procedure Do_C_Move(Board: in out Board_Type; New_Char: Character) is
Found: Boolean := False;
X,Y: The_Range;
begin
while not Found loop
X := Rand.Random(Gen);
Y := Rand.Random(Gen);
if (Board(X,Y) /= 'x') and (Board(X,Y) /= 'o') then
Found := True;
Board(X,Y) := New_Char;
end if;
end loop;
end Do_C_Move;
begin
if Computer_Move then
Do_C_Move(Board, New_Char);
else -- read move;
Put_Line("Choose your move, " & New_Char);
while not Done loop
Get(C);
for Row in The_Range loop
for Col in The_Range loop
if Board(Row, Col) = C then
Board(Row, Col) := New_Char;
Done := True;
end if;
end loop;
end loop;
end loop;
end if;
end Do_Move;
The_Board : Board_Type := (('1','2','3'), ('4','5','6'), ('7','8','9'));
Cnt_Moves: Natural := 0;
Players: array(0 .. 1) of Character := ('x', 'o'); -- 'x' begins
C_Player: array(0 .. 1) of Boolean := (False, False);
Reply: Character;
begin -- Tic_Tac_Toe
-- firstly, ask whether the computer shall take over either player
for I in Players'Range loop
Ada.Text_IO.Put_Line("Shall " & Players(I) &
" be run by the computer? (y=yes)");
Ada.Text_IO.Get(Reply);
if Reply='y' or Reply='Y' then
C_Player(I) := True;
Ada.Text_IO.Put_Line("Yes!");
else
Ada.Text_IO.Put_Line("No!");
end if;
end loop;
Rand.Reset(Gen); -- to initalize the random generator
-- now run the game
while (Find_Winner(The_Board) = ' ') and (Cnt_Moves < 9) loop
Show_Board(The_Board);
Do_Move(The_Board, Players(Cnt_Moves mod 2), C_Player(Cnt_Moves mod 2));
Cnt_Moves := Cnt_Moves + 1;
end loop;
Ada.Text_IO.Put_Line("This is the end!");
-- finally, output the outcome
Show_Board (The_Board);
if Find_Winner(The_Board) = ' ' then
Ada.Text_IO.Put_Line("Draw");
else
Ada.Text_IO.Put_Line("The winner is: " & Find_Winner(The_Board));
end if;
end Tic_Tac_Toe;

View file

@ -1,6 +1,6 @@
len f[] 9
state = 0
gtextsize 14
gtextsize 13
#
proc init .
glinewidth 2
@ -52,31 +52,31 @@ proc rate &res &done .
if f[i] = 0 : cnt += 1
.
res *= cnt
done = 1
if res = 0 and cnt > 1 : done = 0
done = 0
if res <> 0 or cnt = 1 : done = 1
.
proc minmax player alpha beta &rval &rmov .
rate rval done
if done = 1
if player = 1 : rval = -rval
else
rval = alpha
start = random 9
mov = start
repeat
if f[mov] = 0
f[mov] = player
minmax (5 - player) (-beta) (-rval) val h
val = -val
f[mov] = 0
if val > rval
rval = val
rmov = mov
.
return
.
rval = alpha
start = random 1 9
mov = start
repeat
if f[mov] = 0
f[mov] = player
minmax (5 - player) (-beta) (-rval) val h
val = -val
f[mov] = 0
if val > rval
rval = val
rmov = mov
.
mov = mov mod 9 + 1
until mov = start or rval >= beta
.
mov = mov mod 9 + 1
until mov = start or rval >= beta
.
.
proc show_result val .
@ -91,36 +91,36 @@ proc show_result val .
.
state += 2
.
proc computer .
proc computer_turn .
minmax 4 -11 11 val mov
f[mov] = 4
draw mov
rate val done
state = 0
if done = 1 : show_result val
.
proc human .
mov = floor ((mouse_x - 6) / 28) + 3 * floor ((mouse_y - 16) / 28) + 1
if f[mov] = 0
f[mov] = 1
draw mov
state = 1
if done = 1
timer 0.5
else
state = 0
.
.
proc human_turn .
mov = floor ((mouse_x - 6) / 28) + 3 * floor ((mouse_y - 16) / 28) + 1
if f[mov] <> 0 : return
f[mov] = 1
draw mov
state = 1
timer 0.5
.
on timer
rate val done
if done = 1
show_result val
else
computer
computer_turn
.
.
on mouse_down
if state = 0
if mouse_x > 6 and mouse_x < 90 and mouse_y > 16
human
.
if state = 0 and mouse_x - 6 < 84 and mouse_y > 16
human_turn
elif state >= 2
state -= 2
init

View file

@ -0,0 +1,100 @@
include std/console.e
include std/text.e
include std/search.e
include std/sequence.e
sequence board
sequence players = {"X","O"}
function DisplayBoard()
for i = 1 to 3 do
for j = 1 to 3 do
printf(1,"%s",board[i][j])
if j < 3 then
printf(1,"%s","|")
end if
end for
if i < 3 then
puts(1,"\n-----\n")
else
puts(1,"\n\n")
end if
end for
return 1
end function
function CheckWinner()
sequence temp = board
for a = 1 to 2 do
for i = 1 to 3 do
if equal({"X","X","X"},temp[i]) then
puts(1,"X wins\n\n")
return 1
elsif equal({"O","O","O"},temp[i]) then
puts(1,"O wins\n\n")
return 1
end if
end for
temp = columnize(board)
end for
if equal({"X","X","X"},{board[1][1],board[2][2],board[3][3]}) or
equal({"X","X","X"},{board[1][3],board[2][2],board[3][1]}) then
puts(1,"X wins\n")
return 1
elsif equal({"O","O","O"},{board[1][1],board[2][2],board[3][3]}) or
equal({"O","O","O"},{board[1][3],board[2][2],board[3][1]}) then
puts(1,"O wins\n")
return 1
end if
if moves = 9 then
puts(1,"Draw\n\n")
return 1
end if
return 0
end function
integer turn, row, column, moves
sequence replay
while 1 do
board = repeat(repeat(" ",3),3)
DisplayBoard()
turn = rand(2)
moves = 0
while 1 do
while 1 do
printf(1,"%s's turn\n",players[turn])
row = prompt_number("Enter row: ",{})
column = prompt_number("Enter column: ",{})
if match(board[row][column]," ") then
board[row][column] = players[turn]
moves += 1
exit
else
puts(1,"Space already taken - pick again\n")
end if
end while
DisplayBoard()
if CheckWinner() then
exit
end if
if turn = 1 then
turn = 2
else
turn = 1
end if
end while
replay = lower(prompt_string("Play again (y/n)?\n\n"))
if match(replay,"n") then
exit
end if
end while

View file

@ -1,5 +1,5 @@
'`c t b'=. (?@#{])@([:I.0=b)`{.`}. NB. cpu's move; extract turn/board
i=. (0=]{b@[) ::0 *: ]e.i.@9 NB. invalid posn? (x: state; y: posn)
i=. (0=]{b@[) ::0 *: ]e.i.@9 NB. invalid posn? (x: state; y: posn)
y=. [ ($:@[ echo@'no')^:i _1+0".1!:1@1@echo@'move (1-9):' NB. your move
m=. (-,])@t [`(0,1+c`y@.(1=t)@])} ] NB. apply current player's move to board
o=. 'tie'"_`(' wins',~ {&'.XO'@-@t)@.w NB. print game outcome

View file

@ -0,0 +1,89 @@
# The state of the game is represented as a vector of moves made so far
const TTT = Vector{Int}
@enum Role N X O # N = 0, neither X nor O
role(turn::Int) = isodd(turn) ? X : O
# game state functions:
next_role(moves::TTT) = role(length(moves)+1)
available(moves::TTT) = setdiff(1:9, moves)
function winner(moves::TTT)
wintriples = [
[1, 2, 3], [4, 5, 6], [7, 8, 9], # rows
[1, 4, 7], [2, 5, 8], [3, 6, 9], # columns
[1, 5, 9], [3, 5, 7] ] # diagonals
turn = length(moves); XorO = role(turn)
inmoves(triple) = all((moves[Int(XorO):2:end]), triple)
turn 5 && any(inmoves, wintriples) && return XorO
N
end
# scoring a state of the game with the recursive negamax algorithm
negamax(moves::TTT) = winner(moves) N ? 1 : length(moves) == 9 ? 0 :
-maximum(negamax([moves; move]) for move available(moves))
scored_options(moves::TTT) =
Dict(move => negamax([moves; move]) for move available(moves))
# players of X and O with different intelligence
abstract type Player end
struct RandomBot <: Player end
select_move(::RandomBot, moves::TTT) = rand(available(moves))
struct NegamaxBot <: Player end
function select_move(::NegamaxBot, moves::TTT)
opts = scored_options(moves)
maxscore = maximum(values(opts))
rand([move for (move, score) opts if score == maxscore])
end
struct Human <: Player name::String end
function select_move(player::Human, moves::TTT)
move = 0
while move available(moves)
print(player, " as ", next_role(moves), ", enter your move: ")
move = try parse(Int, readline()) catch; 0 end
end
move
end
Base.show(io::IO, player::Player) =
print(io, player isa Human ? player.name : typeof(player))
function displayboard(moves::TTT, hints = false)
reset = "\e[0m"; bold = reset * "\e[1m"; faint = reset * "\e[2m"
board = fill(" ", 9)
fillmove((i, move)) = board[move] = bold * repr(role(i)) * faint
foreach(fillmove, enumerate(moves))
fillscore((move, score)) =
board[move] = isone(score) ? "+" : iszero(score) ? "·" : "-"
hints && foreach(fillscore, scored_options(moves))
matrix = reshape([n*m for (n, m) in zip("¹²³⁴⁵⁶⁷⁸⁹", board)], 3, 3)
to_row(col) = join(col, "")
rows = join(to_row.(eachcol(matrix)), "\n───┼───┼───\n")
println(faint, " ╷ ╷\n", rows, "\n ╵ ╵", reset)
end
function ttt(Xplayer::Player, Oplayer::Player; hints = true)
moves = TTT(); cast = Dict(X => Xplayer, O => Oplayer)
println("\n","-"^40,"\nLet's play TicTacToe")
println("Cast: X => $Xplayer, O => $Oplayer\n", "-"^40)
while winner(moves) == N && length(moves) < 9
displayboard(moves, hints)
XorO = next_role(moves)
player = cast[XorO]
move = select_move(player, moves)
player isa Human ||
println(player, " as ", XorO, " plays move: ", move)
push!(moves, move)
end
displayboard(moves)
XorO = winner(moves)
println( XorO == N ? "It's a draw!" :
cast[XorO] isa Human ? "Congratulations, $(cast[XorO])! You win!" :
"$player as $XorO wins!" )
end
ttt(RandomBot(), NegamaxBot(); hints = false)
ttt(RandomBot(), Human("Alice"))

View file

@ -0,0 +1,41 @@
# the functions provided above are mandatory
function result_distribution(moves::TTT, casts::Dict{Role, Player})
w = winner(moves)
distribution = Dict(p => 0//1 for p in instances(Role))
if w N
distribution[w] = 1//1
return 1, 1, distribution
elseif length(moves) == 9
distribution[N] = 1//1
return 0, 1, distribution
else
scores = [result_distribution([moves; move], casts)
for move in setdiff(1:9, moves)]
maxscore = maximum(s[1] for s in scores)
p = role(length(moves)+1)
casts[p] isa NegamaxBot && filter!(s -> s[1] == maxscore, scores)
n = length(scores)
distribution = Dict(p => sum(s[3][p] for s in scores) // n for p in instances(Role))
return -maxscore, sum(s[2] for s in scores), distribution
end
end
function bot_statistics()
casts = [RandomBot(), NegamaxBot()]
combinations = Dict{Role, Player}[Dict(X => x, O => o) for x in casts for o in casts]
println("--------------------------------------------------------------")
println(" as X - as O | games | draws X wins O wins")
println("--------------------------------------------------------------")
for combi in combinations
distrib = result_distribution(Int[], combi)
print("$(lpad(combi[X], 10)) - $(rpad(combi[O], 10)) | ", lpad(distrib[2], 6), " | ")
for role in [N, X, O]
print(" $(lpad(round(100 * distrib[3][role], digits=1), 5))% ")
end
println()
end
println("--------------------------------------------------------------")
end
bot_statistics()

View file

@ -2,6 +2,6 @@ b::2 9#0; WINMASKS::((9#2)\)'7 56 448 73 146 292 273 84 / the board a
{1}{({`1:"MOVE: ";$[(|/b)m:(`I$-1_1:`)-1;o`0:"NO";b[0;m]::1]} / your move
{b[1;*1?&~|/b]::1})[x;] / cpu's move
x{`0:" "/'`c$3 3#|/"XO*"*b,,~|/b}/0 / show board after each move
w:|/3=0^WINMASKS(+/&)\:b x;t:511=2/|/b / test win and tie conditions
$[w|t;{`0:x," won";`exit 0}("XO"x;"the cat")t;] / when game is over, exit and print winner
w:|/3=0^WINMASKS(+/&)\:b x;f:511=2/|/b / test win and full conditions
$[w|f;[`0:("the cat";"XO"x)[w]," won";`exit 0];] / when game is over, exit and print winner
~x}/1 / now it's other player's turn

View file

@ -0,0 +1,90 @@
local player_O, blank, player_X = -1, 0, 1
local show_tile = {[player_O]="O", [blank]="-", [player_X]="X"}
function valid_pos_Q(pos)
return type(pos) == "number" and pos%1 == 0 and 1 <= pos and pos <= 9
end
function member_Q(arr, e) -- Does `arr` contain `e`?
for _, val in ipairs(arr) do
if val == e then return true end
end
return false
end
function full_Q(board) return not member_Q(board, blank) end
function sum(arr, idxs)
local result = 0
for _,i in ipairs(idxs) do result = result + arr[i] end
return result
end
-- rcd stands for rows, columns, and diagonals
local rcd = {{1,2,3},{4,5,6},{7,8,9}, {1,4,7},{2,5,8},{3,6,9}, {1,5,9},{3,5,7}}
function won_Q(board)
for _,idxs in ipairs(rcd) do
if math.abs(sum(board, idxs)) == 3 then
return true
end -- if
end -- for
return false
end
function you(board)
local position
repeat
io.write("Enter a move(1-" .. 9 .. "): ")
position = tonumber(io.read("*line"))
until valid_pos_Q(position) and board[position] == blank
return position
end
function cpu(board)
for position, value in ipairs(board) do
if value == blank then return position end
end
end
function pos(board) -- a players takes a turn, returns chosen position
if board[0] == player_O then
return cpu(board)
else
return you(board)
end
end
function move(board)
assert(not full_Q(board))
local position = pos(board)
board[position] = board[0]
board[0] = -board[0] -- toggle whose turn
return board
end
function show(board)
for key, val in ipairs(board) do
io.write(show_tile[val] .. " ")
if key % 3 == 0 then io.write"\n" end
end -- for
io.write"\n"
end
-- board[0] indicates whose turn it is
local the_board = { [0]=player_O }
for i = 1, 9 do the_board[i] = blank end
repeat
move(the_board)
show(the_board)
until won_Q(the_board) or full_Q(the_board)
if won_Q(the_board) then
print (show_tile[-the_board[0]], "wins!")
elseif full_Q(the_board) then
print("tie!")
else
print("incomplete game")
assert(false) -- this should be logically impossible
end -- if

View file

@ -0,0 +1,190 @@
#!/usr/bin/env luajit
ffi=require"ffi"
local function printf(fmt,...) io.write(string.format(fmt, ...)) end
local board="123456789" -- board
local pval={1, -1} -- player 1=1 2=-1 for negamax
local pnum={} for k,v in ipairs(pval) do pnum[v]=k end
local symbol={'X','O'} -- default symbols X and O
local isymbol={} for k,v in pairs(symbol) do isymbol[v]=pval[k] end
math.randomseed(os.time()^5*os.clock()) -- time-seed the random gen
local random=math.random
-- usage of ffi variables give 20% speed
ffi.cdef[[
typedef struct{
char value;
char flag;
int depth;
}cData;
]]
-- draw the "board" in the way the numpad is organized
local function draw(board)
for i=7,1,-3 do
print(board:sub(i,i+2))
end
end
-- pattern for win situations
local check={"(.)...%1...%1","..(.).%1.%1..",
"(.)%1%1......","...(.)%1%1...","......(.)%1%1",
"(.)..%1..%1..",".(.)..%1..%1.","..(.)..%1..%1",
}
-- calculate a win situation for which player or draw
local function win(b)
local sub
for i=1,#check do
sub=b:match(check[i])
if sub then break end
end
sub=isymbol[sub]
return sub or 0
end
-- input only validate moves of not yet filled positions
local function input(b,player)
char=symbol[pnum[player]]
local inp
repeat
printf("Player %d (\"%s\") move: ",pnum[player],char)
inp=tonumber(io.read()) or 0
until inp>=1 and inp<=9 and b:find(inp)
b=b:gsub(inp,char)
return b,inp
end
-- ask how many human or AI players
local function playerselect()
local ai={}
local yn
for i=1,2 do
repeat
printf("Player %d human (Y/n)? ", i) yn=io.read():lower()
until yn:match("[yn]") or yn==''
if yn=='n' then
ai[pval[i]]=true
printf("Player %d is AI\n", i)
else
printf("Player %d is human\n", i)
end
end
return ai
end
local function endgame()
repeat
printf("\nEnd game? (y/n)? ", i) yn=io.read():lower()
until yn:match("[yn]")
if yn=='n' then
return false
else
printf("\nGOOD BYE PROFESSOR FALKEN.\n\nA STRANGE GAME.\nTHE ONLY WINNING MOVE IS\nNOT TO PLAY.\n\nHOW ABOUT A NICE GAME OF CHESS?\n")
return true
end
end
-- AI Routine
local function shuffle(t)
for i=#t,1,-1 do
local rnd=random(i)
t[i], t[rnd] = t[rnd], t[i]
end
return t
end
-- move generator
local function genmove(node, color)
return coroutine.wrap(function()
local moves={}
for m in node:gmatch("%d") do
moves[#moves+1]=m
end
shuffle(moves) -- to make it more interesting
for _,m in ipairs(moves) do
local child=node:gsub(m,symbol[pnum[color]])
coroutine.yield(child, m)
end
end)
end
--[[
Negamax with alpha-beta pruning and table caching
]]
local cache={}
local best, aimove, tDepth
local LOWERB,EXACT,UPPERB=-1,0,1 -- has somebody an idea how to make them real constants?
local function negamax(node, depth, color, α, β)
color=color or 1
α=α or -math.huge
β=β or math.huge
-- check for cached node
local αOrg=α
local cData=cache[node]
if cData and cData.depth>=depth and depth~=tDepth then
if cData.flag==EXACT then
return cData.value
elseif cData.flag==LOWERB then
α=math.max(α,cData.value)
elseif cData.flag==UPPERB then
β=math.min(β,cData.value)
end
if α>=β then
return cData.value
end
end
local winner=win(node)
if depth==0 or winner~=0 then
return winner*color
end
local value=-math.huge
for child,move in genmove(node, color) do
value=math.max(value, -negamax(child, depth-1, -color, -β, -α))
if value>α then
α=value
if depth==tDepth then
best=child
aimove=move
end
end
if α>=β then break end
end
-- cache known data
--cData={} -- if you want Lua tables instead of ffi you can switch the two lines here, costs 20% speed
cData=ffi.new("cData")
cData.value=value
if value<=αOrg then
cData.flag=UPPERB
elseif value>=β then
cData.flag=LOWERB
else
cData.flag=EXACT
end
cData.depth=depth
cache[node]=cData
return α
end
-- MAIN
do
local winner,value
local score={[-1]=0, [0]=0, [1]=0}
repeat
print("\n TIC-TAC-TOE\n")
local aiplayer=playerselect()
local player=1
board="123456789"
for i=1,#board do
draw(board)
tDepth=10-i
if aiplayer[player] then
negamax(board, tDepth, player, -math.huge, math.huge)
board=best
printf("AI %d moves %s\n", pnum[player], aimove)
else
board=input(board,player)
end
winner=win(board)
if winner~=0 then break end
player=-player
end
score[winner]=score[winner]+1
if winner and winner~=0 then
printf("*** Player %d (%s) has won\n", pnum[winner], symbol[pnum[winner]])
else
printf("*** No winner\n")
end
printf("Score Player 1: %d Player 2: %d Draw: %d\n",score[1],score[-1],score[0])
draw(board)
until endgame()
end

View file

@ -1,6 +1,6 @@
\( Simple (not perfect) solver for tic-tac-toe
The state is a 9-element vector, with
0 for free, 1 for user; 4 for machine
0 for free, 1 for user; 4 for machine
Lanes are used to check if there is a win or near-win:
1 2 3
4 5 6
@ -31,58 +31,58 @@ main (parms):+
state.lanes =: ((1, 2, 3), (4, 5, 6), (7, 8, 9), (1, 4, 7), (2, 5, 8), (3, 6, 9), (1, 5, 9), (3, 5, 7))
state.free =: 9
?* state.free > 0
show state
set user state
show state
check end state
? state.free > 0
step move state
check end state
show state
set user state
show state
check end state
? state.free > 0
step move state
check end state
show state
check end (state):
?# t =: tuple state.lanes give values
c =: sum of places state lane t
\ print c, t
? c = 3:
print "You win:", t
?# i =: tuple t give values
state[i] =: '+'
state.free =: 0
:>
? c = 12:
print "I win:", t
?# i =: tuple t give values
state[i] =: '*'
state.free =: 0
:>
c =: sum of places state lane t
\ print c, t
? c = 3:
print "You win:", t
?# i =: tuple t give values
state[i] =: '+'
state.free =: 0
:>
? c = 12:
print "I win:", t
?# i =: tuple t give values
state[i] =: '*'
state.free =: 0
:>
? state.free = 0
print "This is a draw."
print "This is a draw."
step move (state):
?# t =: tuple state.lanes give values
c =: sum of places state lane t
? c = 2
set state at t
:>
? c = 8
set state at t
:>
? set state at 5
:>
? set state at shuffle 1, 3, 7, 9
:>
? set state at shuffle 2, 4, 6, 8
:>
c =: sum of places state lane t
? c = 2
set state at t
:>
? c = 8
set state at t
:>
? set state at 5
:>
? set state at shuffle 1, 3, 7, 9
:>
? set state at shuffle 2, 4, 6, 8
:>
set (state) at (points):
? ~ is points tuple
points =: points, () \ make it a tuple
points =: points, () \ make it a tuple
?# i =: tuple points give values
? state[i] = 0
state[i] =: 4
print "my move:", i
:> ?+
? state[i] = 0
state[i] =: 4
print "my move:", i
:> ?+
:> ?-
shuffle (points):
@ -94,40 +94,40 @@ shuffle (points):
sum of places (state) lane (tpl):
s =: 0
?# i =: tuple tpl give values
v =: state[i]
? v ~= 0
s =+ state[i]
v =: state[i]
? v ~= 0
s =+ state[i]
:> s
set user (state):
?*
print "your move: " nonl
c =: file stream () get
? c = 'q' || c = 'x'
system exit 0
n =: string c as integer else ()
? n = () || n < 1 || n > state.Count
print "Invalid input, " nonl
?^
? state[n] = 0
state[n] =: 1
:>
print "not free; retry " nonl
print "your move: " nonl
c =: file stream () get
? c = 'q' || c = 'x' || c = ()
system exit 0
n =: string c as integer else ()
? n = () || n < 1 || n > state.Count
print "Invalid input, " nonl
?^
? state[n] = 0
state[n] =: 1
:>
print "not free; retry " nonl
show (state):
state.free =:0
?# i =: from 1 upto 9
v =: state[i]
w =: v
? v = 0
w =: i
state.free =+ 1
? v = 1
w =: 'X'
? v = 4
w =: 'O'
print ' ' _ w nonl
? i = 3 || i = 6
print ''
v =: state[i]
w =: v
? v = 0
w =: i
state.free =+ 1
? v = 1
w =: 'X'
? v = 4
w =: 'O'
print ' ' _ w nonl
? i = 3 || i = 6
print ''
print ''
\ state.free=0 is used to terminate the central loop

View file

@ -0,0 +1,26 @@
Threes ← [0_1_2 3_4_5 6_7_8 0_3_6 1_4_7 2_5_8 0_4_8 2_4_6]
Moves ← ≡(⊂□)⊙(¤□)⊸(≡⍜⊡⋅∘ ⊙¤⊙⊙¤⊚⊸⌕@_)⊙(⨬(@X|@O)=@X)∩°□°⊟
RandomMove ← [⊡]⌊×⚂⊸⧻ Moves
WasWin ← /↥⊢≡(≡/↧˜⌕⊏Threes)¤∩°□°⊟
IsDraw ← ¬/↥⌕@_°□⊢
Done ← ↥⊃IsDraw WasWin
[] # Score accumulator
⍥( # They start
⊢path(RandomMove|Done){"_________" @X}
# Score each of our moves as winning or losing, save.
⨬(◌|⊂≡⊟⊃(≡⊢▽⊸≡◇(=@X°□⊣)|¤□⨬(¯1|1)=@X°□⊣⊣))⊸(¬IsDraw⊣)
) 3000
# Build map from moves and accumulated scores
¤map⍜⍉°⊟⊕(⊂⊃(⊢°□⊢|/+≡◇⊣))⊛⊸≡⊢
# Play our *best* moves against their *random* moves.
BestMove ← |1 ⨬(RandomMove|[⊢]▽=⊸/↥◡≡(°□⬚0get⊢)Moves)=@O°□⊸⊣
# One demo game
&p"Sample Game: 'O' starts, playing randomly.\n'X' is trained."
≡&p↘1⊢path(BestMove|Done){"_________" @X}
&p"Thirty results, showing X/O as winner or '=' for draw."
⍥( # Let them start
⊢path(BestMove|Done){"_________" @X}
&p⊟∩□⍥⊙⋅@=¬/↥⊸⌕@_°□°⊟⊣
)30

View file

@ -1,110 +1,116 @@
import rand
import os
__global (
b = [3][3]int{}
best_i = 0
best_j = 0
)
struct Board {
mut:
bay [3][3]int
best_i int
best_j int
}
fn main() {
mut brd := Board{}
mut user := false
mut yn :=''
mut yn :=""
for {
user = !user
print(game(user))
print(game(mut brd, user))
for (yn != "y" ) && (yn != "n") {
yn = os.input('Play again y/n: ').str().to_lower()
yn = os.input("Play again y/n: ").str().to_lower()
}
if yn != "y" {exit(0)} else {yn =''}
println('')
if yn != "y" {exit(0)} else {yn =""}
println("")
}
}
fn game(user bool) string {
mut u := user
mut move, mut my_move, mut i, mut j, mut win := 0, 0, 0, 0, 0
for k in 0..3 {
for l in 0..3 {
if b[k][l] != 0 {b[k][l] = 0}
fn game(mut brd Board, user bool) string {
mut ubl := user
mut move, mut my_move, mut ir, mut jir, mut win := 0, 0, 0, 0, 0
for kal in 0..3 {
for lal in 0..3 {
if brd.bay[kal][lal] != 0 {brd.bay[kal][lal] = 0}
}
}
print("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9\n")
print("You have O, I have X.\n\n")
for k in 1..9 {
if u {
for kal in 1..9 {
if ubl {
for move !in [1,2,3,4,5,6,7,8,9] {
move = os.input('your move: ').int()
move = os.input("your move: ").int()
}
move--
i = move / 3
j = move % 3
if b[i][j] != 0 {continue}
b[i][j] = 1
ir = move / 3
jir = move % 3
if brd.bay[ir][jir] != 0 {continue}
brd.bay[ir][jir] = 1
move = 0
}
if !u {
if k == 1 {
best_i = (rand.int_in_range(1, 9) or {exit(1)}) % 3
best_j = (rand.int_in_range(1, 9) or {exit(1)}) % 3
if !ubl {
if kal == 1 {
brd.best_i = (rand.int_in_range(1, 9) or {exit(1)}) % 3
brd.best_j = (rand.int_in_range(1, 9) or {exit(1)}) % 3
}
else {test_move(-1, 0)}
b[best_i][best_j] = -1
my_move = best_i * 3 + best_j + 1
else {test_move(mut brd, -1, 0)}
brd.bay[brd.best_i][brd.best_j] = -1
my_move = brd.best_i * 3 + brd.best_j + 1
println("My move: $my_move")
}
show_board()
win = check_winner()
show_board(mut brd)
win = check_winner(mut brd)
println("win res: $win")
if win != 0 {
if win == 1 {return "You win" + ".\n\n"}
else {return "I win" + ".\n\n"}
}
u = !u
ubl = !ubl
}
return "A draw.\n\n"
}
fn check_winner() int {
for i in 0..3 {
if b[i][0] != 0 && b[i][1] == b[i][0] && b[i][2] == b[i][0] {return b[i][0]}
if b[0][i] != 0 && b[1][i] == b[0][i] && b[2][i] == b[0][i] {return b[0][i]}
fn check_winner(mut brd Board) int {
for ial in 0..3 {
if brd.bay[ial][0] != 0 && brd.bay[ial][1] == brd.bay[ial][0] && brd.bay[ial][2] == brd.bay[ial][0] {
return brd.bay[ial][0]
}
if brd.bay[0][ial] != 0 && brd.bay[1][ial] == brd.bay[0][ial] && brd.bay[2][ial] == brd.bay[0][ial] {
return brd.bay[0][ial]
}
}
if b[1][1] == 0 {return 0}
if b[1][1] == b[0][0] && b[2][2] == b[0][0] {return b[0][0]}
if b[1][1] == b[2][0] && b[0][2] == b[1][1] {return b[1][1]}
if brd.bay[1][1] == 0 {return 0}
if brd.bay[1][1] == brd.bay[0][0] && brd.bay[2][2] == brd.bay[0][0] {return brd.bay[0][0]}
if brd.bay[1][1] == brd.bay[2][0] && brd.bay[0][2] == brd.bay[1][1] {return brd.bay[1][1]}
return 0
}
fn show_board() {
fn show_board(mut brd Board) {
mut t := "X O"
for i in 0..3 {
for j in 0..3 {
print("${t[b[i][j] + 1].ascii_str()} ")
for ial in 0..3 {
for jal in 0..3 {
print("${t[brd.bay[ial][jal] + 1].ascii_str()} ")
}
println('')
println("")
}
println("-----")
}
fn test_move(value int, depth int) int {
fn test_move(mut brd Board, value int, depth int) int {
mut best := -1
mut changed := 0
mut score := check_winner()
mut score := check_winner(mut brd)
if score != 0 {
if score == value {return 1} else {return -1}
}
for i in 0..3 {
for j in 0..3 {
if b[i][j] != 0 {continue}
b[i][j] = value
for ial in 0..3 {
for jal in 0..3 {
if brd.bay[ial][jal] != 0 {continue}
brd.bay[ial][jal] = value
changed = value
score = -test_move(-value, depth + 1)
b[i][j] = 0
score = -test_move(mut brd, -value, depth + 1)
brd.bay[ial][jal] = 0
if score <= best {continue}
if depth == 0 {
best_i = i
best_j = j
brd.best_i = ial
brd.best_j = jal
}
best = score
}