Skip to content
Snippets Groups Projects
Select Git revision
  • b9a520f96ddb03a62934f60c26b10c9dc50f4aa9
  • master default protected
2 results

sidecheck.go

Blame
  • sidecheck.go 3.34 KiB
    package sidecheck
    
    import (
    	"strings"
    )
    
    // Constants for the different board piece types.
    const (
    	BOARD int = iota
    	PIECE
    	SELECTED
    )
    
    type coords struct {
    	x, y int
    }
    
    func coordsAround(x, y int) []coords {
    	return []coords{
    		{x - 1, y - 1},
    		{x - 1, y},
    		{x - 1, y + 1},
    		{x, y - 1},
    		{x, y + 1},
    		{x + 1, y - 1},
    		{x + 1, y},
    		{x + 1, y + 1},
    	}
    }
    
    // Board defines a square or rectangular grid to represent a chess-style board.
    type Board struct {
    	rows, cols int
    	board      [][]int
    }
    
    // NewBoard creates an empty Board with the given size.
    func NewBoard(rows, cols int) *Board {
    	board := Board{
    		rows, cols,
    		make([][]int, rows),
    	}
    	for i := 0; i < rows; i++ {
    		board.board[i] = make([]int, cols)
    	}
    	return &board
    }
    
    // StringToBoard creates a Board from a string.
    func StringToBoard(b string) *Board {
    	rows := strings.Split(b, "\n")
    	rowMax := len(rows)
    	if rowMax == 0 {
    		panic("Board needs to have at least 1 row")
    	}
    	colMax := len(rows[0])
    	if colMax == 0 {
    		panic("Board needs to have at least 1 column")
    	}
    
    	board := *NewBoard(rowMax, colMax)
    	for i := 0; i < rowMax; i++ {
    		if len(rows[i]) != colMax {
    			panic("Column mismatch")
    		}
    		for j := 0; j < colMax; j++ {
    			switch rows[i][j] {
    			case '.':
    				board.board[i][j] = BOARD
    			case 'o':
    				board.board[i][j] = PIECE
    			default:
    				panic("Unknown board char encountered")
    			}
    		}
    	}
    	return &board
    }
    
    // Piecep returns true if there's a piece at x, y.
    func (b Board) Piecep(x, y int) bool {
    	if x < 0 || y < 0 || x >= b.rows || y >= b.cols {
    		return false
    	}
    	return b.board[x][y] == PIECE
    }
    
    // String converts Board to a string.
    func (b Board) String() string {
    	var result string
    	spotChar := []string{".", "o", "+"}
    	for _, row := range b.board {
    		for _, spot := range row {
    			result += spotChar[spot]
    		}
    		result += "\n"
    	}
    	return result
    }
    
    // NScheck checks if any pieces allow for a path across.
    func (b Board) NScheck() bool {
    	for j := 0; j < b.cols; j++ {
    		if b.Piecep(0, j) {
    			if found := b.nscheck(newPiece(0, j)); found {
    				return true
    			}
    		}
    	}
    	return false
    }
    
    func (b Board) nscheck(p *piece) bool {
    	if p.x == (b.rows - 1) {
    		return true
    	}
    	cs := coordsAround(p.x, p.y)
    	for _, c := range cs {
    		if c.y > 0 && b.Piecep(c.x, c.y) && !p.seen(c.x, c.y) {
    			next := newPiece(c.x, c.y)
    			next.parent = p
    			if found := b.nscheck(next); found {
    				return true
    			}
    		}
    	}
    	return false
    }
    
    // WEcheck checks if any pieces allow for a path across.
    func (b Board) WEcheck() bool {
    	for i := 0; i < b.rows; i++ {
    		if b.Piecep(i, 0) {
    			if found := b.wecheck(newPiece(i, 0)); found {
    				return true
    			}
    		}
    	}
    	return false
    }
    
    func (b Board) wecheck(p *piece) bool {
    	if p.y == (b.cols - 1) {
    		return true
    	}
    	cs := coordsAround(p.x, p.y)
    	for _, c := range cs {
    		if c.x > 0 && b.Piecep(c.x, c.y) && !p.seen(c.x, c.y) {
    			next := newPiece(c.x, c.y)
    			next.parent = p
    			if found := b.wecheck(next); found {
    				return true
    			}
    		}
    	}
    	return false
    }
    
    // piece tracks a connected line of pieces through a board.
    type piece struct {
    	x, y   int
    	parent *piece
    }
    
    // newPiece creates a new node.
    func newPiece(x, y int) *piece {
    	p := &piece{
    		x:      x,
    		y:      y,
    		parent: nil,
    	}
    	return p
    }
    
    // seen returns is a coord has been seen.
    func (p piece) seen(x, y int) bool {
    	pp := p.parent
    	for pp != nil {
    		if pp.x == x && pp.y == y {
    			return true
    		}
    		pp = pp.parent
    	}
    	return false
    }