Решение на Game of Life от Добромир Иванов

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

Към профила на Добромир Иванов

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 11 успешни тест(а)
  • 3 неуспешни тест(а)

Код

package main
import (
"bytes"
"encoding/json"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
)
type cell struct {
x, y int64
}
type board struct {
cells map[cell]bool
}
func (board *board) cellAlive(position cell) bool {
_, ok := board.cells[position]
return ok
}
func (board *board) neighborsAlive(position cell) int64 {
var neighborsAlive int64 = 0
var i, j int64
for i = -1; i <= 1; i++ {
for j = -1; j <= 1; j++ {
currentCell := cell{position.x + i, position.y + j}
if (j != 0 || i != 0) && board.cellAlive(currentCell) {
neighborsAlive++
}
}
}
return neighborsAlive
}
func neighbors(position cell) []cell {
neighbors := make([]cell, 100)
var i, j int64
for i = -1; i <= 1; i++ {
for j = -1; j <= 1; j++ {
if (j != 0 || i != 0) && (position.x+i >= 0 && position.y+j >= 0) {
neighbor := cell{position.x + i, position.y + j}
neighbors = append(neighbors, neighbor)
}
}
}
return neighbors
}
func (board *board) nextGeneration() {
cells := make(map[cell]bool, 10)
for currentCell, _ := range board.cells {
for _, neighbor := range neighbors(currentCell) {
alive := board.neighborsAlive(neighbor)
if alive == 3 || alive == 2 && board.cellAlive(neighbor) {
cells[neighbor] = true
}
}
}
board.cells = cells
}
type GameOfLifeHandler struct {
lock sync.RWMutex
generation int64
gameBoard *board
}
func NewGameOfLifeHandler(boardState [][2]int64) *GameOfLifeHandler {
gameBoard := make(map[cell]bool, 100)
for _, position := range boardState {
cell := cell{position[0], position[1]}
gameBoard[cell] = true
}
game := new(GameOfLifeHandler)
game.generation = 0
game.gameBoard = new(board)
game.gameBoard.cells = gameBoard
return game
}
type response struct {
code int
body string
}
type cellStatusResponse struct {
Alive bool `json:"alive"`
}
type aliveCellsResponse struct {
Generation int64 `json:"generation"`
Cells [][2]int64 `json:"living"`
}
type gameCell struct {
X int64
Y int64
}
func (game *GameOfLifeHandler) cellStatusHandler(url *url.URL) response {
game.lock.RLock()
defer game.lock.RUnlock()
q := url.Query()
x, err := strconv.ParseInt(q.Get("x"), 10, 64)
if err != nil {
return response{400, err.Error()}
}
y, err := strconv.ParseInt(q.Get("y"), 10, 64)
if err != nil {
return response{400, err.Error()}
}
cell := cell{x, y}
alive := cellStatusResponse{game.gameBoard.cellAlive(cell)}
body, err := json.Marshal(alive)
if err != nil {
return response{500, err.Error()}
}
return response{200, string(body)}
}
func (gameHandler *GameOfLifeHandler) cellsAliveHandler(url *url.URL) response {
gameHandler.lock.RLock()
defer gameHandler.lock.RUnlock()
cells := make([][2]int64, 0, 10)
for cell, _ := range gameHandler.gameBoard.cells {
el := [2]int64{cell.x, cell.y}
cells = append(cells, el)
}
aliveCells := aliveCellsResponse{gameHandler.generation, cells}
responseBody, err := json.Marshal(aliveCells)
if err != nil {
return response{500, err.Error()}
}
return response{200, string(responseBody)}
}
func (game *GameOfLifeHandler) addCellsHandler(request *http.Request) response {
game.lock.Lock()
defer game.lock.Unlock()
if request.ContentLength == 0 {
return response{400, "Request body empty!"}
}
byteArr := make([]byte, 0, request.ContentLength)
jsonBuffer := bytes.NewBuffer(byteArr)
_, err := jsonBuffer.ReadFrom(request.Body)
if err != nil {
return response{500, err.Error()}
}
var cellsToAdd []gameCell
err = json.Unmarshal(jsonBuffer.Bytes(), &cellsToAdd)
if err != nil {
return response{400, err.Error()}
}
for _, newCell := range cellsToAdd {
cell := cell{newCell.X, newCell.Y}
game.gameBoard.cells[cell] = true
}
return response{201, string(jsonBuffer.Bytes())}
}
func (game *GameOfLifeHandler) evolveHandler() response {
game.lock.Lock()
defer game.lock.Unlock()
game.generation++
game.gameBoard.nextGeneration()
return response{204, ""}
}
func (game *GameOfLifeHandler) resetHandler() response {
game.lock.Lock()
defer game.lock.Unlock()
gameBoard := make(map[cell]bool, 100)
game.generation = 0
game.gameBoard = new(board)
game.gameBoard.cells = gameBoard
return response{204, ""}
}
func (gameHandler *GameOfLifeHandler) requestDispatcher(
request *http.Request) response {
if strings.EqualFold("GET", request.Method) {
if request.URL.Path == "/cell/status/" {
return gameHandler.cellStatusHandler(request.URL)
} else if request.URL.Path == "/generation/" {
return gameHandler.cellsAliveHandler(request.URL)
}
return response{404, "Not found!"}
} else if strings.EqualFold("POST", request.Method) {
if request.URL.Path == "/cells/" {
return gameHandler.addCellsHandler(request)
} else if request.URL.Path == "/generation/evolve/" {
return gameHandler.evolveHandler()
} else if request.URL.Path == "/reset/" {
}
return response{404, "Not found!"}
}
return response{405, "Unknown method!"}
}
func (gameHandler *GameOfLifeHandler) ServeHTTP(
response http.ResponseWriter, request *http.Request) {
resp := gameHandler.requestDispatcher(request)
response.WriteHeader(resp.code)
response.Write([]byte(resp.body))
}

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

PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.004s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.005s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.006s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.007s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.009s
--- FAIL: TestBoardReset (0.00s)
	solution_test.go:180: Expected clearing the board to respond with 204 but it was 404
	solution_test.go:194: Resetting did not remove all living cells
FAIL
exit status 1
FAIL	_/tmp/d20160126-5892-ascxi5	0.008s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.006s
--- FAIL: TestWrongHTTPMethods (0.01s)
	solution_test.go:300: Expected method not allowed (405) for GET /generation/evolve/ but it was 404
	solution_test.go:300: Expected method not allowed (405) for POST /generation/ but it was 404
	solution_test.go:300: Expected method not allowed (405) for GET /cells/ but it was 404
	solution_test.go:300: Expected method not allowed (405) for GET /reset/ but it was 404
	solution_test.go:300: Expected method not allowed (405) for POST /cell/status/ but it was 404
FAIL
exit status 1
FAIL	_/tmp/d20160126-5892-ascxi5	0.012s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.006s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.008s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.010s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.015s
--- FAIL: TestBoardEvolutionOscillators (0.01s)
	solution_test.go:716: Expected cell [0 -1] to be alive in test "Blinker"
	solution_test.go:716: Expected cell [-1 0] to be alive in test "Blinker"
	solution_test.go:716: Expected cell [0 0] to be alive in test "Blinker"
	solution_test.go:716: Expected cell [1 0] to be alive in test "Blinker"
FAIL
exit status 1
FAIL	_/tmp/d20160126-5892-ascxi5	0.013s
PASS
ok  	_/tmp/d20160126-5892-ascxi5	0.112s

История (1 версия и 0 коментара)

Добромир обнови решението на 26.01.2016 11:46 (преди над 2 години)

+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+type cell struct {
+ x, y int64
+}
+
+type board struct {
+ cells map[cell]bool
+}
+
+func (board *board) cellAlive(position cell) bool {
+ _, ok := board.cells[position]
+ return ok
+}
+
+func (board *board) neighborsAlive(position cell) int64 {
+ var neighborsAlive int64 = 0
+ var i, j int64
+
+ for i = -1; i <= 1; i++ {
+ for j = -1; j <= 1; j++ {
+ currentCell := cell{position.x + i, position.y + j}
+
+ if (j != 0 || i != 0) && board.cellAlive(currentCell) {
+ neighborsAlive++
+ }
+ }
+ }
+
+ return neighborsAlive
+}
+
+func neighbors(position cell) []cell {
+ neighbors := make([]cell, 100)
+ var i, j int64
+
+ for i = -1; i <= 1; i++ {
+ for j = -1; j <= 1; j++ {
+ if (j != 0 || i != 0) && (position.x+i >= 0 && position.y+j >= 0) {
+ neighbor := cell{position.x + i, position.y + j}
+ neighbors = append(neighbors, neighbor)
+ }
+ }
+ }
+ return neighbors
+}
+
+func (board *board) nextGeneration() {
+ cells := make(map[cell]bool, 10)
+
+ for currentCell, _ := range board.cells {
+ for _, neighbor := range neighbors(currentCell) {
+ alive := board.neighborsAlive(neighbor)
+
+ if alive == 3 || alive == 2 && board.cellAlive(neighbor) {
+ cells[neighbor] = true
+ }
+
+ }
+ }
+
+ board.cells = cells
+}
+
+type GameOfLifeHandler struct {
+ lock sync.RWMutex
+ generation int64
+ gameBoard *board
+}
+
+func NewGameOfLifeHandler(boardState [][2]int64) *GameOfLifeHandler {
+ gameBoard := make(map[cell]bool, 100)
+
+ for _, position := range boardState {
+
+ cell := cell{position[0], position[1]}
+ gameBoard[cell] = true
+ }
+
+ game := new(GameOfLifeHandler)
+
+ game.generation = 0
+ game.gameBoard = new(board)
+ game.gameBoard.cells = gameBoard
+
+ return game
+}
+
+type response struct {
+ code int
+ body string
+}
+
+type cellStatusResponse struct {
+ Alive bool `json:"alive"`
+}
+
+type aliveCellsResponse struct {
+ Generation int64 `json:"generation"`
+ Cells [][2]int64 `json:"living"`
+}
+
+type gameCell struct {
+ X int64
+ Y int64
+}
+
+func (game *GameOfLifeHandler) cellStatusHandler(url *url.URL) response {
+ game.lock.RLock()
+ defer game.lock.RUnlock()
+
+ q := url.Query()
+
+ x, err := strconv.ParseInt(q.Get("x"), 10, 64)
+ if err != nil {
+ return response{400, err.Error()}
+ }
+
+ y, err := strconv.ParseInt(q.Get("y"), 10, 64)
+ if err != nil {
+ return response{400, err.Error()}
+ }
+
+ cell := cell{x, y}
+ alive := cellStatusResponse{game.gameBoard.cellAlive(cell)}
+ body, err := json.Marshal(alive)
+
+ if err != nil {
+ return response{500, err.Error()}
+ }
+
+ return response{200, string(body)}
+}
+
+func (gameHandler *GameOfLifeHandler) cellsAliveHandler(url *url.URL) response {
+ gameHandler.lock.RLock()
+ defer gameHandler.lock.RUnlock()
+
+ cells := make([][2]int64, 0, 10)
+
+ for cell, _ := range gameHandler.gameBoard.cells {
+ el := [2]int64{cell.x, cell.y}
+ cells = append(cells, el)
+ }
+
+ aliveCells := aliveCellsResponse{gameHandler.generation, cells}
+
+ responseBody, err := json.Marshal(aliveCells)
+
+ if err != nil {
+ return response{500, err.Error()}
+ }
+
+ return response{200, string(responseBody)}
+}
+
+func (game *GameOfLifeHandler) addCellsHandler(request *http.Request) response {
+ game.lock.Lock()
+ defer game.lock.Unlock()
+
+ if request.ContentLength == 0 {
+ return response{400, "Request body empty!"}
+ }
+
+ byteArr := make([]byte, 0, request.ContentLength)
+ jsonBuffer := bytes.NewBuffer(byteArr)
+ _, err := jsonBuffer.ReadFrom(request.Body)
+
+ if err != nil {
+ return response{500, err.Error()}
+ }
+
+ var cellsToAdd []gameCell
+ err = json.Unmarshal(jsonBuffer.Bytes(), &cellsToAdd)
+
+ if err != nil {
+ return response{400, err.Error()}
+ }
+
+ for _, newCell := range cellsToAdd {
+ cell := cell{newCell.X, newCell.Y}
+ game.gameBoard.cells[cell] = true
+ }
+
+ return response{201, string(jsonBuffer.Bytes())}
+}
+
+func (game *GameOfLifeHandler) evolveHandler() response {
+ game.lock.Lock()
+ defer game.lock.Unlock()
+
+ game.generation++
+ game.gameBoard.nextGeneration()
+
+ return response{204, ""}
+}
+
+func (game *GameOfLifeHandler) resetHandler() response {
+ game.lock.Lock()
+ defer game.lock.Unlock()
+
+ gameBoard := make(map[cell]bool, 100)
+
+ game.generation = 0
+ game.gameBoard = new(board)
+ game.gameBoard.cells = gameBoard
+
+ return response{204, ""}
+}
+
+func (gameHandler *GameOfLifeHandler) requestDispatcher(
+ request *http.Request) response {
+
+ if strings.EqualFold("GET", request.Method) {
+
+ if request.URL.Path == "/cell/status/" {
+
+ return gameHandler.cellStatusHandler(request.URL)
+
+ } else if request.URL.Path == "/generation/" {
+ return gameHandler.cellsAliveHandler(request.URL)
+ }
+
+ return response{404, "Not found!"}
+
+ } else if strings.EqualFold("POST", request.Method) {
+
+ if request.URL.Path == "/cells/" {
+
+ return gameHandler.addCellsHandler(request)
+
+ } else if request.URL.Path == "/generation/evolve/" {
+
+ return gameHandler.evolveHandler()
+
+ } else if request.URL.Path == "/reset/" {
+
+ }
+
+ return response{404, "Not found!"}
+ }
+
+ return response{405, "Unknown method!"}
+}
+
+func (gameHandler *GameOfLifeHandler) ServeHTTP(
+ response http.ResponseWriter, request *http.Request) {
+
+ resp := gameHandler.requestDispatcher(request)
+
+ response.WriteHeader(resp.code)
+ response.Write([]byte(resp.body))
+}