package board import ( "bytes" "encoding/json" "fmt" "io" "math/rand" ) type Board struct { Cols int `json:"cols"` Rows int `json:"rows"` Finish Coordinate `json:"finish"` Tiles []Tile `json:"-"` } const maxIceWidth = 26 // Create a new randomly generated board. func New(cols, rows int) *Board { b := &Board{ Cols: cols, Rows: rows, Tiles: make([]Tile, rows*cols)} for y := 0; y < rows; y++ { for x := 0; x < cols; x++ { b.randomizeTile(x, y) } } return b } // Set the tile in column x and row y to val. func (b *Board) Set(x, y int, val Tile) { b.Tiles[y*b.Cols+x] = val } // Get the tile in column x and row y. func (b *Board) Get(x, y int) Tile { return b.Tiles[y*b.Cols+x] } func (b *Board) String() string { var buffer bytes.Buffer for y := 0; y < b.Rows; y++ { for x := 0; x < b.Cols; x++ { buffer.WriteString(b.Get(x, y).String()) } buffer.WriteString(fmt.Sprintln()) } return buffer.String() } func (b *Board) WriteJSON(w io.Writer, startCol, startRow, cols, rows int) { sc, sr, cols, rows := sanitizeViewPort(b, startCol, startRow, cols, rows) fmt.Fprintf(w, "{\"x\":%v,\"y\":%v,\"rows\":%v,\"cols\":%v,\"tiles\":[", sc, sr, cols, rows) for y := startRow; y < sr+rows; y++ { for x := startCol; x < sc+cols; x++ { if (!(x == startCol && y == startRow)) { w.Write([]byte{','}) } t := &jsonTile{x, y, b.Get(x, y).Name(), ""} bs, _ := json.Marshal(t) w.Write(bs) } } fmt.Fprintf(w, "]}") } func sanitizeViewPort(b *Board, startCol, startRow, cols, rows int) (int, int, int, int) { if startCol > b.Cols { startCol = b.Cols } if startCol < 0 { cols += startCol startCol = 0 } if startRow > b.Rows { startRow = b.Rows } if startRow < 0 { rows += startRow startRow = 0 } if startCol+cols > b.Cols { cols = b.Cols - startCol } if startRow+rows > b.Rows { rows = b.Rows - startRow } if cols < 0 { cols = 0 } if rows < 0 { rows = 0 } return startCol, startRow, cols, rows } func (b *Board) randomizeTile(x, y int) { switch { case b.isIglo(x, y): b.Set(x, y, Iglo) b.Finish.X = x b.Finish.Y = y case b.isRock(x, y): b.Set(x, y, Rock) case b.isIce(x, y): b.Set(x, y, Ice) default: b.Set(x, y, Water) } } func (b *Board) isIglo(x, y int) bool { return x == (b.Cols-1) && y == (b.Rows-1)/2 } func (b *Board) isRock(x, y int) bool { return rand.Intn(10) > 7 } func (b *Board) isIce(x, y int) bool { leftLimit := (b.Cols - maxIceWidth) / 2 rightLimit := b.Cols/2 + maxIceWidth/2 return x > leftLimit && x < rightLimit && rand.Intn(maxIceWidth) >= abs((b.Cols/2)-x) } func abs(a int) int { if a < 0 { return -a } return a }