package board import ( "bytes" "encoding/json" "fmt" "io" "math/rand" "time" ) 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 { r := rand.New(rand.NewSource(time.Now().UnixNano())) return new(cols, rows, r) } func new(cols, rows int, r *rand.Rand) *Board { b := &Board{ Cols: cols, Rows: rows, Tiles: make([]Tile, rows*cols, rows*cols)} for y := 0; y < rows; y++ { for x := 0; x < cols; x++ { switch { case r.Intn(10) > 7: b.Set(x, y, Rock) case x > (b.Cols-maxIceWidth)/2 && x < b.Cols/2+maxIceWidth/2 && r.Intn(maxIceWidth) >= abs((b.Cols/2)-x): b.Set(x, y, Ice) default: b.Set(x, y, Water) } } } igloY := r.Intn(rows-2) + 1 b.Set(cols-2, igloY, Iglo) b.Finish.X = cols - 2 b.Finish.Y = igloY b.Set(cols-2, igloY-1, Water) b.Set(cols-2, igloY+1, Water) 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 abs(a int) int { if a < 0 { return -a } return a }