|
|
|
@ -28,6 +28,7 @@ const (
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var againstComputer bool = false
|
|
|
|
|
var paikaMoveCounter int // Keeps track of 5 paika moves
|
|
|
|
|
|
|
|
|
|
type pos struct {
|
|
|
|
|
strong bool // Strong if true, weak if not
|
|
|
|
@ -115,16 +116,13 @@ func (g *Game) ValidateMove(c move) error {
|
|
|
|
|
return fmt.Errorf("You cannot move diagonally from that space")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO check if the move is non-capturing. If so, see if there
|
|
|
|
|
// are available capturing moves that could be played. This will
|
|
|
|
|
// be semi-involved as it will require checking all other available
|
|
|
|
|
// pieces by the same player
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *Game) MoveAndDestroyStones(m move) (int, error) {
|
|
|
|
|
dead := g.RemoveDeadStones(m, false, false)
|
|
|
|
|
UpdatePaikaCounter(dead)
|
|
|
|
|
|
|
|
|
|
g.board[m.toRow][m.toCol].state = g.turn
|
|
|
|
|
g.board[m.fromRow][m.fromCol].state = Empty
|
|
|
|
@ -146,6 +144,47 @@ func (g Game) withdrawAvailable(m move) bool {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is not working right and keeps saying that an attack
|
|
|
|
|
// is available when one is not
|
|
|
|
|
func (g Game) invalidPaika(m move) bool {
|
|
|
|
|
na := g.CountPotentialDead(m, false)
|
|
|
|
|
nw := g.CountPotentialDead(m, true)
|
|
|
|
|
if na + nw > 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
var ap, wd bool
|
|
|
|
|
for r := range g.board {
|
|
|
|
|
for c := range g.board[r] {
|
|
|
|
|
if g.board[r][c].state != g.turn {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, d := range weakDirs {
|
|
|
|
|
ap = g.approachAvailable(move{r, c, r+d.rowOff, c+d.colOff})
|
|
|
|
|
if ap {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
wd = g.withdrawAvailable(move{r, c, r+d.rowOff, c+d.colOff})
|
|
|
|
|
if wd {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if g.board[r][c].strong {
|
|
|
|
|
for _, d := range strongDirs {
|
|
|
|
|
ap = g.approachAvailable(move{r, c, r+d.rowOff, c+d.colOff})
|
|
|
|
|
if ap {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
wd = g.withdrawAvailable(move{r, c, r+d.rowOff, c+d.colOff})
|
|
|
|
|
if wd {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g Game) approachAvailable(m move) bool {
|
|
|
|
|
d := m.Direction()
|
|
|
|
|
nextRow, nextCol := m.toRow+d.rowOff, m.toCol+d.colOff
|
|
|
|
@ -255,15 +294,34 @@ func (g *Game) RemoveDeadStones(m move, cpu bool, approach bool) int {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g Game) GameOver() {
|
|
|
|
|
enemy := g.Enemy()
|
|
|
|
|
for _, row := range g.board {
|
|
|
|
|
for _, space := range row {
|
|
|
|
|
if space.state == enemy {
|
|
|
|
|
return
|
|
|
|
|
winner := g.Player()
|
|
|
|
|
if paikaMoveCounter >= 5 {
|
|
|
|
|
var counter = make(map[int]int)
|
|
|
|
|
for _, row := range g.board {
|
|
|
|
|
for _, space := range row {
|
|
|
|
|
counter[space.state]++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if counter[Black] > counter[White] {
|
|
|
|
|
winner = "Black"
|
|
|
|
|
} else if counter[White] > counter[Black] {
|
|
|
|
|
winner = "White"
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
winner = "No one"
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
enemy := g.Enemy()
|
|
|
|
|
for _, row := range g.board {
|
|
|
|
|
for _, space := range row {
|
|
|
|
|
if space.state == enemy {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("GAME OVER! %s wins!\n", g.Player())
|
|
|
|
|
fmt.Printf("GAME OVER! %s wins!\n", winner)
|
|
|
|
|
termios.Restore()
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
@ -354,6 +412,7 @@ func (g *Game) TakeTurn() {
|
|
|
|
|
fmt.Print("\n")
|
|
|
|
|
if lowIn := strings.ToLower(input); strings.HasPrefix("pass", lowIn) || strings.HasPrefix("done", lowIn) {
|
|
|
|
|
if firstMove {
|
|
|
|
|
// TODO make this doable, but have it forfeit?
|
|
|
|
|
ShowError("Cannot pass before making any moves on your turn")
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
@ -382,6 +441,11 @@ func (g *Game) TakeTurn() {
|
|
|
|
|
ShowError(err.Error())
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// FIXME this does not work
|
|
|
|
|
// if g.invalidPaika(m) {
|
|
|
|
|
// ShowError("Must attack when an attack is available")
|
|
|
|
|
// continue
|
|
|
|
|
// }
|
|
|
|
|
dead, err := g.MoveAndDestroyStones(m)
|
|
|
|
|
if err != nil {
|
|
|
|
|
ShowError(err.Error())
|
|
|
|
@ -406,6 +470,14 @@ func ShowError(e string) {
|
|
|
|
|
Getch()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func UpdatePaikaCounter(dead int) {
|
|
|
|
|
if dead == 0 {
|
|
|
|
|
paikaMoveCounter += 1
|
|
|
|
|
} else {
|
|
|
|
|
paikaMoveCounter = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *Game) Play() {
|
|
|
|
|
var c cpu
|
|
|
|
|
for {
|
|
|
|
@ -415,7 +487,7 @@ func (g *Game) Play() {
|
|
|
|
|
fmt.Print(g.String())
|
|
|
|
|
m, approach, attacking, continuation := c.PickMove(g)
|
|
|
|
|
if attacking {
|
|
|
|
|
g.RemoveDeadStones(m, true, approach)
|
|
|
|
|
UpdatePaikaCounter(g.RemoveDeadStones(m, true, approach))
|
|
|
|
|
}
|
|
|
|
|
g.board[m.toRow][m.toCol].state = g.turn
|
|
|
|
|
g.board[m.fromRow][m.fromCol].state = Empty
|
|
|
|
@ -437,7 +509,7 @@ func (g *Game) Play() {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
bl = append(bl, point{cont.toRow, cont.toCol})
|
|
|
|
|
g.RemoveDeadStones(cont, true, approach)
|
|
|
|
|
UpdatePaikaCounter(g.RemoveDeadStones(cont, true, approach))
|
|
|
|
|
g.board[cont.toRow][cont.toCol].state = g.turn
|
|
|
|
|
g.board[cont.fromRow][cont.fromCol].state = Empty
|
|
|
|
|
|
|
|
|
|