Решение на Game of Life от Анонимен Потребител 1

Обратно към всички решения

Към профила на Анонимен Потребител 1

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 7 успешни тест(а)
  • 7 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"fmt"
"html"
"io"
"io/ioutil"
"net/http"
"strconv"
)
type GameOfLifeHandler struct {
Living [][2]int64 `json:"living"`
Generation int `json:"generation"`
}
type Coordinate struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
return &GameOfLifeHandler{m, 0}
}
func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := html.EscapeString(r.URL.Path)
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
if path == "/cell/status/" {
xVal := r.FormValue("x")
yVal := r.FormValue("y")
x, e1 := strconv.ParseInt(xVal, 10, 64)
y, e2 := strconv.ParseInt(yVal, 10, 64)
if e1 != nil || e2 != nil {
http.Error(w, "Invalid x and y coordinates.", http.StatusBadRequest)
return
}
io.WriteString(w, fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y)))
} else if path == "/generation" {
b, _ := json.Marshal(h)
w.Write(b)
}
} else if r.Method == "POST" {
switch path {
case "/cells":
coords := make([]Coordinate, 0)
bs, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(bs, &coords)
if err != nil {
http.Error(w, "Wrong JSON format.", http.StatusBadRequest)
return
}
if h == nil {
h = NewGameOfLifeHandler([][2]int64{})
}
for _, coord := range coords {
if !h.isAlive(coord.X, coord.Y) {
h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
}
}
w.WriteHeader(http.StatusCreated)
case "/generation/evolve/":
h.evolve()
w.WriteHeader(http.StatusNoContent)
case "/reset":
h.Living = h.Living[:0]
h.Generation = 0
w.WriteHeader(http.StatusNoContent)
}
}
}
func (h *GameOfLifeHandler) evolve() {
h.Generation += 1
newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
copy(newSlice, h.Living)
deleted := 0
// step 1 - kill over- or underpopulated cells
for i, coord := range h.Living {
x := coord[0]
y := coord[1]
neighbors := h.countNeighbors(x, y)
if neighbors < 2 || neighbors > 3 {
newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
deleted += 1
}
}
// step 2 - reproduce dead cells with 3 neighbours
for _, coord := range h.Living {
x := coord[0]
y := coord[1]
if h.shouldReproduce(x-1, y-1) {
newSlice = append(newSlice, [2]int64{x - 1, y - 1})
}
if h.shouldReproduce(x, y-1) {
newSlice = append(newSlice, [2]int64{x, y - 1})
}
if h.shouldReproduce(x+1, y-1) {
newSlice = append(newSlice, [2]int64{x + 1, y - 1})
}
if h.shouldReproduce(x-1, y) {
newSlice = append(newSlice, [2]int64{x - 1, y})
}
if h.shouldReproduce(x+1, y) {
newSlice = append(newSlice, [2]int64{x + 1, y})
}
if h.shouldReproduce(x-1, y+1) {
newSlice = append(newSlice, [2]int64{x - 1, y + 1})
}
if h.shouldReproduce(x, y+1) {
newSlice = append(newSlice, [2]int64{x, y + 1})
}
if h.shouldReproduce(x+1, y+1) {
newSlice = append(newSlice, [2]int64{x + 1, y + 1})
}
}
copy(h.Living, newSlice)
}
func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
}
func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
count := 0
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
continue
}
deltaX := coord[0] - x
deltaY := coord[1] - y
if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
count += 1
}
}
return count
}
func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
return true
}
}
return false
}

Лог от изпълнението

▸ Покажи лога

История (5 версии и 3 коментара)

Антоан обнови решението на 17.01.2016 01:16 (преди над 2 години)

