{"id":"rfrxsm","deleted":false,"future_paste":false,"expired":false,"language":"go","created_at":"2026-02-14 01:59:00","expires_at":null,"content":"\/\/ by gera\r\n\/\/ public domain\r\npackage hello_life\r\n\r\nimport sdl \"vendor:sdl3\"\r\n\r\nClearBoard :: proc(pixels : [][4]u8, color : [4]u8) {\r\n\tfor i in 0..<len(pixels) {\r\n\t\tpixels[i] = color\r\n\t}\r\n}\r\n\r\nDrawCells :: proc(cells : ^map[[2]i32]bool, pixels : [][4]u8, color : [4]u8, w, h : i32) {\r\n\tfor cell in cells {\r\n\t\tif cell.x >= 0 && cell.y >= 0 && cell.x < w && cell.y < h {\r\n\t\t\tpixels[cell.x + cell.y * w] = color\r\n\t\t}\r\n\t}\r\n}\r\n\r\nCountNeighbors :: proc(cells : ^map[[2]i32]bool, pos : [2]i32) -> i32\r\n{\r\n\tcount : i32\r\n\tcount += i32(cells[{pos.x + 1, pos.y}])\r\n\tcount += i32(cells[{pos.x + 1, pos.y + 1}])\r\n\tcount += i32(cells[{pos.x, pos.y + 1}])\r\n\tcount += i32(cells[{pos.x - 1, pos.y + 1}])\r\n\tcount += i32(cells[{pos.x - 1, pos.y}])\r\n\tcount += i32(cells[{pos.x - 1, pos.y - 1}])\r\n\tcount += i32(cells[{pos.x, pos.y - 1}])\r\n\tcount += i32(cells[{pos.x + 1, pos.y - 1}])\r\n\treturn count\r\n}\r\n\r\nApplyRulesOnCell :: proc(cellscur, cellsnext : ^map[[2]i32]bool, pos : [2]i32)\r\n{\r\n\tneighbors := CountNeighbors(cellscur, pos)\r\n\talive := cellscur[pos]\r\n\tif (alive && (neighbors < 2 || neighbors > 3)) do delete_key(cellsnext, pos)\r\n\telse if (!alive && neighbors == 3) do cellsnext[pos] = true\r\n\telse if (alive && (neighbors == 2 || neighbors == 3)) do cellsnext[pos] = true\r\n}\r\n\r\nComputeLife :: proc(cellscur, cellsnext : ^map[[2]i32]bool)\r\n{\r\n\tclear(cellsnext)\r\n\tfor cell in cellscur {\r\n\t\tx := cell[0]\r\n\t\ty := cell[1]\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x, y})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x + 1, y})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x + 1, y + 1})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x, y + 1})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x - 1, y + 1})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x - 1, y})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x - 1, y - 1})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x, y - 1})\r\n\t\tApplyRulesOnCell(cellscur, cellsnext, {x + 1, y - 1})\r\n\t}\r\n}\r\n\r\nmain :: proc() {\r\n\tresult := sdl.Init({.VIDEO})\r\n\twindow : ^sdl.Window\r\n\trenderer : ^sdl.Renderer\r\n\tresult = sdl.CreateWindowAndRenderer(\"Game of Life\", width = 640, height = 480,\r\n\t\t\t\t\t\t\t\t\t\t window_flags = {.RESIZABLE,},\r\n\t\t\t\t\t\t\t\t\t\t window = &window, renderer = &renderer)\r\n\ttexture := sdl.CreateTexture(renderer, sdl.PixelFormat.ABGR8888, sdl.TextureAccess.STREAMING, 320, 240)\r\n\tsdl.SetRenderLogicalPresentation(renderer, texture.w, texture.h, sdl.RendererLogicalPresentation.LETTERBOX)\r\n\tsdl.SetTextureScaleMode(texture, sdl.ScaleMode.PIXELART)\r\n\r\n\tcells1 : map[[2]i32]bool\r\n\tcells2 : map[[2]i32]bool\r\n\tcellsfront := &cells1\r\n\tcellsback := &cells2\r\n\r\n\/* initial state:\r\n\t****\r\n\t *\r\n\t  *\r\n\t  *\r\n*\/\r\n\tcellsfront[{0+texture.w\/2, 0+texture.h\/2}] = true\r\n\tcellsfront[{1+texture.w\/2, 0+texture.h\/2}] = true\r\n\tcellsfront[{2+texture.w\/2, 0+texture.h\/2}] = true\r\n\tcellsfront[{3+texture.w\/2, 0+texture.h\/2}] = true\r\n\tcellsfront[{1+texture.w\/2, 1+texture.h\/2}] = true\r\n\tcellsfront[{2+texture.w\/2, 2+texture.h\/2}] = true\r\n\tcellsfront[{2+texture.w\/2, 3+texture.h\/2}] = true\r\n\r\n\trunning : bool = true\r\n\ttime_start : u64\r\n\tloop: for running {\r\n\t\ttime_start = sdl.GetTicksNS()\r\n\t\tevent : sdl.Event\r\n\t\tresult = sdl.PollEvent(&event)\r\n\t\t#partial switch event.type {\r\n\t\t\tcase .QUIT:\r\n\t\t\trunning = false\r\n\t\t\tbreak loop\r\n\t\t}\r\n\r\n\t\tpixels_rawptr : rawptr\r\n\t\tpitch : i32\r\n\t\tsdl.LockTexture(texture, nil, &pixels_rawptr, &pitch)\r\n\t\tpixels := ([^][4]u8)(pixels_rawptr)[:texture.w * texture.h]\r\n\t\tClearBoard(pixels, {200, 200, 200, 255})\r\n\t\tDrawCells(cellsfront, pixels, {0, 0, 255, 255}, texture.w, texture.h)\r\n\t\tsdl.UnlockTexture(texture)\r\n\t\tsdl.RenderClear(renderer)\r\n\t\tsdl.RenderTexture(renderer, texture, nil, nil)\r\n\t\tsdl.RenderPresent(renderer)\r\n\r\n\t\tComputeLife(cellsfront, cellsback)\r\n\t\tcellsfront, cellsback = cellsback, cellsfront\r\n\r\n\t\ttime_end := sdl.GetTicksNS()\r\n\t\t\/\/ do more generations but maintain the target fps\r\n\t\tfor time_end - time_start < 1e9\/30 {\r\n\t\t\tComputeLife(cellsfront, cellsback)\r\n\t\t\tcellsfront, cellsback = cellsback, cellsfront\r\n\t\t\t\/\/ also handle events so the window doesn't lag\r\n\t\t\tresult = sdl.PollEvent(&event)\r\n\t\t\t#partial switch event.type {\r\n\t\t\t\tcase .QUIT:\r\n\t\t\t\trunning = false\r\n\t\t\t\tbreak loop\r\n\t\t\t}\r\n\t\t\ttime_end = sdl.GetTicksNS()\r\n\t\t}\r\n\t}\r\n\r\n\tsdl.DestroyRenderer(renderer)\r\n\tsdl.DestroyWindow(window)\r\n\tsdl.Quit()\r\n}"}