Website Summary Files Commits Branches @commit @diff @stats
path: root / homework / 81013 / go2html / sample.go
diff options
context:
space:
mode:
Commit93cd8cac8a616ae13bd42dcbee0bb9da278eb49d (patch)
Author
 Ralitsa Velikova <rherince@gmail.com>
2018-11-07 14:26:16 +0200
Committer
 dtrendafilov <trendafilov.dn@gmail.com>
2018-11-07 14:26:16 +0200
Filesce8b306af9c36d6443fe2fc34526223e44c804cf /homework/81013/go2html/sample.go
IPL-93cd8cac8a616ae13bd42dcbee0bb9da278eb49d.tar
IPL-93cd8cac8a616ae13bd42dcbee0bb9da278eb49d.tar.gz
IPL-93cd8cac8a616ae13bd42dcbee0bb9da278eb49d.zip
Parent47e8c6f331525f01f150ba80a3557a18618b0cf5 (diff)
Solution to first homework (#25)
* Add token types enum for Lexer * Local test if I've correctly switched from https to ssh * Adds initial Lexer logic; Reuses JSImpl's Lexer logic; Still needs refactoring; * Adds README.md * Adds README.md * Adds tokenization of strings and a few operators * Adds some operators * Adds highlighter and sample for future testing * Adds runes & fixes double whitespace bug * API fix, premake, solution * Update README.md * Delete HL.sln * Delete HL.vcxproj
1 files changed, 308 insertions, 0 deletions
-rw-r--r--homework/81013/go2html/sample.go308
diff --git a/homework/81013/go2html/sample.go b/homework/81013/go2html/sample.go
new file mode 100644
index 0000000..9c76ea2
--- /dev/null
+++ b/homework/81013/go2html/sample.go
@@ -0,0 +1,308 @@
+package main
+
+import (
+ "encoding/json"
+ "errors"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "regexp"
+ "strconv"
+ "sync"
+ //"fmt"
+)
+
+type Cell struct {
+ X int64 `json:"x"`
+ Y int64 `json:"y"`
+}
+
+type GameOfLifeHandler struct {
+ Generation int
+ Board map[Cell]bool
+ Neighbours map[Cell]int
+ RespWriter http.ResponseWriter
+ BoardMutex sync.Mutex
+ NeighboursMutex sync.Mutex
+ RequestMutex sync.RWMutex
+}
+
+/* util functions */
+func (g *GameOfLifeHandler) sendError(err error) {
+ g.RespWriter.Header().Set("Error", err.Error())
+ g.RespWriter.WriteHeader(http.StatusBadRequest)
+}
+
+func (g *GameOfLifeHandler) parseXYQuery(r *http.Request) (result Cell, err error) {
+ values, err := url.ParseQuery(r.URL.RawQuery)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ // validate
+ if len(values) != 2 {
+ err = errors.New("Invalid parameters query - invalid number of query parameters")
+ g.sendError(err)
+ return
+ }
+
+ xString := values.Get("x")
+ yString := values.Get("y")
+
+ if xString == "" || yString == "" {
+ err = errors.New("Invalid parameters query - x or y not set")
+ g.sendError(err)
+ return
+ }
+
+ x, err := strconv.ParseInt(xString, 10, 64)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+ y, err := strconv.ParseInt(yString, 10, 64)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ result.X = x
+ result.Y = y
+
+ return
+}
+
+func updateNeighbours(cell Cell, neighbours *map[Cell]int) {
+ var neighbour Cell
+
+ 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.X = i
+ neighbour.Y = j
+
+ (*neighbours)[neighbour]++
+ }
+ }
+}
+
+/* url handlers */
+func (g *GameOfLifeHandler) addNewCells(r *http.Request) (err error) {
+ var cellSlice []Cell
+ cellSlice = make([]Cell, 0, 2)
+
+ jsonBytes, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ err = json.Unmarshal(jsonBytes, &cellSlice)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ for _, cell := range cellSlice {
+ g.BoardMutex.Lock()
+ g.Board[cell] = true
+ g.BoardMutex.Unlock()
+
+ g.NeighboursMutex.Lock()
+ updateNeighbours(cell, &g.Neighbours)
+ g.NeighboursMutex.Unlock()
+ }
+
+ return err
+}
+
+// writes json as a response
+func (g *GameOfLifeHandler) checkCell(w http.ResponseWriter, cell Cell) (err error) {
+ alive := make(map[string]bool)
+ alive["alive"] = g.Board[cell]
+
+ output, err := json.Marshal(alive)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Write(output)
+ return
+}
+
+// writes json as a response
+func (g *GameOfLifeHandler) generation(w http.ResponseWriter) {
+ generation := make([]Cell, 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)
+ if err != nil {
+ g.sendError(err)
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Write(output)
+}
+
+func (g *GameOfLifeHandler) evolve(w http.ResponseWriter) {
+ newBoard := make(map[Cell]bool)
+ newNeighbourBoard := make(map[Cell]int)
+
+ for cell, neighbours := range g.Neighbours {
+ if g.Board[cell] {
+ if neighbours == 2 || neighbours == 3 {
+ newBoard[cell] = true
+
+ updateNeighbours(cell, &newNeighbourBoard)
+ }
+ } else {
+ if neighbours == 3 {
+ newBoard[cell] = true
+
+ updateNeighbours(cell, &newNeighbourBoard)
+ }
+ }
+ }
+
+ g.BoardMutex.Lock()
+ g.Board = newBoard
+ g.BoardMutex.Unlock()
+
+ g.NeighboursMutex.Lock()
+ g.Neighbours = newNeighbourBoard
+ g.NeighboursMutex.Unlock()
+
+ g.Generation++
+
+ w.WriteHeader(http.StatusNoContent)
+}
+
+func (g *GameOfLifeHandler) reset(w http.ResponseWriter) {
+ g.Generation = 0
+
+ g.BoardMutex.Lock()
+ g.Board = make(map[Cell]bool)
+ g.BoardMutex.Unlock()
+
+ w.WriteHeader(http.StatusNoContent)
+}
+
+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.RequestMutex.Lock()
+
+ g.evolve(w)
+
+ g.RequestMutex.Unlock()
+ }
+
+ case regexp.MustCompile(`/generation/`).MatchString(path):
+ // GET
+ if r.Method != "GET" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.RequestMutex.RLock()
+
+ g.generation(w)
+
+ g.RequestMutex.RUnlock()
+ }
+
+ case regexp.MustCompile(`/cell/status/`).MatchString(path):
+ // GET
+ if r.Method != "GET" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.RequestMutex.RLock()
+
+ cell, err := g.parseXYQuery(r)
+ if err == nil {
+ g.checkCell(w, cell)
+ }
+
+ g.RequestMutex.RUnlock()
+ }
+
+ case regexp.MustCompile(`/cells/`).MatchString(path):
+ // POST
+ if r.Method != "POST" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.RequestMutex.Lock()
+
+ if err := g.addNewCells(r); err == nil {
+ w.WriteHeader(http.StatusCreated)
+ }
+
+ g.RequestMutex.Unlock()
+ }
+
+ case regexp.MustCompile(`/reset/`).MatchString(path):
+ // POST
+ if r.Method != "POST" {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ } else {
+ g.RequestMutex.Lock()
+
+ g.reset(w)
+
+ g.RequestMutex.Unlock()
+ }
+
+ default:
+ w.WriteHeader(http.StatusNotFound)
+ }
+}
+
+func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
+ board := make(map[Cell]bool)
+ neighbours := make(map[Cell]int)
+
+ var newCell Cell
+
+ for _, cell := range cells {
+ newCell.X = cell[0]
+ newCell.Y = cell[1]
+
+ board[newCell] = true
+
+ updateNeighbours(newCell, &neighbours)
+ }
+
+ gameOfLifeHandler := &GameOfLifeHandler{Generation: 0, Board: board, Neighbours: neighbours}
+
+ return gameOfLifeHandler
+}
+
+func main() {
+ gofh := NewGameOfLifeHandler([][2]int64{
+ {2, 3},
+ {2, 4},
+ {-20, 4},
+ {-42, 0},
+ })
+
+ http.ListenAndServe(":8080", gofh)
+}