▸ Покажи разликите
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "html"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+)
+
+type GameOfLifeHandler struct {
+ Living [][2]int64 `json:"living"`
+ Generation int `json:"generation"`
+}
+
+type Coordinate struct {
+ X int64 `json:"x"`
+ Y int64 `json:"y"`
+}
+
+func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
+ return &GameOfLifeHandler{m, 0}
+}
+
+func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ path := html.EscapeString(r.URL.Path)
+ w.Header().Set("Content-Type", "application/json")
+
+ if r.Method == "GET" {
+ if path == "/cell/status/" {
+
+ xVal := r.FormValue("x")
+ yVal := r.FormValue("y")
+
+ x, e1 := strconv.ParseInt(xVal, 10, 64)
+ y, e2 := strconv.ParseInt(yVal, 10, 64)
+
+ if e1 != nil || e2 != nil {
+ w.Write([]byte("Invalid x and y coordinates."))
+ w.WriteHeader(400)
+ return
+ }
+
+ w.Write([]byte(fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y))))
+ w.WriteHeader(204)
+ } else if path == "/generation" {
+ b, _ := json.Marshal(h)
+ w.Write([]byte(b))
+ w.WriteHeader(204)
+ }
+ } else if r.Method == "POST" {
+ switch path {
+ case "/cells":
+ coords := make([]Coordinate, 0)
+ bs, _ := ioutil.ReadAll(r.Body)
+ err := json.Unmarshal(bs, &coords)
+ if err != nil {
+ w.Write([]byte("Wrong JSON format."))
+ w.WriteHeader(400)
+ return
+ }
+
+ if h == nil {
+ h = NewGameOfLifeHandler([][2]int64{})
+ }
+
+ for _, coord := range coords {
+ if !h.isAlive(coord.X, coord.Y) {
+ h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
+ }
+ }
+
+ w.WriteHeader(201)
+ case "/generation/evolve/":
+ h.evolve()
+ w.WriteHeader(204)
+
+ case "/reset":
+ h.Living = h.Living[:0]
+ h.Generation = 0
+ w.WriteHeader(204)
+ }
+ }
+}
+
+func (h *GameOfLifeHandler) evolve() {
+ h.Generation += 1
+
+ newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
+ copy(newSlice, h.Living)
+
+ deleted := 0
+
+ // step 1 - kill over- or underpopulated cells
+ for i, coord := range h.Living {
+ x := coord[0]
+ y := coord[1]
+ neighbors := h.countNeighbors(x, y)
+
+ if neighbors < 2 || neighbors > 3 {
+ newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
+ deleted += 1
+ }
+ }
+
+ // step 2 - reproduce dead cells with 3 neighbours
+ for _, coord := range h.Living {
+ x := coord[0]
+ y := coord[1]
+
+ if h.shouldReproduce(x-1, y-1) {
+ newSlice = append(newSlice, [2]int64{x - 1, y - 1})
+ }
+
+ if h.shouldReproduce(x, y-1) {
+ newSlice = append(newSlice, [2]int64{x, y - 1})
+ }
+
+ if h.shouldReproduce(x+1, y-1) {
+ newSlice = append(newSlice, [2]int64{x + 1, y - 1})
+ }
+
+ if h.shouldReproduce(x-1, y) {
+ newSlice = append(newSlice, [2]int64{x - 1, y})
+ }
+
+ if h.shouldReproduce(x+1, y) {
+ newSlice = append(newSlice, [2]int64{x + 1, y})
+ }
+
+ if h.shouldReproduce(x-1, y+1) {
+ newSlice = append(newSlice, [2]int64{x - 1, y + 1})
+ }
+
+ if h.shouldReproduce(x, y+1) {
+ newSlice = append(newSlice, [2]int64{x, y + 1})
+ }
+
+ if h.shouldReproduce(x+1, y+1) {
+ newSlice = append(newSlice, [2]int64{x + 1, y + 1})
+ }
+ }
+
+ copy(h.Living, newSlice)
+}
+
+func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
+ return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
+}
+
+func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
+ count := 0
+ for _, coord := range h.Living {
+ if coord[0] == x && coord[1] == y {
+ continue
+ }
+
+ deltaX := coord[0] - x
+ deltaY := coord[1] - y
+ if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
+ count += 1
+ }
+ }
+
+ return count
+}
+
+func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
+ for _, coord := range h.Living {
+ if coord[0] == x && coord[1] == y {
+ return true
+ }
+ }
+
+ return false
+}

Mного добре! Подхода от slice с координати на живи клетки прави решението ти да заема много малко памет. Дори си се сетил да сложиш Content-Type.

Обаче мисля, че можеш да го направиш по - хубаво. Имаш и много време за това т.к. си предал задачата доволно рано.

Мисля си, че секцията с няколко вложени if-а и switch-а е доста трудна за четене. Ако разгледаш внимателно http пакета ще намериш полезни неща, които ще ти да позволят на пренапишеш тази секция по - ясно.

