Даниел обнови решението на 21.01.2016 00:02 (преди над 2 години)
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+)
+
+type empty struct{}
+type pair [2]int64
+
+type GameOfLifeHandler struct {
+ alive map[pair]empty
+ gen int64
+ *http.ServeMux
+}
+
+type cellStatusS struct {
+ Alive bool `json:"alive"`
+}
+
+type generationS struct {
+ Generation int64 `json:"generation"`
+ Living []pair `json:"living"`
+}
+
+type cellsS struct {
+ Cells []struct {
+ X int64 `json:"x"`
+ Y int64 `json:"y"`
+ }
+}
+
+func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
+ golh := &GameOfLifeHandler{map[pair]empty{}, 0, http.NewServeMux()}
+
+ for _, v := range cells {
+ golh.alive[v] = empty{}
+ }
+
+ golh.HandleFunc("/cell/status/", func(rw http.ResponseWriter, r *http.Request) {
+ defer r.Body.Close()
+ if r.Method == "GET" {
+ q := r.URL.Query()
+ x, errx := strconv.ParseInt(q["x"][0], 10, 64)
+ y, erry := strconv.ParseInt(q["y"][0], 10, 64)
+ if errx != nil || erry != nil {
+ rw.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintf(rw, "'x' and 'y' should be int64s")
+ return
+ }
+ rw.WriteHeader(http.StatusOK)
+ res, _ := json.Marshal(golh.getCellStatus(x, y))
+ fmt.Fprintf(rw, "%s", res)
+ } else {
+ rw.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+ golh.HandleFunc("/generation/", func(rw http.ResponseWriter, r *http.Request) {
+ defer r.Body.Close()
+ if r.Method == "GET" {
+ rw.WriteHeader(http.StatusOK)
+ res, _ := json.Marshal(golh.getGeneration())
+ fmt.Fprintf(rw, "%s", res)
+ } else {
+ rw.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+ golh.HandleFunc("/cells/", func(rw http.ResponseWriter, r *http.Request) {
+ defer r.Body.Close()
+ if r.Method == "POST" {
+ var cells cellsS
+ contents, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ rw.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintf(rw, "I failed with reading the request's body")
+ return
+ }
+ err = json.Unmarshal(contents, &cells)
+ if err != nil {
+ rw.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintf(rw, "Malformed json was passed")
+ return
+ }
+ var cellsSlice []pair
+ for _, v := range cells.Cells {
+ cellsSlice = append(cellsSlice, pair{v.X, v.Y})
+ }
+ golh.postCells(cellsSlice)
+ rw.WriteHeader(http.StatusNoContent)
+ } else {
+ rw.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+ golh.HandleFunc("/generation/evolve/", func(rw http.ResponseWriter, r *http.Request) {
+ defer r.Body.Close()
+ if r.Method == "POST" {
+ golh.postGenerationEvolve()
+ rw.WriteHeader(http.StatusNoContent)
+ } else {
+ rw.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+ golh.HandleFunc("/reset/", func(rw http.ResponseWriter, r *http.Request) {
+ defer r.Body.Close()
+ if r.Method == "POST" {
+ golh.postReset()
+ rw.WriteHeader(http.StatusNoContent)
+ } else {
+ rw.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+
+ return golh
+}
+
+func (g *GameOfLifeHandler) getCellStatus(x int64, y int64) cellStatusS {
+ _, ok := g.alive[pair{x, y}]
+ return cellStatusS{ok}
+}
+
+func (g *GameOfLifeHandler) getGeneration() generationS {
+ var cells []pair
+ for k, _ := range g.alive {
+ cells = append(cells, k)
+ }
+ return generationS{g.gen, cells}
+}
+
+func (g *GameOfLifeHandler) postCells(cells []pair) {
+ for _, i := range cells {
+ if _, ok := g.alive[i]; !ok {
+ g.alive[i] = empty{}
+ }
+ }
+}
+
+func (g *GameOfLifeHandler) postGenerationEvolve() {
+ g.gen++
+ cells := g.significantCells()
+
+ for k, _ := range cells {
+ n := g.neighbours(k[0], k[1])
+ if _, ok := g.alive[k]; (ok && n == 2) || n == 3 {
+ g.alive[k] = empty{}
+ } else {
+ delete(g.alive, k)
+ }
+ }
+}
+
+var nes = [...]pair{{-1, -1}, {-1, 0}, {-1, 1},
+ {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}
+
+func (g *GameOfLifeHandler) significantCells() map[pair]empty {
+ cells := g.alive
+ for k, _ := range g.alive {
+ for _, v := range nes {
+ cells[pair{k[0] + v[0], k[1] + v[1]}] = empty{}
+ }
+ }
+ return cells
+}
+
+func (g *GameOfLifeHandler) neighbours(x int64, y int64) int8 {
+ count := int8(0)
+ for _, v := range nes {
+ if _, ok := g.alive[pair{x + v[0], y + v[1]}]; ok {
+ count++
+ }
+ }
+ return count
+}
+
+func (g *GameOfLifeHandler) postReset() {
+ g.alive = map[pair]empty{}
+ g.gen = 0
+}
Мого хубаво решение. Особено ми харесва type empty struct{}
. Мисля, че можеш да го направиш още по - добро ако го пробваш с конкурентни кънекции за различни endpoint-и. Знай, че go HTTP сървърите правят отделна goroutine-а за всяка кънекция. Това, потенциално, е отделна нишка.
Сега прочетох по - внимателно решението ти. Пробвал ли си добавяне на клетки? Пробвал ли си еволюцията? Ако си напишеш по един тест за тези две неща няма да сгрешиш.