Ралица обнови решението на 23.01.2016 19:53 (преди над 2 години)
▸ Покажи разликите+package main
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+/* util functions */
+func checkError(err error) {
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func parseXYQuery(query string) (result [][2]int64) {
+ ampersandCount := strings.Count(query, "&")
+
+ result = make([][2]int64, ampersandCount+1)
+ queryParams := make([]string, ampersandCount+1)
+
+ queryParams = strings.Split(query, "&")
+
+ var (
+ param []string
+ index int = 0
+ number int64
+ err error
+ )
+ for _, val := range queryParams {
+ param = strings.Split(val, "=")
+
+ number, err = strconv.ParseInt(param[1], 10, 64)
+ checkError(err)
+
+ if param[0] == "x" {
+ result[index][0] = number
+ } else {
+ result[index][1] = number
+ index++
+ }
+ }
+
+ return
+}
+
+/* url handlers */
+type GameOfLifeHandler struct {
+ Generation int
+ Board map[[2]int64]bool
+ Neighbours map[[2]int64]int
+}
+
+func (g *GameOfLifeHandler) addNewCells(r *http.Request) (err error) {
+
+ var cellSlice []map[string]int64
+ cellSlice = make([]map[string]int64, 0, 2)
+
+ jsonBytes, _ := ioutil.ReadAll(r.Body)
+
+ err = json.Unmarshal(jsonBytes, &cellSlice)
+ checkError(err)
+
+ var newCellValue [2]int64
+ var neighbour [2]int64
+
+ for _, cell := range cellSlice {
+ newCellValue[0] = cell["x"]
+ newCellValue[1] = cell["y"]
+
+ g.Board[newCellValue] = true
+
+ for i := cell["x"] - 1; i < cell["x"]+1; i++ {
+ for j := cell["y"] - 1; j < cell["y"]+1; j++ {
+
+ if i == cell["x"] && j == cell["y"] {
+ continue
+ }
+
+ neighbour[0] = i
+ neighbour[1] = j
+
+ g.Neighbours[neighbour]++
+ }
+ }
+ }
+
+ return err
+}
+
+// writes json as a response
+func (g *GameOfLifeHandler) checkCell(w http.ResponseWriter, cell [2]int64) {
+ alive := make(map[string]bool)
+ alive["alive"] = g.Board[cell]
+
+ output, err := json.Marshal(alive)
+ checkError(err)
+
+ w.Write(output)
+}
+
+// writes json as a response
+func (g *GameOfLifeHandler) generation(w http.ResponseWriter) {
+ generation := make([][2]int64, 0, len(g.Board))
+
+ for cell := range g.Board {
+ generation = append(generation, cell)
+ }
+
+ currentGeneration := make(map[string]interface{})
+ currentGeneration["generation"] = strconv.Itoa(g.Generation)
+ currentGeneration["living"] = generation
+
+ output, err := json.Marshal(currentGeneration)
+ checkError(err)
+
+ w.WriteHeader(http.StatusCreated)
+ w.Write(output)
+}
+
+func (g *GameOfLifeHandler) evolve() {
+ newBoard := make(map[[2]int64]bool)
+ newNeighbourBoard := make(map[[2]int64]int)
+
+ var neighbour [2]int64
+
+ for cell, neighbours := range g.Neighbours {
+ if g.Board[cell] {
+ if neighbours == 2 || neighbours == 3 {
+ newBoard[cell] = true
+
+ for i := cell[0] - 1; i < cell[0]+1; i++ {
+ for j := cell[1] - 1; j < cell[1]+1; j++ {
+
+ if i == cell[0] && j == cell[1] {
+ continue
+ }
+
+ neighbour[0] = i
+ neighbour[1] = j
+
+ newNeighbourBoard[neighbour]++
+ }
+ }
+ }
+ }
+ }
+
+ g.Board = newBoard
+ g.Neighbours = newNeighbourBoard
+ g.Generation++
+}
+
+func (g *GameOfLifeHandler) reset() {
+ g.Generation = 0
+ g.Board = make(map[[2]int64]bool)
+}
+
+func (g *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ path := r.URL.Path
+
+ switch {
+ case regexp.MustCompile(`/generation/evolve/`).MatchString(path):
+ // POST
+ if r.Method != "POST" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.evolve()
+ w.WriteHeader(http.StatusOK)
+ }
+
+ case regexp.MustCompile(`/generation/`).MatchString(path):
+ // GET
+ if r.Method != "GET" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.generation(w)
+ }
+
+ case regexp.MustCompile(`/cell/status/.*`).MatchString(path):
+ // GET
+ if r.Method != "GET" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ cell := parseXYQuery(r.URL.RawQuery)[0]
+ g.checkCell(w, cell)
+ }
+
+ case regexp.MustCompile(`/cells/`).MatchString(path):
+ // POST
+ if r.Method != "POST" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ if err := g.addNewCells(r); err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ } else {
+ w.WriteHeader(http.StatusCreated)
+ }
+ }
+
+ case regexp.MustCompile(`/reset/`).MatchString(path):
+ // POST
+ if r.Method != "POST" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.reset()
+ w.WriteHeader(http.StatusOK)
+ }
+
+ default:
+ w.WriteHeader(http.StatusBadRequest)
+ _, err := w.Write(nil)
+ checkError(err)
+ }
+}
+
+func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
+ board := make(map[[2]int64]bool)
+ neighbours := make(map[[2]int64]int)
+
+ var neighbour [2]int64
+
+ for _, cell := range cells {
+ board[cell] = true
+
+ for i := cell[0] - 1; i < cell[0]+1; i++ {
+ for j := cell[1] - 1; j < cell[1]+1; j++ {
+
+ if i == cell[0] && j == cell[1] {
+ continue
+ }
+
+ neighbour[0] = i
+ neighbour[1] = j
+
+ neighbours[neighbour]++
+ }
+ }
+ }
+
+ gameOfLifeHandler := &GameOfLifeHandler{Generation: 0, Board: board, Neighbours: neighbours}
+
+ http.Handle("/", gameOfLifeHandler)
+
+ return gameOfLifeHandler
+}