Advertisement
taoshi

John Conway's Game of Life (evolutionary automaton)

Oct 21st, 2024 (edited)
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.96 KB | Gaming | 0 0
  1. --programm Evolution. Author Taoshi (Zardar)
  2. local evo={}
  3. local fast, skipFrames, skip = false, 5, 0
  4. local computer, component = require('computer'), require('component')
  5. local unicode = require('unicode')
  6. local gpu, term  = require('component').gpu, require('term')
  7. local text,show = '',''
  8. local x_dim, y_dim = gpu.getResolution()
  9. local xs, ys = x_dim*2-8, y_dim*4-16 --размер в символах брайля
  10. local iter, dots, changes, neighbors, left, right = 0, 0, 0, 0,'left','right'
  11. local pullSignal = computer.pullSignal
  12. local field, snap, screen, actualFieldChanges = {},{},{},{}
  13. local chars, actions,presets = {},{},{}
  14. local mode, restart  = 'edit', false--текущее состояние программы
  15. local time = computer.uptime()
  16. local t, timePlayed, preX, preY = time, 0
  17. local fg, fgl = gpu.getForeground(),20
  18. local events = {touch='touch',drag='touch',drop='touch',key_up='keyUp'}
  19. local buttons = {'(C)lear  (E)dit  (P)lay  (R)estart  (T)erminate',
  20.     '(S)top  (P)lay  (C)lear  (T)erminate  ЛКМ - рисовать, ПКМ - стереть',
  21.     '(S)top  (R)estart  (E)dit  (T)erminate'
  22. }--SPECTR
  23. local ru_keys={[11]='s',[1]='c',[3]='e',[23]='p',[26]='r',[21]='t'}
  24. local char = {} for f = 0, 255 do char[f] = unicode.char(10240+f) end
  25. local bits = {}
  26. bits[1]={1,8,2,16,4,32,64,128} bits[0]={-1,-8,-2,-16,-4,-32,-64,-128}
  27.  --добавим символы для линий и углов
  28. local vert1, vert2, line = char[184], char[71], char[54]
  29. local  tl, tr = char[176]..char[118], char[182]..char[70]
  30. local  bl, br = char[56]..char[55], char[62]..char[7]
  31. local cll, line = string.rep(' ',x_dim-2), string.rep(line,x_dim-4)
  32. local topLine, bottomLine = tl..line..tr, bl..line..br
  33. vert1, vert2 = string.rep(vert1,y_dim-4), string.rep(vert2,y_dim-4)
  34. screen.left,screen.right, l, r = {},{}, 'left', 'right'
  35. component.screen.setPrecise(true)
  36. ------------------------------ ------------------------------------
  37. function computer.pullSignal(...)
  38.     local e = {pullSignal(...)}
  39.         if events[e[1]] then
  40.             return actions[events[e[1]]](e)
  41.         end
  42.     return true --table.unpack(e)
  43. end
  44. actions.s=function()--select
  45.     if mode == 'edit' then evo.saveChanges() end
  46.     mode = 'select' return evo.select() --true
  47.  end
  48. actions.p=function()--play
  49.     if mode == 'play' then return true end
  50.     return evo.play()
  51.  end
  52. actions.e=function(e)--edit
  53.     if mode ~= 'edit' then return evo.gotoEdit() end --true
  54.     return true
  55.  end
  56. actions.c=function()--clear
  57.     --if mode == 'play' then return true end
  58.     mode = 'select' term.clear() evo.border() evo.tablesInit()
  59.     return evo.select()
  60.  end
  61. actions.t=function()--terminate
  62.     mode ='terminate' return evo.terminate() --true
  63.  end
  64. actions.r=function()--restart
  65.     if mode ~= 'select' and mode ~= 'play' then return true end  
  66.     if restart then mode = 'restart' end
  67.     return evo.restart() --true
  68.  end
  69. actions.touch=function(e)
  70.     if mode ~= 'edit' then
  71.          return true
  72.     end
  73.     return evo.edit(e)  
  74.  end
  75. actions.keyUp=function(e)
  76.     local key=math.floor(e[3])
  77.     if key > 127 then
  78.         key = ru_keys[bit32.band(31,key)]
  79.     else
  80.         key=string.lower(string.char(key))
  81.     end
  82.     if actions[key] then
  83.         return actions[key](e)
  84.     end
  85.     return true
  86.  end
  87. ------------------------------------------------------
  88. function evo.select()
  89.  --вывод clear, edit, play
  90.     if mode == 'play' then mode = 'pause'
  91.     else mode = 'select' end
  92.   gpu.set(3,y_dim-1,cll) gpu.setForeground(0xf000f0)
  93.   gpu.set(3,y_dim-1,buttons[1])
  94.   return true
  95.  end
  96.  
  97. function evo.play()
  98.     gpu.setForeground(fg) gpu.set(3,y_dim-1,cll)
  99.     gpu.set(3,y_dim-1,buttons[3])
  100.     if mode == 'pause' then return evo.main() end
  101.     mode='play' evo.saveChanges()
  102.     evo.toUnicode() evo.showMustGoOne()
  103.     return evo.main()
  104.  end
  105.  
  106. function evo.userDraw(x,y,m)
  107.     local charOnScreen= gpu.get(math.floor(x),math.floor(y))
  108.     local byte,byte2,byte3
  109.         if #charOnScreen<3 then byte = 0
  110.         else
  111.             byte2=string.byte(charOnScreen,2) byte3=string.byte(charOnScreen,3)
  112.             byte=bit32.lshift(bit32.band(byte2,3),6)+bit32.band(byte3,63)
  113.         end
  114.  
  115.         field[math.floor((y-2)*4+1)][math.floor((x-3)*2)+1] = bit32.bxor(1,m)
  116.  
  117.         local w = math.floor((x-math.floor(x))*2)
  118.         local h = math.floor((y-math.floor(y))*4)
  119.         local pixel= bits[1][1+(w+h*2)]
  120.         if m == 0 then byte = bit32.bor(byte,pixel)
  121.         else pixel = bit32.bxor(pixel,255) byte = bit32.band(byte,pixel) end
  122.         gpu.set(x,y,char[byte])    
  123.     return true
  124.  end
  125.  
  126. function evo.edit(e)
  127.     local x, y, m = 4*((e[3])+1), 8*((e[4])+1), e[5]
  128.     if y/2>=ys+4 or x/2>=xs+2 or y/8<2 or x/4<3 then return os.sleep(0.001) end
  129.     if m ~= 'drag' then
  130.         if (preX < 0 or (math.abs(x-preX) < 2 and math.abs(y-preY) < 2))
  131.             then evo.userDraw(x/4,y/8,m) preX = x preY = y
  132.             os.sleep(0.001) return true
  133.         end
  134.     end
  135.    
  136.     if x-preX > 0 then addX = 1 else addX = -1 end
  137.     if y-preY > 0 then addY = 1 else addY = -1 end
  138.     if math.abs(x-preX)>math.abs(y-preY) then
  139.         addY = addY * math.abs(y-preY)/math.abs(x-preX)
  140.     else addX = addX * math.abs(x-preX)/math.abs(y-preY) end
  141.  
  142.     xpos = preX + addX ypos = preY + addY
  143.     xdist=0 ydist=0
  144.     while ydist <= math.abs(y-preY) and xdist <= math.abs(x-preX) do
  145.         evo.userDraw(xpos/4,ypos/8,m)
  146.         ydist, xdist = ydist + math.abs(addY), xdist + math.abs(addX)
  147.         ypos, xpos = ypos + addY, xpos + addX
  148.     end
  149.     preX, preY = x, y os.sleep(0.001)
  150.     return true
  151.  end
  152. function evo.clear()
  153.     term.clear() evo.border() evo.tablesInit()
  154.     return evo.select()
  155.  end
  156. function evo.terminate()
  157.     term.clear()
  158.     computer.pullSignal = pullSignal
  159.     evo = nil return true
  160.  end
  161. function evo.restart()
  162.   iter = 0 evo.tablesInit()
  163.   for y in pairs (snap) do
  164.       for x in pairs (snap[y]) do
  165.           field[y][x] = snap[y][x]
  166.       end
  167.   end
  168.   return evo.play()
  169.  end
  170. -------------------------------------------------------
  171. function evo.border()
  172.     local fg = gpu.getForeground()
  173.     gpu.setForeground(0x20A020)
  174.     gpu.set(1,1,topLine)
  175.     gpu.set(1,y_dim-2,bottomLine)
  176.     gpu.set(1,2,vert1,true)
  177.     gpu.set(2,2,vert2,true)
  178.     gpu.set(x_dim-1,2,vert1,true)
  179.     gpu.set(x_dim,2,vert2,true)
  180.     gpu.setForeground(fg)
  181.     return true
  182.  end
  183.  
  184. function evo.clr_snap()
  185.     for y = 1, ys do snap[y] = {} end
  186.     return true
  187.  end
  188.  
  189. function evo.tablesInit()
  190.     for y = 1,ys do
  191.         field[y] = {} actualFieldChanges[y] = {}
  192.         screen[l][y] = {}
  193.         for x=1, xs do field[y][x] = 0 end
  194.     end
  195.     local ch_y, ch_x= math.floor(ys/4), math.floor(xs/2)
  196.     for y = 1,ch_y do chars[y]={}
  197.         for x = 1,ch_x do chars[y][x] = 0 end
  198.     end    
  199.    
  200.     return true  
  201.  end
  202.  
  203. function evo.preset()
  204.     p={}
  205.     p[1]={{0,0},{1,0},{2,0},{1,1},{2,-1}}
  206.     p[2]={{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},
  207.     {1,0},{1,2},{1,3},{1,5},{2,0},{2,1},{2,2},{2,3},
  208.     {2,5},{3,2},{3,3},{3,5},{4,2},{4,3},{4,5},
  209.     {5,2},{5,3},{5,4},{5,5}}
  210.     p[3]={{-1,-2},{0,0},{1,-3},{1,-2},{1,1},{1,2},{1,3}}
  211.  
  212.     n=3
  213.     for f = 1, #p[n] do
  214.        field[math.ceil(ys/2+p[n][f][1])]
  215.         [math.ceil(xs/2+p[n][f][2])] = 1
  216.     end
  217.    
  218.     return true
  219.  end
  220.  
  221. function evo.saveChanges()
  222.     dots = 0 changes = 0
  223.     local ch_y, ch_x= math.floor(ys/4), math.floor(xs/2)
  224.     for y = 1,ch_y do chars[y]={}
  225.         for x = 1,ch_x do chars[y][x] = 0 end
  226.     end
  227.     for y = 1, ys do
  228.         actualFieldChanges[y] = {}
  229.         snap[y] = {}
  230.     end
  231.     for y in pairs(field) do
  232.        
  233.         local yl,yr = evo.getAdjoining(y,ys)
  234.         for x in pairs(field[y])do
  235.             if field[y][x] == 1 then
  236.                 snap[y][x] = 1
  237.                  actualFieldChanges[y][x] = 1
  238.                 dots = dots + 1 changes = changes + 1
  239.                 local xl,xr = evo.getAdjoining(x,xs)
  240.                 evo.setScreen(yl,y,yr,xl,x,xr,l)
  241.             end
  242.         end
  243.     end
  244.     restart = true
  245.     return true
  246.  end
  247.  
  248. function evo.gotoEdit()
  249.     evo.clr_snap() iter = 0 gpu.set(3,y_dim,cll)
  250.     gpu.set(3,y_dim-1,cll) gpu.setForeground(0x40f040)
  251.     gpu.set(3,y_dim-1,buttons[2]) gpu.setForeground(0xff00ff)
  252.     mode = 'edit' preX= -1 preY=-1
  253.     return true
  254.  end
  255.  
  256. function evo.fail()
  257.   text='Игра окончена'
  258.   gpu.set(3,y_dim,cll)
  259.   gpu.setForeground(0xf02080)
  260.   gpu.set(20,y_dim,text)
  261.   return evo.select()
  262.  end
  263.  
  264. --вычисление координат прилегающих клеток
  265. function evo.getAdjoining(n,ns)
  266.     local yl, yr = 1,1
  267.     if n > 1 and n < ns then
  268.         yl = n-1
  269.         yr = n+1
  270.     else
  271.         if n == 1 then
  272.             yl, yr = ns, n+1
  273.         else
  274.             yl,yr = n-1, 1
  275.         end
  276.     end
  277.     return yl,yr
  278.  end
  279.  
  280. --обозначим узел и соседей узла сменившего состояние
  281. function evo.setScreen(yl,y,yr,xl,x,xr,s)
  282.     screen[s][yl][x] = '*'
  283.     screen[s][y][x] = '*'
  284.     screen[s][yr][x] = '*'
  285.     screen[s][yl][xl] = '*'
  286.     screen[s][y][xl] = '*'
  287.     screen[s][yr][xl] = '*'
  288.     screen[s][yl][xr] = '*'
  289.     screen[s][y][xr] = '*'
  290.     screen[s][yr][xr] = '*'
  291.     return true
  292.  end
  293.  
  294. --поиск узлов которые сменят состояние
  295. function evo.whatNews()
  296.     changes = 0
  297.     for y=1,ys do
  298.         screen[r][y] ={}
  299.         actualFieldChanges[y] = {}
  300.     end
  301.     --получаем из левого экрана сведения о узлах
  302.     --реалии которых нам интересны
  303.     for y in pairs (screen[l]) do
  304.         local yl,yr=evo.getAdjoining(y,ys)
  305.         for x in pairs(screen[l][y]) do
  306.             local xl,xr=evo.getAdjoining(x,xs)
  307.             neighbors =
  308.             field[y][xl] + field[y][xr] +
  309.             field[yl][xl] + field[yl][x] + field[yl][xr] +
  310.             field[yr][xl] + field[yr][x] + field[yr][xr]
  311.             if neighbors == 3 then
  312.                 if field[y][x] == 0 then
  313.                     evo.setScreen(yl,y,yr,xl,x,xr,r)
  314.                     --узел ожил
  315.                     dots = dots+1
  316.                     changes=changes+1
  317.                     actualFieldChanges[y][x] = 1
  318.                 end
  319.             else
  320.                 if neighbors ~= 2 then
  321.                     if field[y][x] == 1 then
  322.                         evo.setScreen(yl,y,yr,xl,x,xr,r)
  323.                         --узел погиб
  324.                         dots = dots-1
  325.                         changes = changes+1
  326.                         actualFieldChanges[y][x] = 0
  327.                     end
  328.                 end
  329.             end
  330.         end
  331.     end
  332.     --вычисления следующего состояния колонии завершены
  333.     --произведём имплементацию изменений
  334.     --function implement dots
  335.     for y in pairs(actualFieldChanges) do
  336.         for x in pairs(actualFieldChanges[y]) do
  337.             field[y][x] = actualFieldChanges[y][x]
  338.         end
  339.     end
  340.     if changes == 0 then return evo.fail()
  341.     else return true
  342.     end
  343.  end
  344.  
  345. --попробуем описать трансформацию значений массива в шрифт брайля
  346. function evo.toUnicode()
  347.   local ch_x,ch_y,yy,xx=0,0,0,0
  348.     for y in pairs(actualFieldChanges) do
  349.         ch_y=y+3  yy=y-1
  350.         ch_y=math.floor(ch_y/4)
  351.         for x in pairs(actualFieldChanges[y]) do
  352.           ch_x=x+1  xx=x-1
  353.             ch_x=math.floor(ch_x/2)
  354.             chars[ch_y][ch_x]=chars[ch_y][ch_x]
  355.             +bits[actualFieldChanges[y][x]][1+(yy%4)*2+xx%2]
  356.         end
  357.     end
  358.     return true
  359.  end
  360.  
  361. --теперь выведем на экран символы брайля
  362. function evo.showMustGoOne()
  363.     if fast == true and skip > 0 then skip = skip - 1 return true
  364.     else skip = skipFrames end
  365.     local line, show, z
  366.     for y in pairs(chars)do
  367.         line, show, z = '', '', 0
  368.         for x in pairs(chars[y]) do
  369.             if chars[y][x] > 255 or chars[y][x]<0 then
  370.                 gpu.set(y_dim,40,tostring(chars[y][x])..'  ')
  371.             end
  372.             show = show..char[chars[y][x]]
  373.             z = z + 1
  374.             if z > 15 then z = 0 line = line .. show show = '' end
  375.         end
  376.         line = line .. show gpu.set(3,y+1,line)
  377.     end
  378.     return true
  379.  end
  380.  
  381. function evo.iteration()gpu.set(x_dim-20,y_dim,('iteration:' .. tostring(iter)))
  382.     text = 'поколение:'..tostring(iter)..' узлы:'..tostring(dots)..'    '
  383.     gpu.set(3,y_dim,text) iter = iter + 1
  384.     l,r = r,l
  385.     if skip == skipFrames then os.sleep(0.001) end
  386.    
  387.     return true
  388.  end
  389.  
  390. function evo.main()
  391.     while mode=='play' do
  392.       evo.whatNews()
  393.       evo.toUnicode()
  394.       evo.showMustGoOne()
  395.       evo.iteration()
  396.     end
  397.     return true
  398.  end
  399. -----------------------------------------------------
  400. evo.border() evo.clr_snap() evo.tablesInit()
  401. evo.preset() evo.play()
  402. while mode ~= 'terminate' do os.sleep(0.11) end
  403. gpu.setForeground(fg) return true
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement