@@ -14,6 +14,11 @@ type Prompter interface {
1414 Select (prompt , defaultValue string , options []string ) (int , error )
1515}
1616
17+ // GameInterface defines the methods needed for GetPlayerMove
18+ type GameInterface interface {
19+ GetAvailablePositions () []string
20+ }
21+
1722// Board represents a 3x3 Tic-tac-toe game board.
1823// Empty squares are represented by empty strings,
1924// and played squares contain either "X" or "O".
@@ -43,11 +48,9 @@ func (g *Game) MakeMove(rowIndex, columnIndex int) error {
4348 if rowIndex < 0 || rowIndex > 2 || columnIndex < 0 || columnIndex > 2 {
4449 return errors .New ("invalid position: must be between 0 and 2" )
4550 }
46-
4751 if g.board [rowIndex ][columnIndex ] != "" {
4852 return errors .New ("position already taken" )
4953 }
50-
5154 g.board [rowIndex ][columnIndex ] = g .CurrentPlayer
5255 g .CurrentPlayer = switchPlayer (g .CurrentPlayer )
5356 return nil
@@ -97,6 +100,7 @@ func (g *Game) GetWinner() string {
97100// IsBoardFull determines if all positions on the board have been played.
98101// Returns true if no empty positions remain, false otherwise.
99102func (g * Game ) IsBoardFull () bool {
103+
100104 for rowIndex := 0 ; rowIndex < 3 ; rowIndex ++ {
101105 for columnIndex := 0 ; columnIndex < 3 ; columnIndex ++ {
102106 if g.board [rowIndex ][columnIndex ] == "" {
@@ -158,14 +162,18 @@ func switchPlayer(currentPlayer string) string {
158162// 1 2 3
159163// 4 5 6
160164// 7 8 9
165+ // Returns (-1, -1) for invalid positions (0 or >9)
161166func positionToRowCol (position int ) (rowIndex , columnIndex int ) {
167+ if position <= 0 || position > 9 {
168+ return - 1 , - 1
169+ }
162170 position -- // Convert to 0-based index
163171 return position / 3 , position % 3
164172}
165173
166- // getAvailablePositions returns a slice of strings representing unoccupied positions.
174+ // GetAvailablePositions returns a slice of strings representing unoccupied positions.
167175// The positions are numbered 1-9 (one-based) to match the display format.
168- func (g * Game ) getAvailablePositions () []string {
176+ func (g * Game ) GetAvailablePositions () []string {
169177 var availablePositions []string
170178 for position := 1 ; position <= 9 ; position ++ {
171179 rowIndex , columnIndex := positionToRowCol (position )
@@ -182,27 +190,31 @@ func (g *Game) getAvailablePositions() []string {
182190// - No valid moves are available (board is full)
183191// - User input is invalid
184192// - Selected position is invalid
185- func GetPlayerMove (prompter Prompter , game * Game ) (rowIndex , columnIndex int , err error ) {
186- availablePositions := game .getAvailablePositions ()
193+ func GetPlayerMove (prompter Prompter , game GameInterface ) (rowIndex , columnIndex int , err error ) {
194+ availablePositions := game .GetAvailablePositions ()
187195 if len (availablePositions ) == 0 {
188- return 0 , 0 , errors .New ("no available moves" )
196+ return - 1 , - 1 , errors .New ("no available moves" )
189197 }
190198
191- posIndex , err := prompter .Select ("Select position (1-9):" , availablePositions [ 0 ] , availablePositions )
199+ posIndex , err := prompter .Select ("Select position (1-9):" , "1" , availablePositions )
192200 if err != nil {
193- return 0 , 0 , err
201+ return - 1 , - 1 , err
194202 }
195203
196204 if posIndex < 0 || posIndex >= len (availablePositions ) {
197- return 0 , 0 , fmt .Errorf ("invalid position selection: %d" , posIndex )
205+ return - 1 , - 1 , fmt .Errorf ("invalid position selection: %d" , posIndex )
198206 }
199207
200208 var position int
201209 _ , err = fmt .Sscanf (availablePositions [posIndex ], "%d" , & position )
202210 if err != nil {
203- return 0 , 0 , fmt .Errorf ("invalid position value: %v" , err )
211+ return - 1 , - 1 , fmt .Errorf ("invalid position value: %v" , err )
204212 }
205213
206214 rowIndex , columnIndex = positionToRowCol (position )
215+ if rowIndex < 0 || columnIndex < 0 {
216+ return - 1 , - 1 , fmt .Errorf ("invalid position value: %d" , position )
217+ }
218+
207219 return rowIndex , columnIndex , nil
208220}
0 commit comments