osmarks

Untitled

Aug 16th, 2018
503
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.45 KB | None | 0 0
  1. --local print_on_paper = require "print"
  2.  
  3. local function deepcopy(o, seen)
  4. seen = seen or {}
  5. if o == nil then return nil end
  6. if seen[o] then return seen[o] end
  7.  
  8. local no
  9. if type(o) == 'table' then
  10. no = {}
  11. seen[o] = no
  12.  
  13. for k, v in next, o, nil do
  14. no[deepcopy(k, seen)] = deepcopy(v, seen)
  15. end
  16. setmetatable(no, deepcopy(getmetatable(o), seen))
  17. else -- number, string, boolean, etc
  18. no = o
  19. end
  20. return no
  21. end
  22.  
  23. local env = deepcopy(_G)
  24.  
  25. local function run(code)
  26. local f = load(code, "@stuff", "t", env)
  27. if not f then return nil end
  28. return pcall(f)
  29. end
  30.  
  31. local function fitness(code)
  32. local start_time = os.clock()
  33. local ok, result = run(code)
  34. local end_time = os.clock()
  35.  
  36. local fitness = 1
  37. fitness = fitness + ((end_time - start_time) * 10)
  38. if result then fitness = fitness + math.max(#result, 8) end
  39. if ok == nil then fitness = 0 end
  40. if ok == true then fitness = fitness * 5 end
  41. if ok == false then fitness = fitness * 0.1 end
  42. return fitness
  43. end
  44.  
  45. local function random_char()
  46. return string.char(math.random(32, 126))
  47. end
  48.  
  49. local function pick_random(l)
  50. return l[math.random(1, #l)]
  51. end
  52.  
  53. local function partition(str, at)
  54. return str:sub(1, at - 1), str:sub(at, at), str:sub(at + 1)
  55. end
  56.  
  57. local function partition_random(str)
  58. return partition(str, math.random(1, #str))
  59. end
  60.  
  61. local mutations = {
  62. function(code) -- add char
  63. local start, c, end_ = partition_random(code)
  64. return start .. random_char() .. c .. end_
  65. end,
  66. function(code) -- delete char
  67. local start, c, end_ = partition_random(code)
  68. return start .. end_
  69. end,
  70. function(code) -- change char
  71. local start, c, end_ = partition_random(code)
  72. return start .. random_char() .. end_
  73. end
  74. }
  75.  
  76. local function mutate(code)
  77. for i = 1, math.random(0, 3) do
  78. code = pick_random(mutations)(code)
  79. end
  80. if code:sub(1, 1) == "#" then -- get around weird Cobalt behavior
  81. code = code:sub(2)
  82. end
  83. return code
  84. end
  85.  
  86. local function weighted_random_by(list, get_weight)
  87. local total_weight = 0
  88. _.map(list, function(i)
  89. total_weight = total_weight + get_weight(i)
  90. end)
  91.  
  92. local rand = math.random() * total_weight
  93.  
  94. for k, v in pairs(list) do
  95. local weight = get_weight(v)
  96. if rand < weight then
  97. return v
  98. else
  99. rand = rand - weight
  100. end
  101. end
  102.  
  103. assert(false, "Should not be reached")
  104. end
  105.  
  106. local function combine(cf_pairs)
  107. local out = ""
  108. local len = _(cf_pairs):map(function(cf) return #cf.code end):reduce(math.max, -math.huge)
  109. for i = 1, len do
  110. local char = weighted_random_by(
  111. _(cf_pairs):map(function(cf) return { c = string.sub(cf.code, i, i), f = cf.fitness } end),
  112. function(cf) return cf.f end
  113. ).c
  114. out = out .. char
  115. end
  116. return out
  117. end
  118.  
  119. local function run_gen(g)
  120. local code_and_fitnesses = _.map(g, function(code)
  121. return { code = code, fitness = fitness(code) }
  122. end)
  123. sleep(0.1)
  124.  
  125. print(textutils.serialise(code_and_fitnesses))
  126.  
  127. local num_descendants = math.max(math.min(4, math.random(-2, 2) + #g), 16)
  128. local descendants = {}
  129. for i = 1, num_descendants do
  130. local cf_pairs = {}
  131. for i = 1, math.random(1, 3) do
  132. table.insert(cf_pairs, weighted_random_by(code_and_fitnesses, function(cf) return cf.fitness end))
  133. end
  134. descendants[i] = mutate(combine(cf_pairs))
  135. end
  136.  
  137. return descendants
  138. end
  139.  
  140. local programs = {"print 'hello, world'"}
  141. while true do
  142. programs = run_gen(programs)
  143. sleep()
  144. end
Add Comment
Please, Sign In to add comment