7 Commits

Author SHA1 Message Date
MSWS
89c940dfc8 test: Add and update UCI engine output tests
- Update `TestInit` in `uci/engine_test.go` to use `out` instead of `in` for expected output source
- Add `TestPrint` test to validate output generation of a custom message ("Hello, World!")
- Add `TestCopyProtection` test to ensure `CopyProtection` method outputs "copyprotection ok"

[uci/engine_test.go]
- Replaced `in` with `out` in the `TestInit` function to align with the expected output source.
- Added a new `TestPrint` function to test output generation for a custom message ("Hello, World!").
- Added a new `TestCopyProtection` function to verify the output of the `CopyProtection` method, ensuring it produces "copyprotection ok".
2025-03-30 21:45:00 -07:00
MSWS
137e694a38 test: Refactor TestInit with reusable helper functions
- Refactor `TestInit` in `uci/engine_test.go` for improved readability and maintainability by introducing helper functions (`expectLine`, `readLine`) for input handling and validation
- Add `strings` package import to support string manipulation in input/output processing

[uci/engine_test.go]
- Added the `strings` package import, likely for string manipulation on input or output data.
- Rewritten the `TestInit` function to use helper functions (`expectLine`) instead of manually evaluating read results:
  - Improved readability and structure by separating line reading and validation logic.
- Introduced a new `expectLine` function to handle assertions on expected input, providing clearer error messages for test failures.
- Created a new `readLine` function to encapsulate the logic for reading a line of input and trimming newline characters, promoting code reusability and cleanliness.
- Removed manual error handling and data validation in `TestInit` by delegating these responsibilities to the new helper functions.
2025-03-30 21:42:56 -07:00
MSWS
097a054644 Merge branch 'feat/uci' of github.com:MSWS/GoChess2 into feat/uci 2025-03-24 12:52:04 -07:00
MSWS
48e7e5b2b8 feat: Implement UCI engine with command processing loop
```
Introduce UCI engine and improve codebase functionality

- Add `CreateMoveUCI` function in `board/move.go` for parsing UCI strings into moves with error handling for invalid inputs.
- Refactor `main.go` to use the `uci` package for implementing a chess engine, replacing legacy functionality and optimizing input handling with `bufio`.
- Add a new `Engine` interface implementation in `uci/engine.go` for handling UCI interactions, including methods for engine initialization, copy protection, and position parsing.
- Add `.vscode` to the `.gitignore` file to exclude editor-specific configurations.
- Add unit tests in `uci/engine_test.go` and `main_test.go` for verifying the UCI engine and main module functionality.
```

[board/move.go]
- Added a new function `CreateMoveUCI` for creating a move using the Universal Chess Interface (UCI) string format.
- The function constructs move coordinates and handles promotion if included in the UCI string.
- Error handling added for invalid promotion piece inputs, with a panic in case of an error.
[main.go]
- Replaced usage of the `fmt` package with `bufio` for input handling.
- Removed logic related to chess board initialization and move generation.
- Introduced new usage of the `uci` package to create and manage a chess engine.
- Implemented a loop to continuously read commands from `stdin`.
- Removed legacy functionality, including FEN parsing, move generation, and `Perft` calculations.
- Added a goroutine to asynchronously handle and process commands using the UCI engine.
[main_test.go]
- Added a new test file for the main package.
[uci/engine.go]
- Added a new implementation of an `Engine` interface for handling UCI (Universal Chess Interface) interactions.
- Defined the `MyEngine` struct with fields for reader, writer, a chess game object, and a debug flag.
- Implemented `Engine` interface methods:
  - `CopyProtection`: Responds with a "copyprotection ok" message.
  - `Init`: Outputs engine metadata such as name and author and indicates UCI readiness.
  - `Debug`: Toggles debug mode.
  - `SetOption`: Stub method added but not yet implemented.
  - `Position`: Parses a FEN string to initialize a chess game and handles errors in debug mode.
- Introduced utility methods for printing through the engine's output stream.
- Provided a constructor function `NewEngine` to initialize a `MyEngine` instance.
[.gitignore]
- Added `.vscode` to the ignored files list.
[uci/engine_test.go]
- Added a test file with unit tests for the UCI engine.
- Implemented a `base` helper function to initialize the engine and establish pipe connections.
- Added a test case `TestInit` to validate the engine's initialization:
  - Ensures that initialization output is read from the pipe.
  - Checks for errors during read operations.
  - Verifies the output matches the expected initialization string.
2025-03-24 12:51:58 -07:00
MSWS
8486955a05 feat: Implement UCI engine with command processing loop
```
Introduce UCI engine and improve codebase functionality

- Add `CreateMoveUCI` function in `board/move.go` for parsing UCI strings into moves with error handling for invalid inputs.
- Refactor `main.go` to use the `uci` package for implementing a chess engine, replacing legacy functionality and optimizing input handling with `bufio`.
- Add a new `Engine` interface implementation in `uci/engine.go` for handling UCI interactions, including methods for engine initialization, copy protection, and position parsing.
- Add `.vscode` to the `.gitignore` file to exclude editor-specific configurations.
- Add unit tests in `uci/engine_test.go` and `main_test.go` for verifying the UCI engine and main module functionality.
```

[board/move.go]
- Added a new function `CreateMoveUCI` for creating a move using the Universal Chess Interface (UCI) string format.
- The function constructs move coordinates and handles promotion if included in the UCI string.
- Error handling added for invalid promotion piece inputs, with a panic in case of an error.
[main.go]
- Replaced usage of the `fmt` package with `bufio` for input handling.
- Removed logic related to chess board initialization and move generation.
- Introduced new usage of the `uci` package to create and manage a chess engine.
- Implemented a loop to continuously read commands from `stdin`.
- Removed legacy functionality, including FEN parsing, move generation, and `Perft` calculations.
- Added a goroutine to asynchronously handle and process commands using the UCI engine.
[main_test.go]
- Added a new test file for the main package.
[uci/engine.go]
- Added a new implementation of an `Engine` interface for handling UCI (Universal Chess Interface) interactions.
- Defined the `MyEngine` struct with fields for reader, writer, a chess game object, and a debug flag.
- Implemented `Engine` interface methods:
  - `CopyProtection`: Responds with a "copyprotection ok" message.
  - `Init`: Outputs engine metadata such as name and author and indicates UCI readiness.
  - `Debug`: Toggles debug mode.
  - `SetOption`: Stub method added but not yet implemented.
  - `Position`: Parses a FEN string to initialize a chess game and handles errors in debug mode.
- Introduced utility methods for printing through the engine's output stream.
- Provided a constructor function `NewEngine` to initialize a `MyEngine` instance.
[.gitignore]
- Added `.vscode` to the ignored files list.
[uci/engine_test.go]
- Added a test file with unit tests for the UCI engine.
- Implemented a `base` helper function to initialize the engine and establish pipe connections.
- Added a test case `TestInit` to validate the engine's initialization:
  - Ensures that initialization output is read from the pipe.
  - Checks for errors during read operations.
  - Verifies the output matches the expected initialization string.
2025-03-24 12:19:28 -07:00
MSWS
a45ae92b01 Merge branch 'main' of github.com:MSWS/GoChess2 2025-03-24 12:18:51 -07:00
MSWS
8e30f7db4c Revert "feat: Implement UCI engine with command processing loop"
This reverts commit f83f9dd036.
2025-03-24 12:06:14 -07:00
6 changed files with 156 additions and 31 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
chess
.vscode

View File

