Skip to content

Instantly share code, notes, and snippets.

@thejhh
Created September 28, 2024 19:38
Show Gist options
  • Save thejhh/a78ca53f63634fa070f77b82a7beeb43 to your computer and use it in GitHub Desktop.
Save thejhh/a78ca53f63634fa070f77b82a7beeb43 to your computer and use it in GitHub Desktop.
Simple Chess Computer Player
// Copyright (c) 2024. Hangover Games <[email protected]>. All rights reserved.
package basicchesscomputer
import (
"chess/internal/chess"
"math/rand"
"time"
"chess/internal/chesserrors"
"chess/internal/chesstypes"
)
var RandSource rand.Source
var RNG *rand.Rand
func init () {
RandSource = rand.NewSource(time.Now().UnixNano())
RNG = rand.New(RandSource)
}
// ComputerMove implements a basic, simple computer which attacks anything it
// can, and moves by random.
func ComputerMove (g *chess.GameState) error {
b := g.Board
mySide := b.Turn.Side()
//log.Printf("Computer Turn: %d (%s)", b.Turn, mySide.String())
allUnits := chesstypes.AllUnits()
RNG.Shuffle(len(allUnits), func(i, j int) {
allUnits[i], allUnits[j] = allUnits[j], allUnits[i]
})
promoteTo := allUnits[0]
myUnits := b.FindUnitIndexes(mySide)
// Randomize units so we don't always use the same way
RNG.Shuffle(len(myUnits), func(i, j int) {
myUnits[i], myUnits[j] = myUnits[j], myUnits[i]
})
//log.Printf("My units: %v", myUnits)
enemyUnits := b.FindUnitIndexes(mySide.Opponent())
// Randomize enemy units so we don't always target the same way
RNG.Shuffle(len(enemyUnits), func(i, j int) {
enemyUnits[i], enemyUnits[j] = enemyUnits[j], enemyUnits[i]
})
//log.Printf("Enemy units: %v", enemyUnits)
allLegalMoves, _ := b.LegalMovesAndAttackMap(promoteTo)
// Try to attack any possible target
for _, unitIndex := range myUnits {
moves := allLegalMoves[unitIndex]
if len(moves) == 0 {
continue
}
// Randomize moves so we don't always move same way
RNG.Shuffle(len(moves), func(i, j int) {
moves[i], moves[j] = moves[j], moves[i]
})
//log.Printf("Unit %d moves: %v", unitIndex, moves)
var possibleTargets = make([]int, 0, 16)
for _, enemyIndex := range enemyUnits {
for _, moveIndex := range moves {
if moveIndex == enemyIndex {
possibleTargets = append(possibleTargets, enemyIndex)
}
}
}
if len(possibleTargets) == 0 {
continue
}
// Randomize possible targets so we don't always attack same way
RNG.Shuffle(len(possibleTargets), func(i, j int) {
possibleTargets[i], possibleTargets[j] = possibleTargets[j], possibleTargets[i]
})
//log.Printf("Unit %d possible targets: %v", unitIndex, possibleTargets)
// Attack
err := g.MovePiece(unitIndex, possibleTargets[0], promoteTo)
if err != nil {
//log.Printf("Unit %d attack: %d: %v", unitIndex, possibleTargets[0], err)
continue
}
//log.Printf("Unit %d attack: %d: OK", unitIndex, possibleTargets[0])
return nil
}
// Move any piece to random location
for _, unitIndex := range myUnits {
moves := allLegalMoves[unitIndex]
if len(moves) == 0 {
continue
}
// Randomize possible targets so we don't always move same way
RNG.Shuffle(len(moves), func(i, j int) {
moves[i], moves[j] = moves[j], moves[i]
})
err := g.MovePiece(unitIndex, moves[0], promoteTo)
if err != nil {
//log.Printf("Unit %d move: %d: %v", unitIndex, moves[0], err)
continue
}
//log.Printf("Unit %d move: %d: OK", unitIndex, moves[0])
return nil
}
return chesserrors.ErrComputerFailedToFindMove
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment