func negamax(b game.Board, depth, alpha, beta int, color game.Color) (int, game.Move) { if depth == 0 { return scoreBoard(b, color), nullMove } moves := b.AvailableMoves(color) if len(moves) == 0 { return math.MinInt32 + 1, nullMove } var ( bestScore = math.MinInt32 bestMove game.Move ) for _, i := range rand.Perm(len(moves)) { val, _ := negamax(b.IfMove(moves[i]), depth-1, -beta, -alpha, color.Other()) val = -val if val > bestScore { bestScore = val bestMove = moves[i] } if val > alpha { alpha = val } if alpha >= beta { break } } return bestScore, bestMove }
func (p httpPlayer) Move(b game.Board) game.Move { var move game.Move moveCommand := commandToClient{ Command: "move", Args: map[string]interface{}{ "board": b, "moves": b.AvailableMoves(p.Color()), }, } if err := p.conn.WriteJSON(moveCommand); err != nil { log.Printf("error requesting move: %s", err) return move } var resp commandFromClient if err := p.conn.ReadJSON(&resp); err != nil { log.Printf("error receiving move: %s", err) return move } if resp.Command != "move" { log.Printf("expected move command, got: %s", resp.Command) return move } if err := json.Unmarshal(resp.Args, &move); err != nil { log.Printf("failed unmarshaling move: %s (%s)", resp.Command, string(resp.Args)) return move } return move }
// simple heuristic for board evaluation func scoreBoard(b game.Board, c game.Color) (score int) { var myPieceCount, theirPieceCount int for x := 0; x < b.Width(); x++ { for y := 0; y < b.Height(); y++ { sq, _ := b.Get(game.Position{x, y}) if sq.PieceColor == c { myPieceCount += sq.PieceCount if sq.PieceCount == 1 || sq.PieceCount > 4 { score-- } } else { theirPieceCount += sq.PieceCount if sq.PieceCount == 1 || sq.PieceCount > 4 { score++ } } } } return score + 5*int(float64(myPieceCount-theirPieceCount)*float64(2*b.Width())/float64(myPieceCount)+0.5) }
func (p cliPlayer) Move(b game.Board) game.Move { buf := new(bytes.Buffer) buf.WriteString(" " + strings.Repeat("-", 5*b.Width()-1) + "\n") for y := 0; y < b.Height(); y++ { buf.WriteByte('|') for x := 0; x < b.Width(); x++ { sq, _ := b.Get(game.Position{x, y}) if sq.PieceCount == 0 { buf.WriteString(" ") } else { var c string if sq.PieceColor == game.Black { c = "b" } else { c = "w" } num := strconv.Itoa(sq.PieceCount) if len(num) == 1 { buf.WriteString(" " + num + c + " ") } else { buf.WriteString(num + c + " ") } } buf.WriteByte('|') } buf.WriteString(" " + strconv.Itoa(y) + "\n") buf.WriteString(" " + strings.Repeat("-", 5*b.Width()-1) + "\n") } buf.WriteString(" ") for x := 0; x < b.Width(); x++ { fmt.Fprintf(buf, " %2d ", x) } buf.WriteString("\n\n") clear := exec.Command("clear") clear.Stdout = os.Stdout clear.Run() os.Stdout.Write(buf.Bytes()) for { var ( move game.Move n int err error ) for n < 4 || err != nil { fmt.Fprintf(os.Stdout, "Enter move for %s (fromx,fromy tox,toy count): ", p.Name()) scanner := bufio.NewScanner(os.Stdin) scanner.Scan() n, err = fmt.Sscanf(scanner.Text(), "%d,%d %d,%d %d", &move.From.X, &move.From.Y, &move.To.X, &move.To.Y, &move.PieceCount, ) } available := b.AvailableMoves(p.Color()) for _, m := range available { if move == m { return move } } fmt.Fprintf(os.Stdout, "Move %+v is not legal!\n", move) } }
func (p randomPlayer) Move(b game.Board) game.Move { moves := b.AvailableMoves(p.Color()) return moves[rand.Intn(len(moves))] }