Minor changes and fixes

This commit is contained in:
Nocturn9x 2023-03-01 10:58:08 +01:00
parent 2da2ebed9a
commit 4f908c24fa
2 changed files with 28 additions and 30 deletions

View File

@ -16,7 +16,9 @@ import ../util/matrix
import../util/multibyte
# import std/random
import std/random
randomize()
export matrix
@ -152,7 +154,7 @@ proc get*(self: TicTacToeGame): GameStatus =
# a successful tic tac toe is 5, so we don't
# bother checking if there's less than those
# in the current board
return
return Playing
# Checks the rows
for _, row in self.map:
if all(row == one):
@ -307,23 +309,23 @@ proc findBest*(tree: Move, map: Matrix[int]): Move =
]#
proc findBest*(tree: Move, map: Matrix[uint8], maximize: bool = true, skip: int = 0): Choice =
proc findBest*(tree: Move, maximize: bool = true, skip: int = 0): Choice =
## Finds the best possible move in the
## given playing field using minimax
## tree search
var start = tree.find(map)
if start.outcome == WinX:
## tree search. The first skip best
## results (default 0) are skipped.
if tree.outcome == WinX:
return Choice(move: tree, weight: 10 - tree.depth)
elif start.outcome == WinO:
elif tree.outcome == WinO:
return Choice(move: tree, weight: -10 + tree.depth)
elif start.outcome == Draw:
elif tree.outcome == Draw:
return Choice(move: tree, weight: 0)
var choices: seq[Choice] = @[]
for i in 0..8:
if start.next[i].isNil():
if tree.next[i].isNil():
continue
choices.add(start.next[i].findBest(start.next[i].state, maximize=not maximize))
choices[^1].move = start.next[i]
choices.add(tree.next[i].findBest(maximize=not maximize))
choices[^1].move = tree.next[i]
var best: Choice
var bestWeight: int = 100
var worst: Choice

View File

@ -27,11 +27,15 @@ import std/os
import std/exitprocs
template clearScreen =
eraseScreen()
setCursorPos(0, 0)
proc play(treeA, treeB: Move) =
## Plays a game of tic tac toe
## against the user
eraseScreen()
setCursorPos(0, 0)
clearScreen()
var game = newTicTacToe()
var moves = treeA
var location: tuple[row, col: int]
@ -41,12 +45,10 @@ proc play(treeA, treeB: Move) =
moves = treeB
location = where(moves.state, moves.state != game.map, 3).index(Self.uint8)
game.place(Self, location.row, location.col)
eraseScreen()
setCursorPos(0, 0)
clearScreen()
styledEcho fgCyan, styleBright, "Computer chose ", fgYellow, $game.map.getIndex(location.row, location.col)
else:
eraseScreen()
setCursorPos(0, 0)
clearScreen()
while game.get() == Playing:
styledEcho fgBlue, styleBright, "Tic Tac Bot v1.0"
echo game, "\n"
@ -57,30 +59,25 @@ proc play(treeA, treeB: Move) =
index = int(parseBiggestInt(readLine(stdin).strip(chars={'\n'})))
location = ind2sub(index, game.map.shape)
except ValueError:
eraseScreen()
setCursorPos(0, 0)
clearScreen()
styledEcho fgRed, styleBright, "Invalid move"
continue
if index notin 0..8 or TileKind(game.map[location.row, location.col]) != Empty:
eraseScreen()
setCursorPos(0, 0)
clearScreen()
styledEcho fgRed, styleBright, "Invalid move"
continue
game.place(Enemy, location.row, location.col)
eraseScreen()
setCursorPos(0, 0)
clearScreen()
if game.get() == WinO:
echo game, "\n"
styledEcho fgGreen, styleBright, "Human wins!"
return
elif game.get() == Draw:
break
moves = moves.find(game.map)
moves = moves.findBest(game.map, true).move
moves = moves.next[game.map.getIndex(location.row, location.col)].findBest(true).move
location = where(moves.state, moves.state != game.map, 3).index(Self.uint8)
game.place(Self, location.row, location.col)
eraseScreen()
setCursorPos(0, 0)
clearScreen()
if game.get() != Draw:
styledEcho fgCyan, styleBright, "Computer chose ", fgYellow, $game.map.getIndex(location.row, location.col)
if game.get() == WinX:
@ -88,7 +85,7 @@ proc play(treeA, treeB: Move) =
styledEcho fgRed, styleBright, "Computer wins!"
return
echo game
echo "It's a draw!"
styledEcho fgYellow, styleBright, "It's a draw!"
proc hook {.noconv.} =
@ -135,10 +132,9 @@ when isMainModule:
fp.close()
# Here we pick one of the first 5 best moves so that the bot doesn't
# always start with an X in the left corner when it's playing first
var state = movesB.state.copy()
var best: seq[Move] = @[]
for i in 0..4:
best.add(movesB.findBest(state, true, i).move)
best.add(movesB.findBest(true, i).move)
movesB = sample(best)
while true:
try: