From 6d0b936e7bbc4845601d1d014114a32a82e393ed Mon Sep 17 00:00:00 2001 From: sloum Date: Fri, 16 Apr 2021 14:59:57 -0700 Subject: [PATCH] Solves minor ai issues, comments out broken paika check, and adds sequential paika limit with game end if crossed --- cpu.go | 1 - main.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/cpu.go b/cpu.go index f8d4065..9758f12 100644 --- a/cpu.go +++ b/cpu.go @@ -62,7 +62,6 @@ func (p *place) FindBestDir() { } } -// FIXME This is broken func ScoreContinuation(m move, g *Game, blacklist []point) (move, bool, error) { p := place{m.toRow, m.toCol, g.board[m.toRow][m.toCol].strong, make([]score, 0, 8), 0, make([]int, 0, 7)} p.Score(g) diff --git a/main.go b/main.go index 3899092..721d0b1 100644 --- a/main.go +++ b/main.go @@ -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