Skip to content

Instantly share code, notes, and snippets.

@chronologos
Last active December 8, 2019 22:08
Show Gist options
  • Save chronologos/a53986c8fd3b183c506607873e976d7a to your computer and use it in GitHub Desktop.
Save chronologos/a53986c8fd3b183c506607873e976d7a to your computer and use it in GitHub Desktop.
koppel-week5
package control
// Read from stdin and write to a board.
func Act(b board.Board, f *os.File) error {}
func nuke(b board.Board, coords *board.Coordinates) error {
// Check if cell is unrevealed.
// If cell has mine, toggle it to not having a mine.
// game loop in main function needs to re-render board.
}
package display
// Draw a board.
func RenderBoard(b board.BoardView) {}
package board
// 3 layer architecture
// board state
// control layer
// presentation layer
// Board state
type BoardView interface {
// Board stores source of truth for coordinates of each cell.
Cell(_ Coordinates) (Cell, error)
Coords(_ Cell) (Coordinates, error)
MaxCols() int
MaxRows() int
// BoardGameState will be interface. Implemented by one of {Inprogress or Ended}.
GameState() BoardGameState
}
type Board interface {
BoardView // Reuse read-only interface.
Click(_ Coordinates) error
}
func (b *Board) AdjacentCoords(c Coordinates) []Coordinates {}
type Coordinates interface {
isCoordinate()
}
// Each coordinate system will have noop implementation of `isCoordinate`.
// Methods that work with coordinates e.g. AdjacentCoords(), RenderBoard(), and Act(),
// will need to type switch on the Coordinates interface to perform coordinate system specific actions.
type 2DCoordinates struct {}
type 3DCoordinates struct {}
// etc...
type Cell interface {
IsRevealed() bool
Mine() MineStatus // MineStatus is interface implemented by one of {Mine, Nomine.}
Board() *Board
}
// implements Cell
type RevealedCell struct {
// State() will return RevealedState
}
type RevealedCellState interface {
// private method in interface ensures that only package-internal types that implement this method can satisfy the interface.
// this + type switching is what ast.go uses to represent a sum type. Not quite as graceful as haskell, but has the same result.
revealed()
}
func (rc *RevealedCell) State() RevealedCellState {} // will return {RevealedState}
// implements Cell
// UnrevealedCell will implement a `Click` method that checks if State().(type) == UnflaggedState
type UnrevealedCell struct {
// State() will return one of: {FlaggedState, UnflaggedState}
}
type UnrevealedCellState interface {
unrevealed()
}
func (rc *UnrevealedCell) State() UnrevealedCellState {} // will return one of: {FlaggedState, UnflaggedState, QuestionMarkState}
// Use CellState interface as stand-in for sum type in Go.
type CellState interface {
Name() string
}
// implements UnrevealedCellState
type FlaggedState struct {}
// implements UnrevealedCellState
type UnflaggedState struct {}
// implements RevealedCellState
type RevealedState struct {}
// implements UnrevealedCellState
type QuestionMarkState struct {}
// Only RevealedCell implements AdjacentMines.
func (c *RevealedCell) AdjacentMines() (count int) {
adjacentCoords := c.Board.AdjacentCoords(c.Board.Coords(c))
for _, coord := range adjacentCoords {
adjacentCell := c.Board.Cells(coord)
switch adjacentCell.Mine().(type) {
case Mine:
count += 1
}
}
return count
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment