Решение на Game of Life от Михаил Здравков

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

Към профила на Михаил Здравков

Резултати

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

Код

package main
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"sync"
)
type GameOfLifeHandler struct {
generation int
living map[[2]int64]struct{}
mutex sync.Mutex
}
func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
switch request.Method {
case "GET":
switch request.URL.Path {
case "/cell/status/":
xStr := request.FormValue("x")
if len(xStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
x, err := strconv.ParseInt(xStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
yStr := request.FormValue("y")
if len(yStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
y, err := strconv.ParseInt(yStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
result, err := gl.CellStatus(x, y)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
case "/generation/":
result, err := gl.GetGeneration()
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
}
case "POST":
switch request.URL.Path {
case "/cells/":
type Cell struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
var cells []Cell
body, err := ioutil.ReadAll(request.Body)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if err := json.Unmarshal(body, &cells); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
cellSlice := make([][2]int64, len(cells))
for i, _ := range cells {
cellSlice[i] = [2]int64{cells[i].X, cells[i].Y}
}
gl.AddCells(cellSlice)
response.WriteHeader(http.StatusCreated)
return
case "/generation/evolve/":
gl.NextGeneration() // nope, no Star Trek here
response.WriteHeader(http.StatusNoContent)
return
case "/reset/":
gl.mutex.Lock()
defer gl.mutex.Unlock()
gl.living = make(map[[2]int64]struct{})
gl.generation = 0
response.WriteHeader(http.StatusNoContent)
return
}
}
switch request.URL.Path {
case "/cell/status/", "/generation/", "/cells/", "/generation/evolve/", "/reset/":
response.WriteHeader(http.StatusMethodNotAllowed)
return
}
response.WriteHeader(http.StatusNotFound)
}
func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
_, ok := gl.living[[2]int64{x, y}]
type result struct {
Alive bool `json:"alive"`
}
return json.Marshal(result{Alive: ok})
}
func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
type result struct {
Generation int `json:"generation"`
Living [][2]int64 `json:"living"`
}
res := result{Generation: gl.generation, Living: make([][2]int64, 0)}
for pos, _ := range gl.living {
res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
}
return json.Marshal(res)
}
func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
gl.mutex.Lock()
defer gl.mutex.Unlock()
for _, cell := range cells {
gl.living[cell] = struct{}{}
}
}
func (gl *GameOfLifeHandler) NextGeneration() {
gl.mutex.Lock()
defer gl.mutex.Unlock()
nextGen := make(map[[2]int64]struct{})
for cell, _ := range gl.living {
livingNeigbours := 0
for _, neighbour := range Neighbours(cell) {
if _, ok := gl.living[neighbour]; ok {
livingNeigbours++
}
livingNeigboursNested := 0
for _, neighbourNested := range Neighbours(neighbour) {
if _, ok := gl.living[neighbourNested]; ok {
livingNeigboursNested++
}
}
// for dead cells to be born
if livingNeigboursNested == 3 {
nextGen[neighbour] = struct{}{}
}
}
// for living cells to remain living
if livingNeigbours == 2 || livingNeigbours == 3 {
nextGen[cell] = struct{}{}
}
}
gl.living = nextGen
gl.generation++
}
func Neighbours(pos [2]int64) [][2]int64 {
relatives := [][2]int64{
[2]int64{0, -1},
[2]int64{0, 1},
[2]int64{-1, 0},
[2]int64{1, 0},
[2]int64{-1, -1},
[2]int64{-1, 1},
[2]int64{1, -1},
[2]int64{1, 1},
}
neighbours := make([][2]int64, 8)
for i, relative := range relatives {
neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
}
return neighbours
}
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
living := make(map[[2]int64]struct{})
for _, pos := range cells {
living[[2]int64{pos[0], pos[1]}] = struct{}{}
}
return &GameOfLifeHandler{generation: 0, living: living}
}

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

PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.005s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.004s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.006s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.007s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.007s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.006s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.006s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.007s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.006s
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
2016/01/26 20:31:11 http: multiple response.WriteHeader calls
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.007s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.009s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.010s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.011s
PASS
ok  	_/tmp/d20160126-5892-19gpkdg	0.062s

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

Михаил обнови решението на 25.01.2016 03:02 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "net/http"
+ "strconv"
+ "sync"
+)
+
+type GameOfLifeHandler struct {
+ generation int
+ living map[[2]int64]struct{}
+ mutex *sync.Mutex
+}
+
+func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+ response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
+ switch request.Method {
+ case "GET":
+ switch request.URL.Path {
+ case "/cell/status/":
+ xStr := request.FormValue("x")
+ if len(xStr) == 0 {
+ response.WriteHeader(http.StatusBadRequest)
+ }
+ x, err := strconv.ParseInt(xStr, 10, 64)
+ if err != nil {
+ response.WriteHeader(http.StatusBadRequest)
+ }
+
+ yStr := request.FormValue("y")
+ if len(yStr) == 0 {
+ response.WriteHeader(http.StatusBadRequest)
+ }
+ y, err := strconv.ParseInt(yStr, 10, 64)
+ if err != nil {
+ response.WriteHeader(http.StatusBadRequest)
+ }
+
+ result, err := gl.CellStatus(x, y)
+ if err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
+ if _, err := response.Write(result); err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
+ return
+ case "/generation/":
+ result, err := gl.GetGeneration()
+ if err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
+
+ if _, err := response.Write(result); err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
+ return
+ }
+ case "POST":
+ switch request.URL.Path {
+ case "/cells/":
+ type input struct {
+ Cells [][2]int64
+ }
+
+ body := make([]byte, 0)
+ if _, err := request.Body.Read(body); err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
+
+ cells := input{}
+ json.Unmarshal(body, &cells)
+
+ gl.AddCells(cells.Cells)
+
+ response.WriteHeader(http.StatusCreated)
+ return
+ case "/generation/evolve/":
+ gl.NextGeneration() // nope, no Star Trek here
+ response.WriteHeader(http.StatusNoContent)
+ return
+ case "/reset/":
+ gl.mutex.Lock()
+ defer func() { gl.mutex.Unlock() }()
+
+ gl.living = make(map[[2]int64]struct{})
+ gl.generation = 0
+ response.WriteHeader(http.StatusNoContent)
+ return
+ }
+ }
+ response.WriteHeader(http.StatusNotFound)
+}
+
+func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
+ _, ok := gl.living[[2]int64{x, y}]
+
+ type result struct {
+ Alive bool
+ }
+
+ return json.Marshal(result{Alive: ok})
+}
+
+func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
+ type result struct {
+ Generation int
+ Living [][2]int64
+ }
+
+ res := result{Generation: gl.generation, Living: make([][2]int64, len(gl.living))}
+ for pos, _ := range gl.living {
+ res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
+ }
+
+ return json.Marshal(res)
+}
+
+func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
+ gl.mutex.Lock()
+ defer func() { gl.mutex.Unlock() }()
+
+ for _, cell := range cells {
+ gl.living[cell] = struct{}{}
+ }
+}
+
+func (gl *GameOfLifeHandler) NextGeneration() {
+ gl.mutex.Lock()
+ defer func() { gl.mutex.Unlock() }()
+
+ nextGen := make(map[[2]int64]struct{})
+ for cell, _ := range gl.living {
+ livingNeigbours := 0
+ for _, neighbour := range Neighbours(cell) {
+ if _, ok := gl.living[neighbour]; ok {
+ livingNeigbours++
+ }
+
+ livingNeigboursNested := 0
+ for _, neighbourNested := range Neighbours(neighbour) {
+ if _, ok := gl.living[neighbourNested]; ok {
+ livingNeigboursNested++
+ }
+ }
+
+ // for dead cells
+ if livingNeigboursNested == 3 {
+ nextGen[neighbour] = struct{}{}
+ }
+ }
+
+ // for living cells
+ if livingNeigbours == 2 || livingNeigbours == 3 {
+ nextGen[cell] = struct{}{}
+ }
+ }
+
+ gl.living = nextGen
+ gl.generation++
+}
+
+func Neighbours(pos [2]int64) [][2]int64 {
+ relatives := [][2]int64{
+ [2]int64{0, -1},
+ [2]int64{0, 1},
+ [2]int64{-1, 0},
+ [2]int64{1, 0},
+ [2]int64{-1, -1},
+ [2]int64{-1, 1},
+ [2]int64{1, -1},
+ [2]int64{1, 1},
+ }
+
+ neighbours := make([][2]int64, 8)
+ for i, relative := range relatives {
+ neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
+ }
+
+ return neighbours
+}
+
+func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
+ living := make(map[[2]int64]struct{})
+
+ for _, pos := range cells {
+ living[[2]int64{pos[0], pos[1]}] = struct{}{}
+ }
+
+ return &GameOfLifeHandler{generation: 0, living: living}
+}

Михаил обнови решението на 25.01.2016 03:59 (преди над 2 години)

package main
import (
"encoding/json"
+ "io/ioutil"
"net/http"
"strconv"
"sync"
)
type GameOfLifeHandler struct {
generation int
living map[[2]int64]struct{}
- mutex *sync.Mutex
+ mutex sync.Mutex
}
func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
switch request.Method {
case "GET":
switch request.URL.Path {
case "/cell/status/":
xStr := request.FormValue("x")
if len(xStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
x, err := strconv.ParseInt(xStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
yStr := request.FormValue("y")
if len(yStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
y, err := strconv.ParseInt(yStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
result, err := gl.CellStatus(x, y)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
case "/generation/":
result, err := gl.GetGeneration()
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
}
case "POST":
switch request.URL.Path {
case "/cells/":
- type input struct {
- Cells [][2]int64
+ type Cell struct {
+ X int64 `json:"x"`
+ Y int64 `json:"y"`
}
- body := make([]byte, 0)
- if _, err := request.Body.Read(body); err != nil {
+ var cells []Cell
+ body, err := ioutil.ReadAll(request.Body)
+ if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
+ if err := json.Unmarshal(body, &cells); err != nil {
+ response.WriteHeader(http.StatusInternalServerError)
+ }
- cells := input{}
- json.Unmarshal(body, &cells)
+ cellSlice := make([][2]int64, len(cells))
+ for i, _ := range cells {
+ cellSlice[i] = [2]int64{cells[i].X, cells[i].Y}
+ }
- gl.AddCells(cells.Cells)
+ gl.AddCells(cellSlice)
response.WriteHeader(http.StatusCreated)
return
case "/generation/evolve/":
gl.NextGeneration() // nope, no Star Trek here
response.WriteHeader(http.StatusNoContent)
return
case "/reset/":
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
gl.living = make(map[[2]int64]struct{})
gl.generation = 0
response.WriteHeader(http.StatusNoContent)
return
}
}
response.WriteHeader(http.StatusNotFound)
}
func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
_, ok := gl.living[[2]int64{x, y}]
type result struct {
- Alive bool
+ Alive bool `json:"alive"`
}
return json.Marshal(result{Alive: ok})
}
func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
type result struct {
- Generation int
- Living [][2]int64
+ Generation int `json:"generation"`
+ Living [][2]int64 `json:"living"`
}
- res := result{Generation: gl.generation, Living: make([][2]int64, len(gl.living))}
+ res := result{Generation: gl.generation, Living: make([][2]int64, 0)}
for pos, _ := range gl.living {
res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
}
return json.Marshal(res)
}
func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
for _, cell := range cells {
gl.living[cell] = struct{}{}
}
}
func (gl *GameOfLifeHandler) NextGeneration() {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
nextGen := make(map[[2]int64]struct{})
for cell, _ := range gl.living {
livingNeigbours := 0
for _, neighbour := range Neighbours(cell) {
if _, ok := gl.living[neighbour]; ok {
livingNeigbours++
}
livingNeigboursNested := 0
for _, neighbourNested := range Neighbours(neighbour) {
if _, ok := gl.living[neighbourNested]; ok {
livingNeigboursNested++
}
}
- // for dead cells
+ // for dead cells to be born
if livingNeigboursNested == 3 {
nextGen[neighbour] = struct{}{}
}
}
- // for living cells
+ // for living cells to remain living
if livingNeigbours == 2 || livingNeigbours == 3 {
nextGen[cell] = struct{}{}
}
}
gl.living = nextGen
gl.generation++
}
func Neighbours(pos [2]int64) [][2]int64 {
relatives := [][2]int64{
[2]int64{0, -1},
[2]int64{0, 1},
[2]int64{-1, 0},
[2]int64{1, 0},
[2]int64{-1, -1},
[2]int64{-1, 1},
[2]int64{1, -1},
[2]int64{1, 1},
}
neighbours := make([][2]int64, 8)
for i, relative := range relatives {
neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
}
return neighbours
}
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
living := make(map[[2]int64]struct{})
for _, pos := range cells {
living[[2]int64{pos[0], pos[1]}] = struct{}{}
}
return &GameOfLifeHandler{generation: 0, living: living}
+}
+
+func main() {
+ h := NewGameOfLifeHandler([][2]int64{
+ {0, 0},
+ {1, 1},
+ {3, 4},
+ {-2, 5},
+ {-19023482123, 5},
+ })
+ http.Handle("/", h)
+
+ http.ListenAndServe(":8080", nil)
}

Михаил обнови решението на 25.01.2016 03:59 (преди над 2 години)

package main
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"sync"
)
type GameOfLifeHandler struct {
generation int
living map[[2]int64]struct{}
mutex sync.Mutex
}
func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
switch request.Method {
case "GET":
switch request.URL.Path {
case "/cell/status/":
xStr := request.FormValue("x")
if len(xStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
x, err := strconv.ParseInt(xStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
yStr := request.FormValue("y")
if len(yStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
y, err := strconv.ParseInt(yStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
result, err := gl.CellStatus(x, y)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
case "/generation/":
result, err := gl.GetGeneration()
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
}
case "POST":
switch request.URL.Path {
case "/cells/":
type Cell struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
var cells []Cell
body, err := ioutil.ReadAll(request.Body)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if err := json.Unmarshal(body, &cells); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
cellSlice := make([][2]int64, len(cells))
for i, _ := range cells {
cellSlice[i] = [2]int64{cells[i].X, cells[i].Y}
}
gl.AddCells(cellSlice)
response.WriteHeader(http.StatusCreated)
return
case "/generation/evolve/":
gl.NextGeneration() // nope, no Star Trek here
response.WriteHeader(http.StatusNoContent)
return
case "/reset/":
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
gl.living = make(map[[2]int64]struct{})
gl.generation = 0
response.WriteHeader(http.StatusNoContent)
return
}
}
response.WriteHeader(http.StatusNotFound)
}
func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
_, ok := gl.living[[2]int64{x, y}]
type result struct {
Alive bool `json:"alive"`
}
return json.Marshal(result{Alive: ok})
}
func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
type result struct {
Generation int `json:"generation"`
Living [][2]int64 `json:"living"`
}
res := result{Generation: gl.generation, Living: make([][2]int64, 0)}
for pos, _ := range gl.living {
res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
}
return json.Marshal(res)
}
func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
for _, cell := range cells {
gl.living[cell] = struct{}{}
}
}
func (gl *GameOfLifeHandler) NextGeneration() {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
nextGen := make(map[[2]int64]struct{})
for cell, _ := range gl.living {
livingNeigbours := 0
for _, neighbour := range Neighbours(cell) {
if _, ok := gl.living[neighbour]; ok {
livingNeigbours++
}
livingNeigboursNested := 0
for _, neighbourNested := range Neighbours(neighbour) {
if _, ok := gl.living[neighbourNested]; ok {
livingNeigboursNested++
}
}
// for dead cells to be born
if livingNeigboursNested == 3 {
nextGen[neighbour] = struct{}{}
}
}
// for living cells to remain living
if livingNeigbours == 2 || livingNeigbours == 3 {
nextGen[cell] = struct{}{}
}
}
gl.living = nextGen
gl.generation++
}
func Neighbours(pos [2]int64) [][2]int64 {
relatives := [][2]int64{
[2]int64{0, -1},
[2]int64{0, 1},
[2]int64{-1, 0},
[2]int64{1, 0},
[2]int64{-1, -1},
[2]int64{-1, 1},
[2]int64{1, -1},
[2]int64{1, 1},
}
neighbours := make([][2]int64, 8)
for i, relative := range relatives {
neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
}
return neighbours
}
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
living := make(map[[2]int64]struct{})
for _, pos := range cells {
living[[2]int64{pos[0], pos[1]}] = struct{}{}
}
return &GameOfLifeHandler{generation: 0, living: living}
}
-
-func main() {
- h := NewGameOfLifeHandler([][2]int64{
- {0, 0},
- {1, 1},
- {3, 4},
- {-2, 5},
- {-19023482123, 5},
- })
- http.Handle("/", h)
-
- http.ListenAndServe(":8080", nil)
-}

Функционално, решението ти е много близо до перфектното! Ако прочетеш условието още веднъж и обърнеш внимание на третата точка от допълнителните пояснения ще го изгладиш до край.

Мисля, че основната причина да се объркаш е сложния switch-if блок във ServeHTTP. Виждал ли си http.ServerMux? С него, вероятно, ще ти е лесно да скриеш онази логика.

Михаил обнови решението на 25.01.2016 23:50 (преди над 2 години)

package main
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"sync"
)
type GameOfLifeHandler struct {
generation int
living map[[2]int64]struct{}
mutex sync.Mutex
}
func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
switch request.Method {
case "GET":
switch request.URL.Path {
case "/cell/status/":
xStr := request.FormValue("x")
if len(xStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
x, err := strconv.ParseInt(xStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
yStr := request.FormValue("y")
if len(yStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
y, err := strconv.ParseInt(yStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
result, err := gl.CellStatus(x, y)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
case "/generation/":
result, err := gl.GetGeneration()
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
}
case "POST":
switch request.URL.Path {
case "/cells/":
type Cell struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
var cells []Cell
body, err := ioutil.ReadAll(request.Body)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if err := json.Unmarshal(body, &cells); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
cellSlice := make([][2]int64, len(cells))
for i, _ := range cells {
cellSlice[i] = [2]int64{cells[i].X, cells[i].Y}
}
gl.AddCells(cellSlice)
response.WriteHeader(http.StatusCreated)
return
case "/generation/evolve/":
gl.NextGeneration() // nope, no Star Trek here
response.WriteHeader(http.StatusNoContent)
return
case "/reset/":
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
gl.living = make(map[[2]int64]struct{})
gl.generation = 0
response.WriteHeader(http.StatusNoContent)
return
}
}
+ switch request.URL.Path {
+ case "/cell/status/", "/generation/", "/cells/", "/generation/evolve/", "/reset/":
+ response.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
response.WriteHeader(http.StatusNotFound)
}
func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
_, ok := gl.living[[2]int64{x, y}]
type result struct {
Alive bool `json:"alive"`
}
return json.Marshal(result{Alive: ok})
}
func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
type result struct {
Generation int `json:"generation"`
Living [][2]int64 `json:"living"`
}
res := result{Generation: gl.generation, Living: make([][2]int64, 0)}
for pos, _ := range gl.living {
res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
}
return json.Marshal(res)
}
func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
for _, cell := range cells {
gl.living[cell] = struct{}{}
}
}
func (gl *GameOfLifeHandler) NextGeneration() {
gl.mutex.Lock()
defer func() { gl.mutex.Unlock() }()
nextGen := make(map[[2]int64]struct{})
for cell, _ := range gl.living {
livingNeigbours := 0
for _, neighbour := range Neighbours(cell) {
if _, ok := gl.living[neighbour]; ok {
livingNeigbours++
}
livingNeigboursNested := 0
for _, neighbourNested := range Neighbours(neighbour) {
if _, ok := gl.living[neighbourNested]; ok {
livingNeigboursNested++
}
}
// for dead cells to be born
if livingNeigboursNested == 3 {
nextGen[neighbour] = struct{}{}
}
}
// for living cells to remain living
if livingNeigbours == 2 || livingNeigbours == 3 {
nextGen[cell] = struct{}{}
}
}
gl.living = nextGen
gl.generation++
}
func Neighbours(pos [2]int64) [][2]int64 {
relatives := [][2]int64{
[2]int64{0, -1},
[2]int64{0, 1},
[2]int64{-1, 0},
[2]int64{1, 0},
[2]int64{-1, -1},
[2]int64{-1, 1},
[2]int64{1, -1},
[2]int64{1, 1},
}
neighbours := make([][2]int64, 8)
for i, relative := range relatives {
neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
}
return neighbours
}
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
living := make(map[[2]int64]struct{})
for _, pos := range cells {
living[[2]int64{pos[0], pos[1]}] = struct{}{}
}
return &GameOfLifeHandler{generation: 0, living: living}
}

Михаил обнови решението на 25.01.2016 23:52 (преди над 2 години)

package main
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"sync"
)
type GameOfLifeHandler struct {
generation int
living map[[2]int64]struct{}
mutex sync.Mutex
}
func (gl *GameOfLifeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
switch request.Method {
case "GET":
switch request.URL.Path {
case "/cell/status/":
xStr := request.FormValue("x")
if len(xStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
x, err := strconv.ParseInt(xStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
yStr := request.FormValue("y")
if len(yStr) == 0 {
response.WriteHeader(http.StatusBadRequest)
}
y, err := strconv.ParseInt(yStr, 10, 64)
if err != nil {
response.WriteHeader(http.StatusBadRequest)
}
result, err := gl.CellStatus(x, y)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
case "/generation/":
result, err := gl.GetGeneration()
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if _, err := response.Write(result); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
return
}
case "POST":
switch request.URL.Path {
case "/cells/":
type Cell struct {
X int64 `json:"x"`
Y int64 `json:"y"`
}
var cells []Cell
body, err := ioutil.ReadAll(request.Body)
if err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
if err := json.Unmarshal(body, &cells); err != nil {
response.WriteHeader(http.StatusInternalServerError)
}
cellSlice := make([][2]int64, len(cells))
for i, _ := range cells {
cellSlice[i] = [2]int64{cells[i].X, cells[i].Y}
}
gl.AddCells(cellSlice)
response.WriteHeader(http.StatusCreated)
return
case "/generation/evolve/":
gl.NextGeneration() // nope, no Star Trek here
response.WriteHeader(http.StatusNoContent)
return
case "/reset/":
gl.mutex.Lock()
- defer func() { gl.mutex.Unlock() }()
+ defer gl.mutex.Unlock()
gl.living = make(map[[2]int64]struct{})
gl.generation = 0
response.WriteHeader(http.StatusNoContent)
return
}
}
switch request.URL.Path {
case "/cell/status/", "/generation/", "/cells/", "/generation/evolve/", "/reset/":
response.WriteHeader(http.StatusMethodNotAllowed)
return
}
response.WriteHeader(http.StatusNotFound)
}
func (gl *GameOfLifeHandler) CellStatus(x, y int64) ([]byte, error) {
_, ok := gl.living[[2]int64{x, y}]
type result struct {
Alive bool `json:"alive"`
}
return json.Marshal(result{Alive: ok})
}
func (gl *GameOfLifeHandler) GetGeneration() ([]byte, error) {
type result struct {
Generation int `json:"generation"`
Living [][2]int64 `json:"living"`
}
res := result{Generation: gl.generation, Living: make([][2]int64, 0)}
for pos, _ := range gl.living {
res.Living = append(res.Living, [2]int64{pos[0], pos[1]})
}
return json.Marshal(res)
}
func (gl *GameOfLifeHandler) AddCells(cells [][2]int64) {
gl.mutex.Lock()
- defer func() { gl.mutex.Unlock() }()
+ defer gl.mutex.Unlock()
for _, cell := range cells {
gl.living[cell] = struct{}{}
}
}
func (gl *GameOfLifeHandler) NextGeneration() {
gl.mutex.Lock()
- defer func() { gl.mutex.Unlock() }()
+ defer gl.mutex.Unlock()
nextGen := make(map[[2]int64]struct{})
for cell, _ := range gl.living {
livingNeigbours := 0
for _, neighbour := range Neighbours(cell) {
if _, ok := gl.living[neighbour]; ok {
livingNeigbours++
}
livingNeigboursNested := 0
for _, neighbourNested := range Neighbours(neighbour) {
if _, ok := gl.living[neighbourNested]; ok {
livingNeigboursNested++
}
}
// for dead cells to be born
if livingNeigboursNested == 3 {
nextGen[neighbour] = struct{}{}
}
}
// for living cells to remain living
if livingNeigbours == 2 || livingNeigbours == 3 {
nextGen[cell] = struct{}{}
}
}
gl.living = nextGen
gl.generation++
}
func Neighbours(pos [2]int64) [][2]int64 {
relatives := [][2]int64{
[2]int64{0, -1},
[2]int64{0, 1},
[2]int64{-1, 0},
[2]int64{1, 0},
[2]int64{-1, -1},
[2]int64{-1, 1},
[2]int64{1, -1},
[2]int64{1, 1},
}
neighbours := make([][2]int64, 8)
for i, relative := range relatives {
neighbours[i] = [2]int64{pos[0] + relative[0], pos[1] + relative[1]}
}
return neighbours
}
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
living := make(map[[2]int64]struct{})
for _, pos := range cells {
living[[2]int64{pos[0], pos[1]}] = struct{}{}
}
return &GameOfLifeHandler{generation: 0, living: living}
}

Да, това с безсмислените функции в defer не знам как не съм го осъзнал...

Сега май трябва да е работещо от гледна точка на грешките. Пробвах и със ServeMux, ама го design-нах лошо и се забих в един парадокс, където за да създадеш променлива от типа ми, трябва вече да имаш референция към същата тая променлива дето ще създаваш... :D След твърде много време мъки осъзнах, че и дискретната математика ме чака и се върнах към първоначалното решение.