board.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package board
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "math/rand"
  8. )
  9. type Board struct {
  10. Cols int `json:"cols"`
  11. Rows int `json:"rows"`
  12. Finish Coordinate `json:"finish"`
  13. Tiles []Tile `json:"-"`
  14. }
  15. const maxIceWidth = 26
  16. // Create a new randomly generated board.
  17. func New(cols, rows int) *Board {
  18. b := &Board{
  19. Cols: cols,
  20. Rows: rows,
  21. Tiles: make([]Tile, rows*cols)}
  22. for y := 0; y < rows; y++ {
  23. for x := 0; x < cols; x++ {
  24. b.randomizeTile(x, y)
  25. }
  26. }
  27. igloY := rand.Intn(rows-1) + 1
  28. b.Set(cols-2, igloY, Iglo)
  29. b.Finish.X = cols - 2
  30. b.Finish.Y = igloY
  31. b.Set(cols-2, igloY-1, Water)
  32. b.Set(cols-2, igloY+1, Water)
  33. return b
  34. }
  35. // Set the tile in column x and row y to val.
  36. func (b *Board) Set(x, y int, val Tile) {
  37. b.Tiles[y*b.Cols+x] = val
  38. }
  39. // Get the tile in column x and row y.
  40. func (b *Board) Get(x, y int) Tile {
  41. return b.Tiles[y*b.Cols+x]
  42. }
  43. func (b *Board) String() string {
  44. var buffer bytes.Buffer
  45. for y := 0; y < b.Rows; y++ {
  46. for x := 0; x < b.Cols; x++ {
  47. buffer.WriteString(b.Get(x, y).String())
  48. }
  49. buffer.WriteString(fmt.Sprintln())
  50. }
  51. return buffer.String()
  52. }
  53. func (b *Board) WriteJSON(w io.Writer, startCol, startRow, cols, rows int) {
  54. sc, sr, cols, rows := sanitizeViewPort(b, startCol, startRow, cols, rows)
  55. fmt.Fprintf(w, "{\"x\":%v,\"y\":%v,\"rows\":%v,\"cols\":%v,\"tiles\":[", sc, sr, cols, rows)
  56. for y := startRow; y < sr+rows; y++ {
  57. for x := startCol; x < sc+cols; x++ {
  58. if !(x == startCol && y == startRow) {
  59. w.Write([]byte{','})
  60. }
  61. t := &jsonTile{x, y, b.Get(x, y).Name(), ""}
  62. bs, _ := json.Marshal(t)
  63. w.Write(bs)
  64. }
  65. }
  66. fmt.Fprintf(w, "]}")
  67. }
  68. func sanitizeViewPort(b *Board, startCol, startRow, cols, rows int) (int, int, int, int) {
  69. if startCol > b.Cols {
  70. startCol = b.Cols
  71. }
  72. if startCol < 0 {
  73. cols += startCol
  74. startCol = 0
  75. }
  76. if startRow > b.Rows {
  77. startRow = b.Rows
  78. }
  79. if startRow < 0 {
  80. rows += startRow
  81. startRow = 0
  82. }
  83. if startCol+cols > b.Cols {
  84. cols = b.Cols - startCol
  85. }
  86. if startRow+rows > b.Rows {
  87. rows = b.Rows - startRow
  88. }
  89. if cols < 0 {
  90. cols = 0
  91. }
  92. if rows < 0 {
  93. rows = 0
  94. }
  95. return startCol, startRow, cols, rows
  96. }
  97. func (b *Board) randomizeTile(x, y int) {
  98. switch {
  99. case b.isRock(x, y):
  100. b.Set(x, y, Rock)
  101. case b.isIce(x, y):
  102. b.Set(x, y, Ice)
  103. default:
  104. b.Set(x, y, Water)
  105. }
  106. }
  107. func (b *Board) isRock(x, y int) bool {
  108. return rand.Intn(10) > 7
  109. }
  110. func (b *Board) isIce(x, y int) bool {
  111. leftLimit := (b.Cols - maxIceWidth) / 2
  112. rightLimit := b.Cols/2 + maxIceWidth/2
  113. return x > leftLimit && x < rightLimit && rand.Intn(maxIceWidth) >= abs((b.Cols/2)-x)
  114. }
  115. func abs(a int) int {
  116. if a < 0 {
  117. return -a
  118. }
  119. return a
  120. }