Skip to content

Commit ff2b4df

Browse files
committed
moved engine code to own file and added test
1 parent 7978f93 commit ff2b4df

File tree

3 files changed

+69
-29
lines changed

3 files changed

+69
-29
lines changed
Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
1-
// Package game provides a simple Go engine interface and a random-move engine.
2-
package game
1+
// Package engine provides a simple Go engine interface and a random-move engine.
2+
package engine
33

44
import (
55
"math/rand"
66
"time"
7+
8+
"github.com/RubikNube/GoInGo/cmd/game"
79
)
810

911
// Engine is an interface for Go engines.
1012
type Engine interface {
1113
// Move returns the next move as a Point, or nil if passing.
12-
Move(board Board, player FieldState, ko *Point) *Point
14+
Move(board game.Board, player game.FieldState, ko *game.Point) *game.Point
1315
}
1416

1517
// RandomEngine implements Engine by picking a random legal move.
1618
type RandomEngine struct{}
1719

18-
func (e *RandomEngine) Move(board Board, player FieldState, ko *Point) *Point {
19-
empty := []Point{}
20+
func (e *RandomEngine) Move(board game.Board, player game.FieldState, ko *game.Point) *game.Point {
21+
empty := []game.Point{}
2022
for i := 0; i < 9; i++ {
2123
for j := 0; j < 9; j++ {
22-
if board[i][j] == Empty {
23-
empty = append(empty, Point{Row: i, Col: j})
24+
if board[i][j] == game.Empty {
25+
empty = append(empty, game.Point{Row: i, Col: j})
2426
}
2527
}
2628
}
@@ -32,26 +34,26 @@ func (e *RandomEngine) Move(board Board, player FieldState, ko *Point) *Point {
3234
if ko != nil && pt.Row == ko.Row && pt.Col == ko.Col {
3335
continue
3436
}
35-
var nextBoard Board
37+
var nextBoard game.Board
3638
copy(nextBoard[:], board[:])
3739
nextBoard[pt.Row][pt.Col] = player
38-
opp := Black
39-
if player == Black {
40-
opp = White
40+
opp := game.Black
41+
if player == game.Black {
42+
opp = game.White
4143
}
42-
captured := []Point{}
43-
for _, n := range Neighbors(pt) {
44+
captured := []game.Point{}
45+
for _, n := range game.Neighbors(pt) {
4446
if nextBoard[n.Row][n.Col] == opp {
45-
group, libs := Group(nextBoard, n)
47+
group, libs := game.Group(nextBoard, n)
4648
if len(libs) == 0 {
4749
for stonePt := range group {
48-
nextBoard[stonePt.Row][stonePt.Col] = Empty
50+
nextBoard[stonePt.Row][stonePt.Col] = game.Empty
4951
captured = append(captured, stonePt)
5052
}
5153
}
5254
}
5355
}
54-
_, libs := Group(nextBoard, pt)
56+
_, libs := game.Group(nextBoard, pt)
5557
if len(libs) == 0 {
5658
continue
5759
}

cmd/engine/engine_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package engine
2+
3+
import (
4+
"testing"
5+
6+
"github.com/RubikNube/GoInGo/cmd/game"
7+
)
8+
9+
func TestRandomEngine_MoveReturnsLegalMove(t *testing.T) {
10+
board := game.Board{}
11+
engine := &RandomEngine{}
12+
player := game.Black
13+
var ko *game.Point
14+
15+
move := engine.Move(board, player, ko)
16+
if move == nil {
17+
t.Error("Expected a move, got nil")
18+
}
19+
if move.Row < 0 || move.Row > 8 || move.Col < 0 || move.Col > 8 {
20+
t.Errorf("Move out of bounds: %+v", move)
21+
}
22+
}
23+
24+
func TestRandomEngine_MoveReturnsNilWhenNoMoves(t *testing.T) {
25+
board := game.Board{}
26+
// Fill the board
27+
for i := range board {
28+
for j := range board[i] {
29+
board[i][j] = game.Black
30+
}
31+
}
32+
engine := &RandomEngine{}
33+
player := game.White
34+
var ko *game.Point
35+
36+
move := engine.Move(board, player, ko)
37+
if move != nil {
38+
t.Errorf("Expected nil (pass), got %+v", move)
39+
}
40+
}

main.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99
"unicode"
1010

11+
"github.com/RubikNube/GoInGo/cmd/engine"
1112
"github.com/RubikNube/GoInGo/cmd/game"
1213
"github.com/jroimartin/gocui"
1314
)
@@ -20,13 +21,13 @@ var (
2021
cursorRow, cursorCol int
2122
gui game.Gui
2223
keybindings map[string]string
23-
prevBoard *game.Board // Track previous board for Ko rule
24-
currentPlayer int = 1 // Track current player (1 or 2), start with Black
25-
koPoint *game.Point // Track Ko point (nil if no Ko)
26-
passCount int // Track consecutive passes
27-
gameOver bool // Track if the game is over
28-
engineEnabled bool // Play against engine if true
29-
engine game.Engine // The engine instance
24+
prevBoard *game.Board // Track previous board for Ko rule
25+
currentPlayer int = 1 // Track current player (1 or 2), start with Black
26+
koPoint *game.Point // Track Ko point (nil if no Ko)
27+
passCount int // Track consecutive passes
28+
gameOver bool // Track if the game is over
29+
engineEnabled bool // Play against engine if true
30+
selectedEngine engine.Engine // The engine instance
3031
)
3132

3233
func loadConfig(path string) (Config, error) {
@@ -302,10 +303,10 @@ func quit(g *gocui.Gui, v *gocui.View) error {
302303

303304
func engineMove(g *gocui.Gui) {
304305
// Use the engine interface to get a move for White
305-
if engine == nil {
306+
if selectedEngine == nil {
306307
return
307308
}
308-
move := engine.Move(gui.Grid, game.White, koPoint)
309+
move := selectedEngine.Move(gui.Grid, game.White, koPoint)
309310
if move != nil {
310311
// Do not move the cursor for the engine, just place the stone directly
311312
row, col := move.Row, move.Col
@@ -361,13 +362,10 @@ func main() {
361362
}
362363
keybindings = cfg.Keybindings
363364

364-
engine = &game.RandomEngine{}
365+
selectedEngine = &engine.RandomEngine{}
365366
engineEnabled = true // Enable engine by default
366367

367368
defer g.Close()
368-
keybindings = cfg.Keybindings
369-
370-
engine = &game.RandomEngine{}
371369

372370
if err != nil {
373371
log.Panicln(err)

0 commit comments

Comments
 (0)