Виждам, че използваш fmt за писане на отговори. Разгледай този пакет по - внимателно и ще намериш по - хубав начин да напишеш неща като w.Write([]byte(fmt.Sprintf(...))), които виждам. Може да стане не само по - четимо, но и доста по - ефективно.

Също така си мисля, че не използваш WriteHeader по начина, по който си възнамерявал. Прочети внимателно документацията на ResponseWriter. И поглед на константите ще е полезен.

Давам ти само насоки вместо да ти казвам кое, според мен, е добра идея. Сигурен съм, че ще ги намериш сам и процеса ще ти е по - интересен по този начин.

Антоан обнови решението на 18.01.2016 01:05 (преди над 2 години)

▸ Покажи разликите
package main
import (
"encoding/json"
"fmt"
"html"
+ "io"
"io/ioutil"
"net/http"
"strconv"
)
type GameOfLifeHandler struct {
Living [][2]int64 `json:"living"`
Generation int `json:"generation"`
}
type Coordinate struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
return &GameOfLifeHandler{m, 0}
}
func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := html.EscapeString(r.URL.Path)
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
if path == "/cell/status/" {
xVal := r.FormValue("x")
yVal := r.FormValue("y")
x, e1 := strconv.ParseInt(xVal, 10, 64)
y, e2 := strconv.ParseInt(yVal, 10, 64)
if e1 != nil || e2 != nil {
- w.Write([]byte("Invalid x and y coordinates."))
- w.WriteHeader(400)
+ http.Error(w, "Invalid x and y coordinates.", http.StatusBadRequest)
return
}
- w.Write([]byte(fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y))))
+ io.WriteString(w, fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y)))
w.WriteHeader(204)
} else if path == "/generation" {
b, _ := json.Marshal(h)
w.Write([]byte(b))
w.WriteHeader(204)
}
} else if r.Method == "POST" {
switch path {
case "/cells":
coords := make([]Coordinate, 0)
bs, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(bs, &coords)
if err != nil {
- w.Write([]byte("Wrong JSON format."))
- w.WriteHeader(400)
+ http.Error(w, "Wrong JSON format.", http.StatusBadRequest)
return
}
if h == nil {
h = NewGameOfLifeHandler([][2]int64{})
}
for _, coord := range coords {
if !h.isAlive(coord.X, coord.Y) {
h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
}
}
w.WriteHeader(201)
case "/generation/evolve/":
h.evolve()
w.WriteHeader(204)
case "/reset":
h.Living = h.Living[:0]
h.Generation = 0
w.WriteHeader(204)
}
}
}
func (h *GameOfLifeHandler) evolve() {
h.Generation += 1
newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
copy(newSlice, h.Living)
deleted := 0
// step 1 - kill over- or underpopulated cells
for i, coord := range h.Living {
x := coord[0]
y := coord[1]
neighbors := h.countNeighbors(x, y)
if neighbors < 2 || neighbors > 3 {
newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
deleted += 1
}
}
// step 2 - reproduce dead cells with 3 neighbours
for _, coord := range h.Living {
x := coord[0]
y := coord[1]
if h.shouldReproduce(x-1, y-1) {
newSlice = append(newSlice, [2]int64{x - 1, y - 1})
}
if h.shouldReproduce(x, y-1) {
newSlice = append(newSlice, [2]int64{x, y - 1})
}
if h.shouldReproduce(x+1, y-1) {
newSlice = append(newSlice, [2]int64{x + 1, y - 1})
}
if h.shouldReproduce(x-1, y) {
newSlice = append(newSlice, [2]int64{x - 1, y})
}
if h.shouldReproduce(x+1, y) {
newSlice = append(newSlice, [2]int64{x + 1, y})
}
if h.shouldReproduce(x-1, y+1) {
newSlice = append(newSlice, [2]int64{x - 1, y + 1})
}
if h.shouldReproduce(x, y+1) {
newSlice = append(newSlice, [2]int64{x, y + 1})
}
if h.shouldReproduce(x+1, y+1) {
newSlice = append(newSlice, [2]int64{x + 1, y + 1})
}
}
copy(h.Living, newSlice)
}
func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
}
func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
count := 0
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
continue
}
deltaX := coord[0] - x
deltaY := coord[1] - y
if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
count += 1
}
}
return count
}
func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
return true
}
}
return false
-}
+}

Антоан обнови решението на 18.01.2016 01:13 (преди над 2 години)

