diff --git a/css/boxes.css b/css/boxes.css index 9ab8f1b..15a3822 100644 --- a/css/boxes.css +++ b/css/boxes.css @@ -1,9 +1,10 @@ .boxes-container { max-width: 800px; margin: 100px auto; + position: relative; } .boxes-container input{ - height: 20px; - width: 20px; - margin: 2; + height: 3.125%; + width: 3.125%; + margin: 0; } \ No newline at end of file diff --git a/js/boxes.js b/js/boxes.js index a860331..f0f5ef8 100644 --- a/js/boxes.js +++ b/js/boxes.js @@ -1,68 +1,64 @@ -const socketUrl = - (window.location.protocol.startsWith("https") ? "wss://" : "ws://") + - window.location.host + - "/ws"; - -let socket = new WebSocket(socketUrl); - -socket.addEventListener("message", function (event) { - if (event.data.startsWith("u:")) { - const items = event.data.split(";"); - items.forEach((i) => { - const parts = event.data.split(":"); - document.getElementById("box-" + parts[1]).checked = parts[2] === "+"; - console.log("box-" + parts[1]); +"use strict"; +(() => { + const socket = getSocket("/boxes/ws"); + const deserializeBox = (msg) => { + msg = msg.replaceAll("b:", ""); + const parts = msg.split(":"); + return { + id: Number(parts[0]), + value: parts[1] === "+", + }; + }; + const handleInstruction = (instruction) => { + if (instruction.startsWith("b:")) { + const items = instruction.split(";"); + items.forEach((i) => { + const box = deserializeBox(i); + const el = document.getElementById("box-" + box.id); + el.checked = box.value; + // console.log(i,box,el) + }); + return; + } + }; + socket.addEventListener("message", (event) => { + const instructions = event.data.split("\n"); + instructions.forEach(handleInstruction); }); - return; - } - - if (event.data.startsWith("i:")) { - const str = event.data.split("i:")[1]; - const items = str.split(";"); - if (items.length === 0) { - return; - } - document.querySelectorAll("input").forEach((input) => { - input.checked = false; + document.querySelectorAll(".boxes input").forEach((input) => { + input.addEventListener("change", (event) => { + const target = event.target; + const id = target?.id.split("-")[1]; + const value = target.checked ? "+" : "-"; + socket.send("b:" + id + ":" + value); + }); }); - items.forEach((i) => { - if (!i) { - return; - } - console.log(i, document.getElementById("box-" + i)); - document.getElementById("box-" + i).checked = true; - }); - return; - } -}); - -setInterval(() => { - socket.send("ping"); -}, 10000); - -document.querySelectorAll(".boxes input").forEach((input) => { - input.addEventListener("change", (event) => { - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - const id = event.target.id.split("-")[1]; - const value = event.target.checked ? "+" : "-"; - socket.send("u:" + id + ":" + value); - }); -}); - -var timer = null -document.querySelector("#auto-boxes").addEventListener("change",(e)=>{ - if (e.target.checked){ - timer = setInterval(()=>{ - var id = Math.round(Math.random() * 1000) - const value = document.querySelector('#box-'+id).checked ? "-" : "+"; - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - socket.send("u:" + id + ":" + value); - },500) - }else{ - clearInterval(timer) - } -}) + var autoPlayTimer = undefined; + const handleAutoPlay = (el) => { + if (el.checked) { + autoPlayTimer = setInterval(() => { + socket.send("random"); + }, 50); + } + else { + clearInterval(autoPlayTimer); + } + }; + const autoPlayEl = document.querySelector("#auto-boxes"); + handleAutoPlay(autoPlayEl); + autoPlayEl?.addEventListener("change", (e) => handleAutoPlay(e.target)); + var golTimer = undefined; + const handleGol = (el) => { + if (el.checked) { + golTimer = setInterval(() => { + socket.send("gol"); + }, 500); + } + else { + clearInterval(golTimer); + } + }; + const golEl = document.querySelector("#game-of-life"); + handleGol(golEl); + golEl.addEventListener("change", (e) => handleGol(e.target)); +})(); diff --git a/js/boxes.ts b/js/boxes.ts new file mode 100644 index 0000000..e720428 --- /dev/null +++ b/js/boxes.ts @@ -0,0 +1,80 @@ +type CheckboxEl = HTMLInputElement & { checked: boolean; id: string }; +type Box = { + id: number; + value: boolean; +}; + +(() => { + const socket = getSocket("/boxes/ws"); + + const deserializeBox = (msg: string): Box => { + msg = msg.replaceAll("b:", ""); + const parts = msg.split(":"); + + return { + id: Number(parts[0]), + value: parts[1] === "+", + }; + }; + + const handleInstruction = (instruction: string) => { + if (instruction.startsWith("b:")) { + const items = instruction.split(";"); + items.forEach((i) => { + const box = deserializeBox(i); + + const el = document.getElementById("box-" + box.id) as CheckboxEl; + el.checked = box.value; + // console.log(i,box,el) + }); + return; + } + }; + + socket.addEventListener("message", (event: MessageEvent) => { + const instructions = event.data.split("\n"); + instructions.forEach(handleInstruction); + }); + + document.querySelectorAll(".boxes input").forEach((input) => { + input.addEventListener("change", (event) => { + const target = event.target as CheckboxEl; + + const id = target?.id.split("-")[1]; + const value = target.checked ? "+" : "-"; + socket.send("b:" + id + ":" + value); + }); + }); + + var autoPlayTimer: number | undefined = undefined; + const handleAutoPlay = (el: CheckboxEl) => { + if (el.checked) { + autoPlayTimer = setInterval(() => { + socket.send("random"); + }, 50); + } else { + clearInterval(autoPlayTimer); + } + }; + + const autoPlayEl = document.querySelector("#auto-boxes") as CheckboxEl; + handleAutoPlay(autoPlayEl); + autoPlayEl?.addEventListener("change", (e) => + handleAutoPlay(e.target as CheckboxEl) + ); + + var golTimer: number | undefined = undefined; + const handleGol = (el: CheckboxEl) => { + if (el.checked) { + golTimer = setInterval(() => { + socket.send("gol"); + }, 500); + } else { + clearInterval(golTimer); + } + }; + + const golEl = document.querySelector("#game-of-life") as CheckboxEl; + handleGol(golEl); + golEl.addEventListener("change", (e) => handleGol(e.target as CheckboxEl)); +})(); diff --git a/js/draw.js b/js/draw.js index 876e7f3..3b064db 100644 --- a/js/draw.js +++ b/js/draw.js @@ -4,33 +4,20 @@ if (!drawElement) { throw new Error("canvas not found"); } - const drawEmitter = mitt(); + const emitter = mitt(); let drawing = false; - const socketUrl = "/draw/ws"; - let socket = new WebSocket(socketUrl); - socket.onerror = console.error; - socket.onclose = console.warn; + let previous = null; + const socket = getSocket("/draw/ws"); const serializeDraw = ({ from, to }) => `${from.x},${from.y},${to.x},${to.y}`; const deserializeDraw = (message) => { const parts = message.split(","); return { - from: { - x: Number(parts[0]), - y: Number(parts[1]), - }, - to: { - x: Number(parts[2]), - y: Number(parts[3]), - }, + from: { x: Number(parts[0]), y: Number(parts[1]) }, + to: { x: Number(parts[2]), y: Number(parts[3]) }, }; }; - drawEmitter.on("draw", (e) => sendMessage(e)); - const sendMessage = (e) => { - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - socket.send(serializeDraw(e)); - }; + emitter.on("mouseDraw", (e) => sendMessage(e)); + const sendMessage = (e) => socket.send(serializeDraw(e)); const mouseDown = () => { drawing = true; previous = null; @@ -38,12 +25,11 @@ const mouseUp = () => { drawing = false; }; - let previous = null; const mouseMove = (e) => { if (!drawing) return; if (previous) { - drawEmitter.emit("draw", { + emitter.emit("mouseDraw", { from: previous, to: { x: e.offsetX, y: e.offsetY }, }); @@ -68,30 +54,26 @@ if (!recCtx || !receiveCanvas) { throw new Error("canvas not found"); } - //@ts-expect-error - window.ctx = recCtx; - setTimeout(() => { - recCtx.lineWidth = 2; - recCtx.lineCap = "round"; - recCtx.strokeStyle = "white"; - }, 10); - socket.addEventListener("message", (event) => { - if (event.data === "ping" || event.data.startsWith('pong')) - return; - const { from, to } = deserializeDraw(event.data); + const render = (data) => { + const { from, to } = data; + if (recCtx.strokeStyle != "white") { + recCtx.lineWidth = 2; + recCtx.lineCap = "round"; + recCtx.strokeStyle = "white"; + } recCtx.beginPath(); recCtx.moveTo(from.x, from.y); recCtx.lineTo(to.x, to.y); recCtx.closePath(); recCtx.stroke(); - console.log(from, to); + }; + emitter.on("mouseDraw", render); + emitter.on("netDraw", render); + socket.addEventListener("message", (event) => { + if (event.data === "ping" || event.data.startsWith("pong")) + return; + emitter.emit("netDraw", deserializeDraw(event.data)); }); - setInterval(() => { - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - socket.send("ping"); - }, 10000); const resizeObserver = new ResizeObserver((entries) => { const entry = entries.at(0); receiveCanvas.height = entry?.contentRect.height ?? 500; diff --git a/js/draw.ts b/js/draw.ts index 9ddb810..22639b1 100644 --- a/js/draw.ts +++ b/js/draw.ts @@ -15,58 +15,44 @@ to: DrawPoint; }; type Events = { - draw: DrawEvent; + mouseDraw: DrawEvent; + netDraw: DrawEvent; }; - const drawEmitter = mitt(); + const emitter = mitt(); let drawing = false; - const socketUrl = "/draw/ws"; + let previous: DrawPoint | null = null; - let socket = new WebSocket(socketUrl); + const socket = getSocket("/draw/ws"); - socket.onerror = console.error; - socket.onclose = console.warn; - - const serializeDraw = ({from, to }: DrawEvent) => + const serializeDraw = ({ from, to }: DrawEvent) => `${from.x},${from.y},${to.x},${to.y}`; const deserializeDraw = (message: string): DrawEvent => { const parts = message.split(","); return { - from: { - x: Number(parts[0]), - y: Number(parts[1]), - }, - to: { - x: Number(parts[2]), - y: Number(parts[3]), - }, + from: { x: Number(parts[0]), y: Number(parts[1]) }, + to: { x: Number(parts[2]), y: Number(parts[3]) }, }; }; - drawEmitter.on("draw", (e) => sendMessage(e)); - const sendMessage = (e: DrawEvent) => { - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - socket.send(serializeDraw(e)); - }; + emitter.on("mouseDraw", (e) => sendMessage(e)); + const sendMessage = (e: DrawEvent) => socket.send(serializeDraw(e)); const mouseDown = () => { drawing = true; - previous=null + previous = null; }; const mouseUp = () => { drawing = false; }; - let previous: DrawPoint | null = null; const mouseMove = (e: Pick) => { if (!drawing) return; if (previous) { - drawEmitter.emit("draw", { + emitter.emit("mouseDraw", { from: previous, to: { x: e.offsetX, y: e.offsetY }, }); @@ -98,36 +84,30 @@ if (!recCtx || !receiveCanvas) { throw new Error("canvas not found"); } - //@ts-expect-error - window.ctx = recCtx; - setTimeout(()=>{ - recCtx.lineWidth = 2; - recCtx.lineCap = "round"; - recCtx.strokeStyle = "white"; - },10) + const render = (data: DrawEvent) => { + const { from, to } = data; - - - - socket.addEventListener("message", (event) => { - if(event.data==="ping" || event.data.startsWith('pong')) return - const { from, to } = deserializeDraw(event.data); + if (recCtx.strokeStyle != "white") { + recCtx.lineWidth = 2; + recCtx.lineCap = "round"; + recCtx.strokeStyle = "white"; + } recCtx.beginPath(); recCtx.moveTo(from.x, from.y); recCtx.lineTo(to.x, to.y); recCtx.closePath(); recCtx.stroke(); - console.log(from, to); - }); + }; - setInterval(() => { - if (socket.readyState !== socket.OPEN) { - socket = new WebSocket(socketUrl); - } - socket.send("ping"); - }, 10000); + emitter.on("mouseDraw", render); + emitter.on("netDraw", render); + + socket.addEventListener("message", (event) => { + if (event.data === "ping" || event.data.startsWith("pong")) return; + emitter.emit("netDraw", deserializeDraw(event.data)); + }); const resizeObserver = new ResizeObserver((entries) => { const entry = entries.at(0); diff --git a/js/ws.js b/js/ws.js new file mode 100644 index 0000000..8fde816 --- /dev/null +++ b/js/ws.js @@ -0,0 +1,7 @@ +"use strict"; +const getSocket = (url) => { + let ws = new WebSocket(url); + ws.onclose = () => setTimeout(() => (ws = getSocket(url)), 100); + ws.onerror = () => ws.close(); + return ws; +}; diff --git a/js/ws.ts b/js/ws.ts new file mode 100644 index 0000000..5995bc1 --- /dev/null +++ b/js/ws.ts @@ -0,0 +1,8 @@ +const getSocket = (url: string): WebSocket => { + let ws = new WebSocket(url); + + ws.onclose = () => setTimeout(() => (ws = getSocket(url)), 100); + ws.onerror = () => ws.close(); + + return ws; + }; \ No newline at end of file diff --git a/src/box-db.go b/src/box-db.go deleted file mode 100644 index ea1359b..0000000 --- a/src/box-db.go +++ /dev/null @@ -1,73 +0,0 @@ -package main - -import ( - "database/sql" - - _ "modernc.org/sqlite" // Import the SQLite driver -) - -func initDb() *sql.DB { - - db, err := sql.Open("sqlite", "./data/data.db?_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(ON)") - if err != nil { - e.Logger.Fatal(err) - } - - // Create a table - sqlStmt := ` - CREATE TABLE IF NOT EXISTS boxes (id INTEGER PRIMARY KEY, value BOOLEAN); - ` - - _, err = db.Exec(sqlStmt) - if err != nil { - e.Logger.Fatalf("%q: %s\n", err, sqlStmt) - } - - return db -} - -func getBoxes() map[int]bool { - - rows, err := db.Query("SELECT id, value FROM boxes") - if err != nil { - e.Logger.Fatal(err) - } - - boxes := make(map[int]bool, 1000) - for i := 0; i < 1000; i++ { - boxes[i] = false - } - for rows.Next() { - var id int - var value bool - err = rows.Scan(&id, &value) - if err != nil { - e.Logger.Fatal(err) - } - boxes[id] = value - } - defer rows.Close() - - return boxes -} - -func setBox(id int, value bool) { - e.Logger.Info("START INSERT") - - stmt, err := db.Prepare("INSERT OR REPLACE INTO boxes(id, value) VALUES(?, ?)") - if err != nil { - e.Logger.Fatal(err) - } - - e.Logger.Info("PREPARED") - - res, err := stmt.Exec(id, value) - if err != nil { - e.Logger.Fatal(err) - } - stmt.Close() - - e.Logger.Info("INSERTED") - - e.Logger.Info(res) -} diff --git a/src/boxes.go b/src/boxes.go deleted file mode 100644 index 669aea8..0000000 --- a/src/boxes.go +++ /dev/null @@ -1,102 +0,0 @@ -package main - -import ( - "strconv" - "strings" - "sync" - - "github.com/labstack/echo/v4" - "github.com/labstack/gommon/log" - "golang.org/x/net/websocket" -) - -var ( - wsConnections = make(map[*websocket.Conn]bool) - wsMutex sync.Mutex - db = initDb() -) - -func handleWsError(err error, conn *websocket.Conn) { - if err != nil { - log.Errorf("Failed to handle websocket: %v", err) - conn.Close() - wsMutex.Lock() - defer wsMutex.Unlock() - delete(wsConnections, conn) - } -} - -func broadcastMessage(message string) { - wsMutex.Lock() - defer wsMutex.Unlock() - - for conn := range wsConnections { - err := websocket.Message.Send(conn, message) - handleWsError(err, conn) - - } -} - -func formatMessage(index int, checked bool) string { - message := "u:" + strconv.Itoa(index) - if checked { - message += ":+" - } else { - message += ":-" - } - return message -} - -func handleMessage(msg string, ws *websocket.Conn) error { - if strings.Contains(msg, "u:") { - parts := strings.Split(msg, ":") - index, err := strconv.Atoi(parts[1]) - if err != nil { - return err - } - checked := parts[2] == "+" - - message := formatMessage(index, checked) - broadcastMessage(message) - - setBox(index, checked) - } - if strings.Contains(msg, "ping") { - len := len(wsConnections) - websocket.Message.Send(ws, "pong-"+strconv.Itoa(len)) - } - return nil -} - -func initWs(c echo.Context) error { - websocket.Handler(func(ws *websocket.Conn) { - wsMutex.Lock() - wsConnections[ws] = true - wsMutex.Unlock() - - boxes := getBoxes() - - initialState := "i:" - for index, checked := range boxes { - if checked { - initialState += strconv.Itoa(index) + ";" - } - } - - err := websocket.Message.Send(ws, initialState) - handleWsError(err, ws) - - for { - var msg string - err := websocket.Message.Receive(ws, &msg) - handleWsError(err, ws) - if err != nil { - break - } - handleMessage(msg, ws) - log.Infof("Received message: %s", msg) - } - }).ServeHTTP(c.Response(), c.Request()) - - return nil -} diff --git a/src/boxes/box-db.go b/src/boxes/box-db.go new file mode 100644 index 0000000..aec5e11 --- /dev/null +++ b/src/boxes/box-db.go @@ -0,0 +1,87 @@ +package boxes + +import ( + "database/sql" + + "github.com/labstack/gommon/log" + + _ "modernc.org/sqlite" // Import the SQLite driver +) + +func initDb() *sql.DB { + + db, err := sql.Open("sqlite", "./data/data.db?_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(ON)") + if err != nil { + log.Fatal(err) + } + + // Create a table + sqlStmt := `CREATE TABLE IF NOT EXISTS boxes (id INTEGER PRIMARY KEY, value BOOLEAN);` + + _, err = db.Exec(sqlStmt) + if err != nil { + log.Fatalf("%q: %s\n", err, sqlStmt) + } + + return db +} + +func GetBoxes() []Box { + rows, err := db.Query("SELECT id, value FROM boxes") + if err != nil { + log.Fatal(err) + } + + boxes := make([]Box, 1024) + for i := 0; i < 1024; i++ { + boxes[i] = Box{i, false} + } + for rows.Next() { + var id int + var value bool + err = rows.Scan(&id, &value) + if err != nil { + log.Fatal(err) + } + boxes[id].Value = value + } + defer rows.Close() + + return boxes +} + +func (box Box) persist() { + + stmt, err := db.Prepare("INSERT OR REPLACE INTO boxes(id, value) VALUES(?, ?)") + if err != nil { + log.Fatal(err) + } + + res, err := stmt.Exec(box.Id, box.Value) + if err != nil { + log.Fatal(err) + } + stmt.Close() + + log.Info(res.LastInsertId()) +} + +func getBox(id int) (Box, error) { + var value bool + + stmt, err := db.Prepare("SELECT value FROM boxes WHERE id = ?") + if err != nil { + return Box{}, err + } + defer stmt.Close() + + err = stmt.QueryRow(id).Scan(&value) + if err != nil { + if err == sql.ErrNoRows { + return Box{}, nil + } + return Box{}, err + } + + return Box{id, value}, nil +} diff --git a/src/boxes/boxes.go b/src/boxes/boxes.go new file mode 100644 index 0000000..fef9256 --- /dev/null +++ b/src/boxes/boxes.go @@ -0,0 +1,152 @@ +package boxes + +import ( + "fmt" + "math/rand" + "strconv" + "strings" + "sync" + "time" + + "github.com/labstack/echo/v4" + "github.com/labstack/gommon/log" + "golang.org/x/net/websocket" +) + +var ( + wsConnections = make(map[*websocket.Conn]bool) + wsMutex sync.Mutex + db = initDb() + random = rand.New(rand.NewSource(time.Now().UnixNano())) +) + +type Box struct { + Id int + Value bool +} + +func deserializeBox(msg string) (Box, error) { + parts := strings.Split(msg, ":") + index, err := strconv.Atoi(parts[1]) + if err != nil { + return Box{}, err + } + checked := parts[2] == "+" + return Box{index, checked}, nil +} + +func (box Box) serialize() string { + message := "b:" + strconv.Itoa(box.Id) + if box.Value { + message += ":+" + } else { + message += ":-" + } + return message + "\n" +} + +func handleWsError(err error, conn *websocket.Conn) { + if err != nil { + log.Errorf("Failed to handle websocket: %v", err) + conn.Close() + wsMutex.Lock() + defer wsMutex.Unlock() + delete(wsConnections, conn) + } +} + +func broadcastMessage(message string) { + wsMutex.Lock() + defer wsMutex.Unlock() + + for conn := range wsConnections { + err := websocket.Message.Send(conn, message) + handleWsError(err, conn) + + } +} + +func handleMessage(msg string, ws *websocket.Conn) error { + if msg == "gol" { + matrix := make(map[string]Box) + boxes := GetBoxes() + index := 0 + for i := 0; i < 32; i++ { + for j := 0; j < 32; j++ { + matrix[fmt.Sprintf("%d-%d", i, j)] = boxes[index] + index++ + } + } + log.Error(matrix) + nextGen := make([]Box, 0) + for id, item := range matrix { + nextItem := shouldBeAlive(matrix, id) + if nextItem.Value != item.Value { + nextGen = append(nextGen, shouldBeAlive(matrix, id)) + } + + } + + nextMessage := "" + for _, item := range nextGen { + item.persist() + nextMessage += item.serialize() + } + broadcastMessage(nextMessage) + + } else if msg == "random" { + index := random.Int() % 1000 + box, err := getBox(index) + if err != nil { + log.Fatal(err) + } + box.Value = !box.Value + box.persist() + + message := box.serialize() + broadcastMessage(message) + + } else if strings.Contains(msg, "b:") { + box, err := deserializeBox(msg) + if err != nil { + return err + } + + broadcastMessage(msg) + box.persist() + } else if strings.Contains(msg, "ping") { + len := len(wsConnections) + websocket.Message.Send(ws, "pong-"+strconv.Itoa(len)) + } + return nil +} + +func InitWs(c echo.Context) error { + websocket.Handler(func(ws *websocket.Conn) { + wsMutex.Lock() + wsConnections[ws] = true + wsMutex.Unlock() + + boxes := GetBoxes() + msg := "" + for _, box := range boxes { + msg += box.serialize() + } + + err := websocket.Message.Send(ws, msg) + handleWsError(err, ws) + + for { + var msg string + err := websocket.Message.Receive(ws, &msg) + handleWsError(err, ws) + if err != nil { + break + } + handleMessage(msg, ws) + log.Infof("Received message: %s", msg) + } + }).ServeHTTP(c.Response(), c.Request()) + + return nil +} diff --git a/src/boxes/matrix.go b/src/boxes/matrix.go new file mode 100644 index 0000000..b373b3a --- /dev/null +++ b/src/boxes/matrix.go @@ -0,0 +1,70 @@ +package boxes + +import ( + "fmt" + "strconv" + "strings" +) + +func shouldBeAlive(matrix map[string]Box, key string) Box { + parts := strings.Split(key, "-") + i, _ := strconv.Atoi(parts[0]) + j, _ := strconv.Atoi(parts[1]) + + self := matrix[key] + nextGen := Box{self.Id, self.Value} + + count := getCount(matrix, i, j) + if self.Value && count < 2 { + nextGen.Value = false + } else if self.Value && count > 3 { + nextGen.Value = false + } else if !self.Value && count == 3 { + nextGen.Value = true + } + + return nextGen +} + +func getCount(matrix map[string]Box, i, j int) int { + count := 0 + + if isAlive(matrix, i-1, j-1) { + count++ + } + + if isAlive(matrix, i-1, j) { + count++ + } + + if isAlive(matrix, i-1, j+1) { + count++ + } + + if isAlive(matrix, i, j-1) { + count++ + } + + if isAlive(matrix, i, j+1) { + count++ + } + + if isAlive(matrix, i+1, j-1) { + count++ + } + + if isAlive(matrix, i+1, j) { + count++ + } + + if isAlive(matrix, i+1, j+1) { + count++ + } + + return count +} + +func isAlive(matrix map[string]Box, i, j int) bool { + item, ok := matrix[fmt.Sprintf("%d-%d", i, j)] + return ok && item.Value +} diff --git a/src/draw/draw.go b/src/draw/draw.go index 6491fab..dac3514 100644 --- a/src/draw/draw.go +++ b/src/draw/draw.go @@ -30,9 +30,9 @@ func broadcastMessage(message string, ws *websocket.Conn) { defer wsMutex.Unlock() for conn := range wsConnections { - // if ws == conn { - // continue - // } + if ws == conn { + continue + } err := websocket.Message.Send(conn, message) handleWsError(err, conn) diff --git a/src/main.go b/src/main.go index bd22a44..ab14947 100644 --- a/src/main.go +++ b/src/main.go @@ -7,6 +7,7 @@ import ( "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/labstack/gommon/log" + "knet.sk/src/boxes" "knet.sk/src/draw" ) @@ -25,10 +26,10 @@ func NewTemplates() *Templates { } type Page struct { - Boxes map[int]bool + Boxes []boxes.Box } -func newPage(boxes map[int]bool) Page { +func newPage(boxes []boxes.Box) Page { return Page{ Boxes: boxes, } @@ -50,20 +51,16 @@ func main() { e.Static("/js", "js") e.GET("/", func(c echo.Context) error { - return c.Render(200, "index", newPage(getBoxes())) + return c.Render(200, "index", newPage(boxes.GetBoxes())) }) + e.GET("/boxes/ws", boxes.InitWs) - e.GET("/ws", initWs) - - //favicon e.File("/favicon.ico", "images/favicon.ico") e.GET("/draw", draw.Page) e.GET("/draw/ws", draw.InitWs) e.Logger.Fatal(e.Start(":54321")) - - defer db.Close() } func healthCheck(c echo.Context) error { diff --git a/views/boxes.html b/views/boxes.html index c652561..1c57efc 100644 --- a/views/boxes.html +++ b/views/boxes.html @@ -3,19 +3,27 @@
+
- {{range $index, $value := .}}{{end}}
+ {{end}} diff --git a/views/draw.html b/views/draw.html index 7b0a3fb..44b981e 100644 --- a/views/draw.html +++ b/views/draw.html @@ -23,6 +23,7 @@ bottom: 0; " > + {{end}}