seiterarch

Langton

Mar 1st, 2013
365
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.00 KB | None | 0 0
  1. --Langton's Ant simulator v1.01 by seiterarch
  2. --Usage:  langton [monitorSide] [sequential] [step]  |Default: langton top false 1
  3.  
  4. --Setting 'sequential = false' will attempt to generate the pattern without delay.
  5. --This will often cause 'too long without yielding'
  6. --Setting step higher than one will generate the pattern faster.
  7.  
  8. --Right clicking on the monitor during sequential generation will end the generator.
  9. --Right clicking on the monitor once generation has stopped will start a new randomised generator.
  10. --The background colour of the generator is random, but will be treated as black.
  11. --You can set a default background at line 148.
  12.  
  13. --Define variables
  14. local colourList = {}
  15. local coloursUsed = {}
  16. local coloursUnused  = {}
  17. local dir = 1
  18. local x = 1
  19. local y = 1
  20. local w = 1
  21. local h = 1
  22. local grid = {}
  23. local sequential = true
  24. local step = 1
  25.  
  26. --Miscellaneous helper functions to simplify code later
  27. --Generate either -1 or 1
  28. local function randomSign()
  29.     local k = math.random(2)
  30.     return (k * 2 - 3)
  31. end
  32. --Turn integers from 1 to 16 into their colour vaues without needing to perform exponents.
  33. local function colourSwitch(c)
  34.     if c == 1 then return 1
  35.     elseif c == 2 then return 2
  36.     elseif c == 3 then return 4
  37.     elseif c == 4 then return 8
  38.     elseif c == 5 then return 16
  39.     elseif c == 6 then return 32
  40.     elseif c == 7 then return 64
  41.     elseif c == 8 then return 128
  42.     elseif c == 9 then return 256
  43.     elseif c == 10 then return 512
  44.     elseif c == 11 then return 1024
  45.     elseif c == 12 then return 2048
  46.     elseif c == 13 then return 4096
  47.     elseif c == 14 then return 8192
  48.     elseif c == 15 then return 16384
  49.     elseif c == 16 then return 32768
  50.     end
  51. end
  52.  
  53. --Helper functions for creating a ruleset.
  54.  
  55. local function initColourLists()
  56.     for i=1,16 do colourList[i] = {} end
  57.     coloursUsed = {16}
  58.     coloursUnused = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
  59. end
  60. local function chooseColours()
  61.     local n = math.random(15)
  62.     local choicesLeft = table.getn(coloursUnused)
  63.     local choice = 1
  64.    
  65.     --Choose colours randomly from the list of unchosen colours
  66.     for i=1,n do
  67.         choice = math.random(choicesLeft)
  68.         coloursUsed[i+1] = table.remove(coloursUnused, choice)
  69.         choicesLeft = choicesLeft - 1
  70.     end
  71.    
  72.     --Set up colourList linkage
  73.     for i=1,n do
  74.         colourList[coloursUsed[i]][2] = coloursUsed[i+1]
  75.     end
  76.     colourList[coloursUsed[n]][2] = coloursUsed[1]
  77. end
  78. local function chooseDirections()
  79.     local n = table.getn(coloursUsed)
  80.     local total = 0
  81.     local s = 0
  82.    
  83.     --Randomise the direction for all colours used.
  84.     for i, c in ipairs(coloursUsed) do
  85.         s = randomSign()
  86.         colourList[c][1] = s
  87.         total = total + s
  88.     end
  89.    
  90.     --If all colours turn in the same direction, switch the direction of one used colour.
  91.     if math.abs(total) == n then
  92.         colourList[coloursUsed[1]][1] = - colourList[coloursUsed[1]][1]
  93.     end
  94. end
  95.  
  96. --Function to create the play-space and position the ant/
  97. local function initGrid()
  98.     for i=1,w do
  99.         grid[i] = {}
  100.         for j=1,h do
  101.             grid[i][j] = 16
  102.         end
  103.     end
  104.    
  105.     x = math.ceil(w/2)
  106.     y = math.ceil(h/2)
  107.     dir = math.random(4)
  108. end
  109.  
  110. --Step function for ant movement.  Returns true until the ant leaves the grid.
  111. local function move()
  112.     --Move the ant
  113.     if dir == 1 then x = x + 1
  114.     elseif dir == 2 then y = y + 1
  115.     elseif dir == 3 then x = x - 1
  116.     elseif dir == 4 then y = y - 1
  117.     end
  118.    
  119.     --If out of bounds, return false to end the program
  120.     if x<1 or x>w or y<1 or y>h then
  121.         return false
  122.     end
  123.    
  124.     --Change colour of new position and direction
  125.     local c = grid[x][y]
  126.     grid[x][y] = colourList[c][2]
  127.     dir = dir + colourList[c][1]
  128.    
  129.     --Correct directions outside of possible values
  130.     if dir == 0 then dir = 4
  131.     elseif dir == 5 then dir = 1
  132.     end
  133.    
  134.     return true
  135. end
  136.  
  137. --Function to generate a ruleset and play it out.
  138. function play(monitorSide, sequential, step)
  139.     local m = peripheral.wrap(monitorSide)
  140.     if not m.isColor() then error("Advanced monitor required.") end
  141.     m.setTextScale(0.5)
  142.     w, h = m.getSize()
  143.     if sequential ~= false then sequential = true end
  144.     step = tonumber(step) or 1
  145.    
  146.     --randomise background colour
  147.     --standard can be set by replacing math.random(16) with an integer from 1 to 16
  148.     m.setBackgroundColour(colourSwitch(math.random(16)))
  149.     m.clear()
  150.    
  151.     --initialize variables and choose generator ruleset
  152.     initColourLists()
  153.     initGrid()
  154.     chooseColours()
  155.     chooseDirections()
  156.     local i = 0
  157.    
  158.     --play out the ruleset
  159.     while move() do
  160.         m.setCursorPos(x, y)
  161.         m.setBackgroundColour(colourSwitch(grid[x][y]))
  162.         m.write(" ")
  163.         i = i + 1
  164.        
  165.         --leave breaks so that the program yields and to allow stopping by right-click
  166.         if sequential and i == step then
  167.             i = 0
  168.             os.startTimer(0.1)
  169.             local e = os.pullEvent()
  170.             if e == 'monitor_touch' then return true end
  171.         end
  172.     end
  173. end
  174.  
  175.  
  176. --The part of the program that runs it if not used as an API
  177. local tArgs = {...}
  178. local side = tArgs[1] or "top"
  179. if tArgs[2] == 'false' then sequential = false end
  180. if tArgs[3] ~= nil then step = tonumber(tArgs[3]) end
  181.  
  182. while true do
  183.     play(side, sequential, step)
  184.     os.pullEvent('monitor_touch')
  185. end
Advertisement
Add Comment
Please, Sign In to add comment