▸ Покажи разликите
package main
import (
"encoding/json"
"fmt"
"html"
"io"
"io/ioutil"
"net/http"
"strconv"
)
type GameOfLifeHandler struct {
Living [][2]int64 `json:"living"`
Generation int `json:"generation"`
}
type Coordinate struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
return &GameOfLifeHandler{m, 0}
}
func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := html.EscapeString(r.URL.Path)
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
if path == "/cell/status/" {
xVal := r.FormValue("x")
yVal := r.FormValue("y")
x, e1 := strconv.ParseInt(xVal, 10, 64)
y, e2 := strconv.ParseInt(yVal, 10, 64)
if e1 != nil || e2 != nil {
http.Error(w, "Invalid x and y coordinates.", http.StatusBadRequest)
return
}
io.WriteString(w, fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y)))
- w.WriteHeader(204)
+ w.WriteHeader(http.StatusNoContent)
} else if path == "/generation" {
b, _ := json.Marshal(h)
- w.Write([]byte(b))
- w.WriteHeader(204)
+ w.Write(b)
+ w.WriteHeader(http.StatusNoContent)
}
} else if r.Method == "POST" {
switch path {
case "/cells":
coords := make([]Coordinate, 0)
bs, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(bs, &coords)
if err != nil {
http.Error(w, "Wrong JSON format.", http.StatusBadRequest)
return
}
if h == nil {
h = NewGameOfLifeHandler([][2]int64{})
}
for _, coord := range coords {
if !h.isAlive(coord.X, coord.Y) {
h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
}
}
- w.WriteHeader(201)
+ w.WriteHeader(http.StatusCreated)
case "/generation/evolve/":
h.evolve()
- w.WriteHeader(204)
+ w.WriteHeader(http.StatusNoContent)
case "/reset":
h.Living = h.Living[:0]
h.Generation = 0
- w.WriteHeader(204)
+ w.WriteHeader(http.StatusNoContent)
}
}
}
func (h *GameOfLifeHandler) evolve() {
h.Generation += 1
newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
copy(newSlice, h.Living)
deleted := 0
// step 1 - kill over- or underpopulated cells
for i, coord := range h.Living {
x := coord[0]
y := coord[1]
neighbors := h.countNeighbors(x, y)
if neighbors < 2 || neighbors > 3 {
newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
deleted += 1
}
}
// step 2 - reproduce dead cells with 3 neighbours
for _, coord := range h.Living {
x := coord[0]
y := coord[1]
if h.shouldReproduce(x-1, y-1) {
newSlice = append(newSlice, [2]int64{x - 1, y - 1})
}
if h.shouldReproduce(x, y-1) {
newSlice = append(newSlice, [2]int64{x, y - 1})
}
if h.shouldReproduce(x+1, y-1) {
newSlice = append(newSlice, [2]int64{x + 1, y - 1})
}
if h.shouldReproduce(x-1, y) {
newSlice = append(newSlice, [2]int64{x - 1, y})
}
if h.shouldReproduce(x+1, y) {
newSlice = append(newSlice, [2]int64{x + 1, y})
}
if h.shouldReproduce(x-1, y+1) {
newSlice = append(newSlice, [2]int64{x - 1, y + 1})
}
if h.shouldReproduce(x, y+1) {
newSlice = append(newSlice, [2]int64{x, y + 1})
}
if h.shouldReproduce(x+1, y+1) {
newSlice = append(newSlice, [2]int64{x + 1, y + 1})
}
}
copy(h.Living, newSlice)
}
func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
}
func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
count := 0
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
continue
}
deltaX := coord[0] - x
deltaY := coord[1] - y
if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
count += 1
}
}
return count
}
func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
return true
}
}
return false
}

Антоан обнови решението на 18.01.2016 01:19 (преди над 2 години)

▸ Покажи разликите
package main
import (
"encoding/json"
"fmt"
"html"
"io"
"io/ioutil"
"net/http"
"strconv"
)
type GameOfLifeHandler struct {
Living [][2]int64 `json:"living"`
Generation int `json:"generation"`
}
type Coordinate struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
return &GameOfLifeHandler{m, 0}
}
func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := html.EscapeString(r.URL.Path)
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
if path == "/cell/status/" {
xVal := r.FormValue("x")
yVal := r.FormValue("y")
x, e1 := strconv.ParseInt(xVal, 10, 64)
y, e2 := strconv.ParseInt(yVal, 10, 64)
if e1 != nil || e2 != nil {
http.Error(w, "Invalid x and y coordinates.", http.StatusBadRequest)
return
}
+ w.WriteHeader(http.StatusNoContent)
io.WriteString(w, fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y)))
- w.WriteHeader(http.StatusNoContent)
} else if path == "/generation" {
b, _ := json.Marshal(h)
- w.Write(b)
- w.WriteHeader(http.StatusNoContent)
+ w.WriteHeader(http.StatusNoContent)
+ w.Write(b)
}
} else if r.Method == "POST" {
switch path {
case "/cells":
coords := make([]Coordinate, 0)
bs, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(bs, &coords)
if err != nil {
http.Error(w, "Wrong JSON format.", http.StatusBadRequest)
return
}
if h == nil {
h = NewGameOfLifeHandler([][2]int64{})
}
for _, coord := range coords {
if !h.isAlive(coord.X, coord.Y) {
h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
}
}
w.WriteHeader(http.StatusCreated)
case "/generation/evolve/":
h.evolve()
w.WriteHeader(http.StatusNoContent)
case "/reset":
h.Living = h.Living[:0]
h.Generation = 0
w.WriteHeader(http.StatusNoContent)
}
}
}
func (h *GameOfLifeHandler) evolve() {
h.Generation += 1
newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
copy(newSlice, h.Living)
deleted := 0
// step 1 - kill over- or underpopulated cells
for i, coord := range h.Living {
x := coord[0]
y := coord[1]
neighbors := h.countNeighbors(x, y)
if neighbors < 2 || neighbors > 3 {
newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
deleted += 1
}
}
// step 2 - reproduce dead cells with 3 neighbours
for _, coord := range h.Living {
x := coord[0]
y := coord[1]
if h.shouldReproduce(x-1, y-1) {
newSlice = append(newSlice, [2]int64{x - 1, y - 1})
}
if h.shouldReproduce(x, y-1) {
newSlice = append(newSlice, [2]int64{x, y - 1})
}
if h.shouldReproduce(x+1, y-1) {
newSlice = append(newSlice, [2]int64{x + 1, y - 1})
}
if h.shouldReproduce(x-1, y) {
newSlice = append(newSlice, [2]int64{x - 1, y})
}
if h.shouldReproduce(x+1, y) {
newSlice = append(newSlice, [2]int64{x + 1, y})
}
if h.shouldReproduce(x-1, y+1) {
newSlice = append(newSlice, [2]int64{x - 1, y + 1})
}
if h.shouldReproduce(x, y+1) {
newSlice = append(newSlice, [2]int64{x, y + 1})
}
if h.shouldReproduce(x+1, y+1) {
newSlice = append(newSlice, [2]int64{x + 1, y + 1})
}
}
copy(h.Living, newSlice)
}
func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
}
func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
count := 0
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
continue
}
deltaX := coord[0] - x
deltaY := coord[1] - y
if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
count += 1
}
}
return count
}
func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
return true
}
}
return false
-}
+}

Благодаря за обратната връзка. Мисля, че схванах почти всички насоки, които ми даде.

Относно преработването на кода със switch-а, единственото нещо, за което се сещам, е да използвам ServeMux, но тогава ще трябва да имам отделен handler за всяка заявка, а искаме handler-a да бъде само един - GameOfLifeHandler. Явно пропускам нещо.

EDIT: Ами ако GameOfLifeHandler наследява ServeMux и единствено във функцията NewGameOfLifeHandler добавя методите с mux.HandleFunc? Това използвана практика ли е в Go?

Да, това би бил много хубав подход!

Сега, на по - внимателно прочитане на кода ти, забелязах още няколко неща.

Не използваш gofmt и поради това кода ти страда от презентационни проблеми :Д Забележи колко странно е форматиран на сайта. Добра практика ще е да започнеш да го ползваш на всеки save на файла. Редактора ти трябва да може да ти помогне с това.

Пробвай по - внимателно отговорите на решението ти в случаите, в които дъската е празна, както и отговорите на GET /cell/status. Може би, напиши си тест за тях. Мога да ти кажа, че имаш regression след като направи последната промяна. Тестовете ти вероятно щяха да го намерят.

Антоан обнови решението на 26.01.2016 12:24 (преди над 2 години)

