The Android client for the Flang board game https://codeberg.org/jannis/Flang
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

101 lines
3.4 KiB

package de.tadris.flang_lib.bot
import de.tadris.flang_lib.Board
import de.tadris.flang_lib.Color
import de.tadris.flang_lib.Type
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
class FlangBot(val minDepth: Int, val maxDepth: Int) {
var evaluations = 0
fun findBestMove(board: Board, printTime: Boolean = true) : BotResult {
val start = System.currentTimeMillis()
evaluations = 0
val eval = findBestMove(board, maxDepth)
val end = System.currentTimeMillis()
if(printTime){
println((end-start).toString() + "ms")
}
return eval!!
}
private fun findBestMove(board: Board, depth: Int) : BotResult? {
val moveEvaluations = mutableListOf<MoveEvaluation>()
val allMoves = board.findAllMoves(board.atMove).toMutableList()
allMoves.sortBy { BoardEvaluation(board.executeOnNewBoard(it)).evaluate()*board.atMove.evaluationNumber }
allMoves.forEach {
moveEvaluations+= MoveEvaluation(it, evaluateMove(board.executeOnNewBoard(it), depth-1, -100000.0, 100000.0), depth)
}
moveEvaluations.shuffle()
moveEvaluations.sortBy { -((it.evaluation*100).roundToInt() / 100.0)*board.atMove.evaluationNumber }
if(moveEvaluations.size == 0){
return null
}
val bestMove = moveEvaluations[0]
return BotResult(MoveEvaluation(bestMove.move, bestMove.evaluation, depth), moveEvaluations, evaluations)
}
private fun evaluateMove(board: Board, depth: Int, alpha: Double, beta: Double) : Double {
var alpha = alpha
var beta = beta
if(depth <= 0){
evaluations++
return BoardEvaluation(board).evaluate()
}
var bestEvaluation = -1000000.0*board.atMove.evaluationNumber
val allMoves = board.findAllMoves(board.atMove).toMutableList()
if(depth >= 3){
allMoves.sortBy {
-evaluateMove(board.executeOnNewBoard(it), 0, 0.0, 0.0)*board.atMove.evaluationNumber
}
}else if(depth >= 2){
allMoves.sortBy {
return@sortBy when(it.piece.type){
Type.KING -> -1
else -> 0
}
}
}
allMoves.forEach { move ->
val hypotheticalBoard = board.executeOnNewBoard(move)
val moveEvaluation = evaluateMove(hypotheticalBoard, depth - 1, alpha, beta)*0.99
if(board.atMove == Color.WHITE){
bestEvaluation = max(bestEvaluation, moveEvaluation)
alpha = max(alpha, bestEvaluation)
if(alpha >= beta){
return bestEvaluation
}
}else{
bestEvaluation = min(bestEvaluation, moveEvaluation)
beta = min(beta, bestEvaluation)
if(beta <= alpha){
return bestEvaluation
}
}
}
return bestEvaluation
}
class BotResult(val bestMove: MoveEvaluation, val evaluations: List<MoveEvaluation>, val count: Int){
fun getVariance(): Double {
val sum = evaluations.sumOf { it.evaluation }
val avg = sum / evaluations.size
val summedDiff = evaluations.sumOf { (it.evaluation - avg).pow(2) }
return summedDiff / evaluations.size
}
}
}