15// by gera 15// public domain 02package15 hello_life 02import15 sdl15 05"vendor:sdl3" ClearBoard15 ::15 proc(pixels15 :15 [][024]u8,15 color15 :15 [024]u8)15 { 15 02for15 i15 in15 020..<10len(pixels)15 { 15 pixels[i]15 =15 color 15 } } DrawCells15 ::15 proc(cells15 :15 ^02map[[022]i32]10bool,15 pixels15 :15 [][024]u8,15 color15 :15 [024]u8,15 w,15 h15 :15 i32)15 { 15 02for15 cell15 in15 cells15 { 15 02if15 cell.x15 >=15 02015 &&15 cell.y15 >=15 02015 &&15 cell.x15 <15 w15 &&15 cell.y15 <15 h15 { 15 pixels[cell.x15 +15 cell.y15 *15 w]15 =15 color 15 } 15 } } CountNeighbors15 ::15 proc(cells15 :15 ^02map[[022]i32]10bool,15 pos15 :15 [022]i32)15 ->15 i32 { 15 count15 :15 i32 15 count15 +=15 i32(cells[{pos.x15 +15 021,15 pos.y}]) 15 count15 +=15 i32(cells[{pos.x15 +15 021,15 pos.y15 +15 021}]) 15 count15 +=15 i32(cells[{pos.x,15 pos.y15 +15 021}]) 15 count15 +=15 i32(cells[{pos.x15 -15 021,15 pos.y15 +15 021}]) 15 count15 +=15 i32(cells[{pos.x15 -15 021,15 pos.y}]) 15 count15 +=15 i32(cells[{pos.x15 -15 021,15 pos.y15 -15 021}]) 15 count15 +=15 i32(cells[{pos.x,15 pos.y15 -15 021}]) 15 count15 +=15 i32(cells[{pos.x15 +15 021,15 pos.y15 -15 021}]) 15 02return15 count } ApplyRulesOnCell15 ::15 proc(cellscur,15 cellsnext15 :15 ^02map[[022]i32]10bool,15 pos15 :15 [022]i32) { 15 neighbors15 :=15 CountNeighbors(cellscur,15 pos) 15 alive15 :=15 cellscur[pos] 15 02if15 (alive15 &&15 (neighbors15 <15 02215 ||15 neighbors15 >15 023))15 do15 delete_key(cellsnext,15 pos) 15 02else15 02if15 (!alive15 &&15 neighbors15 ==15 023)15 do15 cellsnext[pos]15 =15 02true 15 02else15 02if15 (alive15 &&15 (neighbors15 ==15 02215 ||15 neighbors15 ==15 023))15 do15 cellsnext[pos]15 =15 02true } ComputeLife15 ::15 proc(cellscur,15 cellsnext15 :15 ^02map[[022]i32]10bool) { 15 10clear(cellsnext) 15 02for15 cell15 in15 cellscur15 { 15 x15 :=15 cell[020] 15 y15 :=15 cell[021] 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x,15 y}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 +15 021,15 y}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 +15 021,15 y15 +15 021}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x,15 y15 +15 021}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 -15 021,15 y15 +15 021}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 -15 021,15 y}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 -15 021,15 y15 -15 021}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x,15 y15 -15 021}) 15 ApplyRulesOnCell(cellscur,15 cellsnext,15 {x15 +15 021,15 y15 -15 021}) 15 } } main15 ::15 proc()15 { 15 result15 :=15 sdl.Init({.VIDEO}) 15 window15 :15 ^sdl.Window 15 renderer15 :15 ^sdl.Renderer 15 result15 =15 sdl.CreateWindowAndRenderer(05"Game of Life",15 width15 =15 02640,15 height15 =15 02480, 15 window_flags15 =15 {.RESIZABLE,}, 15 window15 =15 &window,15 renderer15 =15 &renderer) 15 texture15 :=15 sdl.CreateTexture(renderer,15 sdl.PixelFormat.ABGR8888,15 sdl.TextureAccess.STREAMING,15 02320,15 02240) 15 sdl.SetRenderLogicalPresentation(renderer,15 texture.w,15 texture.h,15 sdl.RendererLogicalPresentation.LETTERBOX) 15 sdl.SetTextureScaleMode(texture,15 sdl.ScaleMode.PIXELART) 15 cells115 :15 02map[[022]i32]10bool 15 cells215 :15 02map[[022]i32]10bool 15 cellsfront15 :=15 &cells1 15 cellsback15 :=15 &cells2 15/* initial state: 15 **** 15 * 15 * 15 * 15*/ 15 cellsfront[{020+texture.w/022,15 020+texture.h/022}]15 =15 02true 15 cellsfront[{021+texture.w/022,15 020+texture.h/022}]15 =15 02true 15 cellsfront[{022+texture.w/022,15 020+texture.h/022}]15 =15 02true 15 cellsfront[{023+texture.w/022,15 020+texture.h/022}]15 =15 02true 15 cellsfront[{021+texture.w/022,15 021+texture.h/022}]15 =15 02true 15 cellsfront[{022+texture.w/022,15 022+texture.h/022}]15 =15 02true 15 cellsfront[{022+texture.w/022,15 023+texture.h/022}]15 =15 02true 15 running15 :15 10bool15 =15 02true 15 time_start15 :15 u64 15 loop:15 02for15 running15 { 15 time_start15 =15 sdl.GetTicksNS() 15 event15 :15 sdl.Event 15 result15 =15 sdl.PollEvent(&event) 15 04#partial15 02switch15 event.02type15 { 15 02case15 .QUIT: 15 running15 =15 02false 15 02break15 loop 15 } 15 pixels_rawptr15 :15 rawptr 15 pitch15 :15 i32 15 sdl.LockTexture(texture,15 02nil,15 &pixels_rawptr,15 &pitch) 15 pixels15 :=15 ([^][024]u8)(pixels_rawptr)[:texture.w15 *15 texture.h] 15 ClearBoard(pixels,15 {02200,15 02200,15 02200,15 02255}) 15 DrawCells(cellsfront,15 pixels,15 {020,15 020,15 02255,15 02255},15 texture.w,15 texture.h) 15 sdl.UnlockTexture(texture) 15 sdl.RenderClear(renderer) 15 sdl.RenderTexture(renderer,15 texture,15 02nil,15 02nil) 15 sdl.RenderPresent(renderer) 15 ComputeLife(cellsfront,15 cellsback) 15 cellsfront,15 cellsback15 =15 cellsback,15 cellsfront 15 time_end15 :=15 sdl.GetTicksNS() 15 15// do more generations but maintain the target fps 15 02for15 time_end15 -15 time_start15 <15 021e9/023015 { 15 ComputeLife(cellsfront,15 cellsback) 15 cellsfront,15 cellsback15 =15 cellsback,15 cellsfront 15 15// also handle events so the window doesn't lag 15 result15 =15 sdl.PollEvent(&event) 15 04#partial15 02switch15 event.02type15 { 15 02case15 .QUIT: 15 running15 =15 02false 15 02break15 loop 15 } 15 time_end15 =15 sdl.GetTicksNS() 15 } 15 } 15 sdl.DestroyRenderer(renderer) 15 sdl.DestroyWindow(window) 15 sdl.Quit() }