Skip to content

Commit

Permalink
Make MCTS move based instead of time based + extra board functions
Browse files Browse the repository at this point in the history
  • Loading branch information
henrykvdb committed Sep 12, 2023
1 parent 1cb4955 commit 31b766b
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/main/kotlin/bots/MCTSBot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class MCTSBot(
private val maxIterations: Int,
private val rand: Xoroshiro = Xoroshiro()
) : Bot {
override fun toString() = "MCTSBotArrayModified"
override fun toString() = "MCTSBot"

private val INIT_SIZE = 1024

Expand All @@ -32,7 +32,7 @@ class MCTSBot(
val touched = IntArray(81) // indices of visited nodes for iteration
val nodeBoard = board.copy()

while (nodeVisits[0] < maxIterations) {
while (nodeBoard.movesPlayed < maxIterations) {
var nodeIdx = 0
nodeBoard.loadInstance(board)
touchedCount = 0
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/bots/MMBot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import common.Coord
import kotlin.Float.Companion.NEGATIVE_INFINITY
import kotlin.math.max

private const val TILE_FACTOR = 1
private const val MACRO_FACTOR = 32
private const val TILE_FACTOR = 1.0F
private const val MACRO_FACTOR = 10e9F

private const val CENTER_FACTOR = 4
private const val CORNER_FACTOR = 2
private const val EDGE_FACTOR = 1
private const val CENTER_FACTOR = 4.0F
private const val CORNER_FACTOR = 3.0F
private const val EDGE_FACTOR = 1.0F

class MMBot(private val depth: Int) : Bot {
init {
Expand Down
22 changes: 17 additions & 5 deletions src/main/kotlin/common/Board.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package common

import java.io.Serializable
import java.util.*
import java.util.random.RandomGenerator

fun toCoord(x: Int, y: Int) = ((((x / 3) + (y / 3) * 3) shl 4) + ((x % 3) + (y % 3) * 3)).toByte()

Expand Down Expand Up @@ -44,16 +43,17 @@ class Board : Serializable {
internal var grids: IntArray // per macro, taken tiles per player (2 x 9b) x 9 macros
private var mainGrid: Int // for game, won macros per player (2 x 9b)
internal var openMacroMask: Int // available macros 9b
internal var movesPlayed = 0

// Exposed variables
var nextPlayX: Boolean; internal set
var lastMove: Coord; internal set // default -1
var tied: Boolean; internal set

// Exposed derived variables
val isDone inline get() = openMacroMask == 0
val availableMoves inline get() = getAvailableMoves<Byte> { it }
val wonBy: Player get() = if (!isDone || tied) Player.NEUTRAL else if (nextPlayX) Player.PLAYER else Player.ENEMY
private var tied: Boolean

/** Constructs an empty [Board]. */
constructor() {
Expand Down Expand Up @@ -218,6 +218,7 @@ class Board : Serializable {
val macroGridPlayer: Int

// Update and extract player local board
movesPlayed++
lastMove = index
if (nextPlayX) {
grids[om] = grids[om] or osShift
Expand Down Expand Up @@ -260,12 +261,23 @@ class Board : Serializable {
}

/** Check owner of macro **/
fun macro(macroIndex: Byte): Player = when {
mainGrid.hasBit(macroIndex.toInt()) -> Player.PLAYER
mainGrid.hasBit(macroIndex.toInt() + 9) -> Player.ENEMY
fun macro(macroIndex: Int): Player = when {
mainGrid.hasBit(macroIndex) -> Player.PLAYER
mainGrid.hasBit(macroIndex + 9) -> Player.ENEMY
else -> Player.NEUTRAL
}

/** Check if macro is tied **/
fun macroTied(macroIndex: Int) = (grids[macroIndex] and GRID_MASK or (grids[macroIndex] shr GRID_BITS)) == GRID_MASK

/** Check if macro is part of win for player **/
fun macroPartOfWin(macroIndex: Int): Boolean {
if (!isDone || tied) return false
val gridWinner = if (nextPlayX) (mainGrid and GRID_MASK) else (mainGrid shr GRID_BITS)
val gridMinimal = WIN_GRIDS.filter { x -> ((gridWinner and x) == x) }.reduce { acc, winGrid -> acc or winGrid }
return gridMinimal.hasBit(macroIndex)
}

/** Check owner of tile **/
fun tile(index: Coord): Player {
val om = (index.toInt() shr 4) and 0b1111 // top bits
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/games/ConsoleGame.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ConsoleGame(private val bot: Bot) {
printCurrent()

if (!current.isDone) {
val botMove = bot.move(current.copy())!!
val botMove = bot.move(current.copy())
println("bot played on $botMove")
current.play(botMove)
history.add(current.copy())
Expand Down
8 changes: 4 additions & 4 deletions src/test/kotlin/BoardTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ class BoardTest {
intArrayOf(0 + 3 * i + (om shl 4), 1 + 3 * i + (om shl 4), 2 + 3 * i + (om shl 4)).fix(),
intArrayOf(0 + (otherOm shl 4), 1 + (otherOm shl 4), 3 + (otherOm shl 4)).fix(),
(if (player == PLAYER) (otherOm shl 4) else (3 * i + (om shl 4))).fix()
).macro(om.toByte())) { "diagonal / in macro $om" }
).macro(om)) { "diagonal / in macro $om" }
assertEquals(player, playedBoard(player,
intArrayOf(0 + i + (om shl 4), 3 + i + (om shl 4), 6 + i + (om shl 4)).fix(),
intArrayOf(0 + (otherOm shl 4), 1 + (otherOm shl 4), 3 + (otherOm shl 4)).fix(),
(if (player == PLAYER) (otherOm shl 4) else (i + (om shl 4))).fix()
).macro(om.toByte())) { "diagonal \\ in macro $om" }
).macro(om)) { "diagonal \\ in macro $om" }
}
}

Expand All @@ -129,12 +129,12 @@ class BoardTest {
intArrayOf(0 + (om shl 4), 4 + (om shl 4), 8 + (om shl 4)).fix(),
intArrayOf(0 + (otherOm shl 4), 1 + (otherOm shl 4), 3 + (otherOm shl 4)).fix(),
(if (player == PLAYER) (otherOm shl 4) else (om shl 4)).fix()
).macro(om.toByte())) { "diagonal / in macro $om" }
).macro(om)) { "diagonal / in macro $om" }
assertEquals(player, playedBoard(player,
intArrayOf(2 + (om shl 4), 4 + (om shl 4), 6 + (om shl 4)).fix(),
intArrayOf(0 + (otherOm shl 4), 1 + (otherOm shl 4), 3 + (otherOm shl 4)).fix(),
(if (player == PLAYER) (otherOm shl 4) else (2 + (om shl 4))).fix()
).macro(om.toByte())) { "diagonal \\ in macro $om" }
).macro(om)) { "diagonal \\ in macro $om" }
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions src/test/kotlin/TestUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fun assertBoardMatches(exp: Expected, board: Board) {
for (o in 0 until 81)
assertEquals(Player.fromChar(exp.tiles[o]), board.tile(o.idxToCoord()))
for (om in 0 until 9)
assertEquals(Player.fromChar(exp.macros[om]), board.macro(om.toByte()))
assertEquals(Player.fromChar(exp.macros[om]), board.macro(om))
}

fun assertBoardEquals(expected: Board, actual: Board) {
Expand Down Expand Up @@ -64,7 +64,7 @@ fun Board.toExpected() = Expected(
availableMoves = availableMoves,
lastMove = lastMove,
done = isDone,
macros = CharArray(9) { macro(it.toByte().idxToCoord()).char },
macros = CharArray(9) { macro(it).char },
tiles = CharArray(81) { tile(it.toByte().idxToCoord()).char },
compactString = toCompactString()
)

0 comments on commit 31b766b

Please sign in to comment.