Data update

This commit is contained in:
Ingy döt Net 2024-07-13 15:19:22 -07:00
parent 29a5eea0d4
commit 5c1bb7bfa9
2011 changed files with 35081 additions and 3229 deletions

View file

@ -1,94 +1,9 @@
Note 'ttt adjudicates or plays'
use: markers ttt characters
characters represent the cell names.
markers is a length 3 character vector of the
characters to use for first and second player
followed by the opponent's mark.
'XOX' means X plays 1st, O is the other mark,
and the first strategy plays 1st.
'XOO' means X plays 1st, O is the other mark,
and the second strategy moves first.
The game is set up for the computer as the
first strategy (random), and human as second.
A standard use:
'XOX'ttt'abcdefghijkl'
Example game reformatted w/ emacs artist-mode
to fit your display:
'#-#'ttt'wersdfxcv'
w│e│r w│e│r .... -│e│r . -│e│#
─┼─┼─ . ─┼─┼─ .. ─┼─┼─ .. ─┼─┼─
s│d│f . s│#│f .. s│#│f .. -│#│f
─┼─┼─ .. ─┼─┼─ . ─┼─┼─ ... ─┼─┼─
x│c│v .. -│c│v . -│c│# .. -│c│#
d .. v .. r . VICTORY
w│e│r .. w│e│r .. -│e│# .
─┼─┼─ ... ─┼─┼─ .. ─┼─┼─ .
s│#│f ... s│#│f .. s│#│f .
─┼─┼─ .. ─┼─┼─ ... ─┼─┼─ ...
x│c│v -│c│# -│c│#
-->cell for -? -->cell for -? -->cell for -?
x w s
)
while=: conjunction def 'u ^: v ^:_' NB. j assumes while is a verb and needs to know while is a conjunction.
ttt=: outcome@:((display@:move) while undecided)@:display@:prepare
blindfolded_variant=: outcome@:display@:(move while undecided)@:display@:prepare
outcome=: {&(>;:'kitty VICTORY')@:won NB. (outcome does not pass along the state)
move=: post locate
undecided=: won nor full
prepare=: , board@:] NB. form the state vector
Note 'locate'
is a monadic verb. y is the state vector.
returns the character of the chosen cell.
Generally:
locate=: second_strategy`first_strategy@.(first = mark)
Simplified:
locate=: human_locate NB. human versus human
)
locate=: human_locate`computer_locate@.(first = mark)
display=: show [: (1 1,:5 5)&(];.0)@:": [: <"0 fold
computer_locate=: [: show@{. board -. marks NB. strategy: first available
computer_locate=: [: show@({~ ?@:#) board -. marks NB. strategy: random
human_locate=: monad define
state=. y
m=. mark state
b=. board state
cells=. b -. marks state
show '-->cell for ' , m , '?'
whilst. cell -.@:e. cells do. cell =. {. (1!:1]1) , m end.
)
post=: 2&A.@:(3&{.)@:[ prepare mark@:[`((i.~ board)~)`(board@:[)}
mark=: {. NB. mark of the current player from state
marks=: 2&{. NB. extract both markers from state
board=: _9&{. NB. extract board from state
first=: 2&{ NB. extract first player from state
show=: [ smoutput
full=: 2 = #@:~.
won=: test@:fold
fold=: 3 3 $ board
test=: [: any [: all [: infix_pairs_agree |:@:lines
lines=: , diagonal , diagonal@:|. , |:
diagonal=: (<0 1)&|:
all=: *./
any=: +./
nor=: 8 b.
infix_pairs_agree=: 2&(=/\)
'`turn board open full'=: {.`}.`(0=[{board@])`(0-.@e.board)
'`cpu_move position'=: (?@#{])@([:I.0=board)`(cpu_move`you_move@.(_1 1 i.turn))
you_move=: $:@echo@'invalid'^:(-.@e.i.@9)@:<:@".@{.@;:@(1!:1@1)
move=: position (][echo@'already taken!')`(-@turn@] , turn@]`[`(board@])})@.open ]
show=: [ [: echo@''@echo (,' '&,)/"1@({&'.XO')@(3 3$board) [ echo@''
won=: [: +./ (3=[:|+/)"1@(], |:, (<@i.@#|:]),: <@i.@#|:|.)@(3 3$board)
prompt=: echo@:>:@i.@3 3@echo@'enter a move (19) each turn; you''re X''s'
outcome=: (echo@'tie')`(' wins'echo@,~{&'.XO'@-@turn)@.won
ttt=: outcome@([F.(show@move[_2:Z:won+.full))@(10{._1)@prompt

View file

@ -0,0 +1,151 @@
include "MRG32k3a" {search: "."}; # see comment above
### Generic functions
def inform(msg):
. as $in
| msg + "\n" | stderr
| $in;
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
# Create an m x n matrix with initial values specified by .
def matrix($m; $n):
if $m == 0 then []
else . as $init
| if $m == 1 then [range(0;$n) | $init]
elif $m > 0 then
matrix(1; $n) as $row
| [range(0; $m) | $row ]
else error("matrix\($m);\($n)) invalid")
end
end;
### Tic-Tac-Toe
# The board is represented by a matrix in which:
# 0 : blank; -1: computer; 1: user
def init:
{b: (0 | matrix(3;3)),
bestI: 0,
bestJ: 0,
prng: seed(now | tostring | sub("^.*[.]";"") | tonumber)};
# Output: 0 if undecided, null if game over, otherwise the player id
def checkWinner:
first(range(0; 3) as $i
| if .b[$i][0] != 0 and .b[$i][1] == .b[$i][0] and .b[$i][2] == .b[$i][0] then .b[$i][0]
elif .b[0][$i] != 0 and .b[1][$i] == .b[0][$i] and .b[2][$i] == .b[0][$i] then .b[0][$i]
else empty
end)
// if (.b[1][1] == 0) then 0
elif (.b[1][1] == .b[0][0] and .b[2][2] == .b[0][0]) then .b[0][0]
elif (.b[1][1] == .b[2][0] and .b[0][2] == .b[1][1]) then .b[1][1]
elif all(.b[][]; . != 0) then null
else 0
end ;
def showBoard:
["X", " ", "O"] as $t
| .b as $b
| range(0;3) as $i
| reduce range(0;3) as $j ("";
. + "\($t[$b[$i][$j] + 1]) " ), # b == -1 => "X"; b == 1 => "O"
"-----";
# Examine possible moves of the player identified by $value, avoiding embarrassment
# Set .result, .bestI, .bestJ, etc
def testMove($value; $depth):
checkWinner as $score
| if $score == null then .result = 0
elif $score != 0
then .result = (if $score == $value then 1 else -1 end)
else .best = -1
| .changed = 0
| reduce range(0;3) as $i (.;
reduce range(0;3) as $j (.;
if .b[$i][$j] == 0
then .b[$i][$j] = $value
| .changed = $value
| testMove(-$value; $depth + 1) as $test
| (-$test.result) as $score
| .b[$i][$j] = 0
| if $score > .best
then if $depth == 0
then .bestI = $i
| .bestJ = $j
end
| .best = $score
end
end ) )
| .result = if .changed != 0 then .best else 0 end
end;
# Issue prompts on stderr;
# always allow q for quit
def read($prompt; $regex):
def r:
($prompt | stderr | empty),
(try ((input
| if . == "q" then halt
else select(test($regex))
end) // r)
catch if . == "break" then halt else r end );
r;
# Input: irrelevant
# $user should be boolean; specify `true` if the user plays first
def game($user):
"Board positions are numbered so:\n1 2 3\n4 5 6\n7 8 9",
"You have O, I have X.\n",
(init + {$user}
| label $out
| foreach range(0;9) as $k (.;
if .user
then .move = null
| until(.move;
(read("Your move: "; "^ *[1-9]") | tonumber - 1) as $move
| ($move/3|floor) as $i
| ($move % 3) as $j
| if .b[$i][$j] == 0
then .b[$i][$j] = 1
| .move = $move
end )
end
| if (.user|not)
then # in the interests of entertainment, randomize if computer opens
if $k == 0
then .prng |= nextFloat
| .bestI = (.prng.nextFloat * 100 | trunc) % 3
| .prng |= nextFloat
| .bestJ = (.prng.nextFloat * 100 | trunc) % 3
else testMove(-1; 0)
end
| .b[.bestI][.bestJ] = -1
| inform("My move: \(.bestI * 3 + .bestJ + 1)")
end
| .user |= not
;
# Output:
showBoard,
(checkWinner
| if . == 0 then empty
else (if . == 1 then "You win"
elif . == -1 then "I win"
else "A draw.\n\n"
end),
break $out
end ) )) ;
# Alternate players
def controller:
def c($user):
game($user),
(read("Play again? [yn]: "; "^[yYnN]") as $in
| if $in|.[0:1]|ascii_downcase == "n" then halt
else c($user|not)
end);
c(true);
controller