@@ -163,6 +163,24 @@ func (board Game) CreateMoveAlgebra(algebra string) Move {
return board.createMoveFromTarget(piece, algebra[1:])
}
func (board Game) CreateMoveUCI(uci string) Move {
from := CreateCoordAlgebra(uci[:2])
to := CreateCoordAlgebra(uci[2:])
move := board.CreateMove(from, to)
if len(uci) == 5 {
piece, err := GetPiece(rune(uci[4]))
if err != nil {
panic(err)
}
move.promotionTo = piece
}
return move
}
func (board Game) createMoveFromTarget(piece Piece, algebra string) Move {
if len(algebra) == 3 {
target := CreateCoordAlgebra(algebra[1:])

39
main.go
View File

@@ -1,46 +1,23 @@
package main
import (
"fmt"
"bufio"
"os"
"strconv"
"strings"
"github.com/msws/chess/board"
"github.com/msws/chess/uci"
)
func main() {
board, err := board.FromFEN("r3k2r/p1pPqpb1/1n3np1/1b2N3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R b KQkq - 0 2")
if err != nil {
panic(err)
}
reader := bufio.NewReader(os.Stdin)
engine := uci.NewEngine(reader, os.Stdout)
baseMoves := board.GetMoves()
for {
cmd, err := reader.ReadString('\n')
depth := 1
total := 0
println(strings.Join(os.Args, ","))
if len(os.Args) == 2 {
val, err := strconv.Atoi(os.Args[1])
if err != nil {
panic(err)
}
depth = val
go engine.Print(cmd)
}
// fmt.Printf("Depth: %d\n", depth)
for _, move := range baseMoves {
board.MakeMove(move)
perft := board.Perft(depth - 1)
total += perft
fmt.Printf("%v%v: %d\n", move.From.GetAlgebra(), move.To.GetAlgebra(), perft)
board.UndoMove()
}
fmt.Printf("Depth: %d, (%d)", depth, total)
}

1
main_test.go Normal file
View File

@@ -0,0 +1 @@
package main

67
uci/engine.go Normal file
View File

@@ -0,0 +1,67 @@
package uci
import (
"io"
"github.com/msws/chess/board"
)
type Engine interface {
Debug(bool bool)
Init()
CopyProtection()
SetOption(name string, id string, value string)
Print(message string)
Position(fen string, moves []string)
}
type MyEngine struct {
in io.Reader
out io.Writer
game *board.Game
debug bool
}
// CopyProtection implements Engine.
func (e *MyEngine) CopyProtection() {
e.Println("copyprotection ok")
}
func (e *MyEngine) Init() {
e.Println("id name GoChess2")
e.Println("id author MS")
e.Println("uciok")
}
func NewEngine(in io.Reader, out io.Writer) Engine {
return &MyEngine{
in: in,
out: out,
}
}
func (e *MyEngine) Print(message string) {
e.out.Write([]byte(message))
}
func (e *MyEngine) Println(message string) {
e.Print(message + "\n")
}
func (e *MyEngine) Debug(bool bool) {
e.debug = bool
}
func (e *MyEngine) SetOption(name string, id string, value string) {
}
func (e *MyEngine) Position(fen string, moves []string) {
game, err := board.FromFEN(fen)
if err != nil {
if e.debug {
e.Print(err.Error())
}
return
}
e.game = game
}

61
uci/engine_test.go Normal file
View File

@@ -0,0 +1,61 @@
package uci
import (
"io"
"strings"
"testing"
)
func base() (Engine, io.Reader, io.Writer) {
in, out := io.Pipe()
e := NewEngine(in, out)
return e, in, out
}
func TestInit(t *testing.T) {
e, out, _ := base()
go e.Init()
expectLine(t, out, "id name GoChess2")
expectLine(t, out, "id author MS")
expectLine(t, out, "uciok")
}
func TestPrint(t *testing.T) {
e, out, _ := base()
go e.Print("Hello, World!")
expectLine(t, out, "Hello, World!")
}
func TestCopyProtection(t *testing.T) {
e, out, _ := base()
go e.CopyProtection()
expectLine(t, out, "copyprotection ok")
}
func expectLine(t *testing.T, in io.Reader, expected string) {
line, err := readLine(in)
if err != nil {
t.Fatalf("Error reading line: %v", err)
}
if line != expected {
t.Fatalf("Expected '%s', got '%s'", expected, line)
}
}
func readLine(in io.Reader) (string, error) {
buf := make([]byte, 1024)
n, err := in.Read(buf)
if err != nil {
return "", err
}
return strings.Trim(string(buf[:n]), "\n"), nil
}