▸ Покажи разликите
package main
import (
"encoding/json"
"fmt"
"html"
"io"
"io/ioutil"
"net/http"
"strconv"
)
type GameOfLifeHandler struct {
Living [][2]int64 `json:"living"`
Generation int `json:"generation"`
}
type Coordinate struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
func NewGameOfLifeHandler(m [][2]int64) *GameOfLifeHandler {
return &GameOfLifeHandler{m, 0}
}
func (h *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := html.EscapeString(r.URL.Path)
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
if path == "/cell/status/" {
xVal := r.FormValue("x")
yVal := r.FormValue("y")
x, e1 := strconv.ParseInt(xVal, 10, 64)
y, e2 := strconv.ParseInt(yVal, 10, 64)
if e1 != nil || e2 != nil {
http.Error(w, "Invalid x and y coordinates.", http.StatusBadRequest)
return
}
- w.WriteHeader(http.StatusNoContent)
io.WriteString(w, fmt.Sprintf("{\"alive\": %t}", h.isAlive(x, y)))
} else if path == "/generation" {
b, _ := json.Marshal(h)
- w.WriteHeader(http.StatusNoContent)
- w.Write(b)
+ w.Write(b)
}
} else if r.Method == "POST" {
switch path {
case "/cells":
coords := make([]Coordinate, 0)
bs, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(bs, &coords)
if err != nil {
http.Error(w, "Wrong JSON format.", http.StatusBadRequest)
return
}
if h == nil {
h = NewGameOfLifeHandler([][2]int64{})
}
for _, coord := range coords {
if !h.isAlive(coord.X, coord.Y) {
h.Living = append(h.Living, [2]int64{coord.X, coord.Y})
}
}
w.WriteHeader(http.StatusCreated)
case "/generation/evolve/":
h.evolve()
w.WriteHeader(http.StatusNoContent)
case "/reset":
h.Living = h.Living[:0]
h.Generation = 0
w.WriteHeader(http.StatusNoContent)
}
}
}
func (h *GameOfLifeHandler) evolve() {
h.Generation += 1
newSlice := make([][2]int64, len(h.Living), 2*cap(h.Living))
copy(newSlice, h.Living)
deleted := 0
// step 1 - kill over- or underpopulated cells
for i, coord := range h.Living {
x := coord[0]
y := coord[1]
neighbors := h.countNeighbors(x, y)
if neighbors < 2 || neighbors > 3 {
newSlice = append(newSlice[:i-deleted], newSlice[i-deleted+1:]...)
deleted += 1
}
}
// step 2 - reproduce dead cells with 3 neighbours
for _, coord := range h.Living {
x := coord[0]
y := coord[1]
if h.shouldReproduce(x-1, y-1) {
newSlice = append(newSlice, [2]int64{x - 1, y - 1})
}
if h.shouldReproduce(x, y-1) {
newSlice = append(newSlice, [2]int64{x, y - 1})
}
if h.shouldReproduce(x+1, y-1) {
newSlice = append(newSlice, [2]int64{x + 1, y - 1})
}
if h.shouldReproduce(x-1, y) {
newSlice = append(newSlice, [2]int64{x - 1, y})
}
if h.shouldReproduce(x+1, y) {
newSlice = append(newSlice, [2]int64{x + 1, y})
}
if h.shouldReproduce(x-1, y+1) {
newSlice = append(newSlice, [2]int64{x - 1, y + 1})
}
if h.shouldReproduce(x, y+1) {
newSlice = append(newSlice, [2]int64{x, y + 1})
}
if h.shouldReproduce(x+1, y+1) {
newSlice = append(newSlice, [2]int64{x + 1, y + 1})
}
}
copy(h.Living, newSlice)
}
func (h *GameOfLifeHandler) shouldReproduce(x int64, y int64) bool {
return !h.isAlive(x, y) && h.countNeighbors(x, y) == 3
}
func (h *GameOfLifeHandler) countNeighbors(x int64, y int64) int {
count := 0
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
continue
}
deltaX := coord[0] - x
deltaY := coord[1] - y
if deltaX >= -1 && deltaX <= 1 && deltaY >= -1 && deltaY <= 1 {
count += 1
}
}
return count
}
func (h *GameOfLifeHandler) isAlive(x int64, y int64) bool {
for _, coord := range h.Living {
if coord[0] == x && coord[1] == y {
return true
}
}
return false
-}
+}