Guest User

Untitled

a guest
Jul 18th, 2015
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.38 KB | None | 0 0
  1. import math
  2. from random import randint, choice as rand_choice, random
  3.  
  4. CELL_SIZE = 5
  5. WORLD_SIZE = 160
  6.  
  7. DIRECTS = {
  8.     0: (0, -1),
  9.     1: (1, 0),
  10.     2: (0, 1),
  11.     3: (-1, 0),
  12. }
  13.  
  14. COMMANDS = 'b↑→↓←FEWs'
  15. MUTATE_PROB = 0.003
  16.  
  17. ACT_GO, ACT_BITE, ACT_BREED, ACT_SHIELD = range(4)
  18.  
  19.  
  20. def mutate_code(code):
  21.     v = randint(0, 2 if len(code) > 0 else 0)
  22.     pos = randint(0, len(code))
  23.     if v == 0:
  24.         # insert symbol
  25.         return code[:pos] + rand_choice(COMMANDS) + code[pos:]
  26.     elif v == 1:
  27.         # replace symbol
  28.         return code[:pos] + rand_choice(COMMANDS) + code[pos+1:]
  29.     else:
  30.         # remove symbol
  31.         return code[:pos] + code[pos+1:]
  32.  
  33.  
  34. def levenstein_distance(a, b):
  35.     M, N = len(a), len(b)
  36.     dmat = {}
  37.  
  38.     def compute_d(i, j):
  39.         if i == 0 and j == 0:
  40.             return 0
  41.         if j == 0:
  42.             return i
  43.         if i == 0:
  44.             return j
  45.         return min(
  46.             dmat[(i, j - 1)] + 1,
  47.             dmat[(i - 1, j)] + 1,
  48.             dmat[(i - 1, j - 1)] + (0 if a[i - 1] == b[j - 1] else 1)
  49.         )
  50.  
  51.     for i in range(len(a) + 1):
  52.         for j in range(len(b) + 1):
  53.             dmat[(i, j)] = compute_d(i, j)
  54.  
  55.     return dmat[(M, N)]
  56.  
  57.  
  58. def force_range(v, _min, _max):
  59.     if v < _min:
  60.         v = _min
  61.     elif v > _max:
  62.         v = _max
  63.     return v
  64.  
  65.  
  66. def code_color(code):
  67.     r, g, b = 0, 0, 0
  68.     lcmd = len(COMMANDS)
  69.     for char in code:
  70.         val = COMMANDS.index(char) / lcmd
  71.         r += min(abs(0.000 - val), abs(1.000 - val))
  72.         g += min(abs(0.333 - val), abs(1.333 - val))
  73.         b += min(abs(0.667 - val), abs(-0.333 - val))
  74.     mx = max(r, g, b)
  75.     if mx < 0.1:
  76.         mx = 0.1
  77.     return (
  78.         force_range(r / mx * 0.6, 0.0, 1.0),
  79.         force_range(g / mx * 0.6, 0.0, 1.0),
  80.         force_range(b / mx * 0.6, 0.0, 1.0),
  81.     )
  82.  
  83.  
  84. class LifeForm:
  85.     def __init__(self, world, code, x, y):
  86.         self.world = world
  87.         self.x = x % WORLD_SIZE
  88.         self.y = y % WORLD_SIZE
  89.         self.age = 0
  90.         self.age_vel = 1.0
  91.         self.hp = 10
  92.         # 0 - up, 1 - right, 2 - down, 3 - left
  93.         self.direct = 0
  94.  
  95.         self.code = code
  96.         self.color = code_color(code)
  97.         self.len = len(code)
  98.         self.codeptr = 0
  99.         self.cond = None
  100.  
  101.         self.lastact = None
  102.  
  103.     def age_tick(self):
  104.         self.age += 1
  105.         if self.age_vel > -0.1:
  106.             self.age_vel -= 0.003
  107.         self.hp += self.age_vel
  108.  
  109.     def brain_tick(self):
  110.         if self.age % 50 == 0 and self.hp >= 100:
  111.             if self.world.try_to_breed(self):
  112.                 self.lastact = ACT_BREED
  113.                 return
  114.  
  115.         char = self.code[self.codeptr]
  116.         if self.cond is None:
  117.             if char in 'FEW':
  118.                 self.cond = False  # enter condition mode
  119.         else:
  120.             if char not in 'FEW':
  121.                 if not self.cond:
  122.                     char = None  # skip command since condition is false
  123.                 self.cond = None  # exit condition mode
  124.             else:
  125.                 if self.cond:
  126.                     char = None  # skip unneccessary condition checks
  127.  
  128.         if char == '↑':
  129.             if self.world.try_to_go(self):
  130.                 self.lastact = ACT_GO
  131.         elif char == '→':
  132.             self.direct = (self.direct + 1) % 4
  133.         elif char == '↓':
  134.             if self.world.try_to_go(self, True):
  135.                 self.lastact = ACT_GO
  136.         elif char == '←':
  137.             self.direct = (self.direct - 1) % 4
  138.         elif char == 'b':
  139.             self.lastact = ACT_BITE
  140.         elif char == 's':
  141.             self.lastact = ACT_SHIELD
  142.         elif char == 'F':
  143.             if self.world.is_friend(self):
  144.                 self.cond = True
  145.         elif char == 'E':
  146.             if self.world.is_enemy(self):
  147.                 self.cond = True
  148.         elif char == 'W':
  149.             if self.world.is_wall(self):
  150.                 self.cond = True
  151.  
  152.         self.codeptr = (self.codeptr + 1) % self.len
  153.  
  154.  
  155. class World:
  156.     def __init__(self):
  157.         self.lifeforms = []
  158.         self.worldmap = {(x, y): None for x in range(WORLD_SIZE) for y in range(WORLD_SIZE)}
  159.         self.frame = 0
  160.         self.levenstein_cache = {}
  161.  
  162.     def get_lev(self, a, b):
  163.         median_len = (len(a) + len(b)) / 2
  164.         if median_len < 1:
  165.             median_len = 1
  166.         k = '{}|{}'.format(a, b) if a > b else '{}|{}'.format(b, a)
  167.         dist = self.levenstein_cache.get(k, None)
  168.         if dist is None:
  169.             dist = (levenstein_distance(a, b), self.frame)
  170.             self.levenstein_cache[k] = dist
  171.         elif dist[1] != self.frame:
  172.             self.levenstein_cache[k] = (dist[0], self.frame)
  173.         return dist[0] / median_len
  174.  
  175.     def cleanup_lev(self):
  176.         removelist = []
  177.         for k, v in self.levenstein_cache.items():
  178.             if self.frame - v[1] >= 100:
  179.                 removelist.append(k)
  180.         for k in removelist:
  181.             del self.levenstein_cache[k]
  182.  
  183.     def someone_in_front(self, form):
  184.         dx, dy = DIRECTS[form.direct]
  185.         rx = form.x + dx
  186.         ry = form.y + dy
  187.         if (rx, ry) not in self.worldmap:
  188.             return True  # Wall
  189.         return self.worldmap[(rx, ry)]
  190.  
  191.     def is_friend(self, form):
  192.         t = self.someone_in_front(form)
  193.         if isinstance(t, LifeForm):
  194.             return self.get_lev(t.code, form.code) < 0.3
  195.         return False
  196.  
  197.     def is_enemy(self, form):
  198.         t = self.someone_in_front(form)
  199.         if isinstance(t, LifeForm):
  200.             return self.get_lev(t.code, form.code) >= 0.3
  201.         return False
  202.  
  203.     def is_wall(self, form):
  204.         t = self.someone_in_front(form)
  205.         return t is False
  206.  
  207.     def try_to_go(self, form, back=False):
  208.         dx, dy = DIRECTS[form.direct]
  209.         if back:
  210.             dx = -dx
  211.             dy = -dy
  212.         rx = force_range(form.x + dx, 0, WORLD_SIZE - 1)
  213.         ry = force_range(form.y + dy, 0, WORLD_SIZE - 1)
  214.         if self.worldmap[(rx, ry)] is None:
  215.             self.worldmap[(form.x, form.y)] = None
  216.             form.x = rx
  217.             form.y = ry
  218.             self.worldmap[(rx, ry)] = form
  219.             return True
  220.         return False
  221.  
  222.     def try_to_breed(self, form):
  223.         dx, dy = DIRECTS[form.direct]
  224.         rx = force_range(form.x - dx, 0, WORLD_SIZE - 1)
  225.         ry = force_range(form.y - dy, 0, WORLD_SIZE - 1)
  226.         if self.worldmap[(rx, ry)] is None:
  227.             new_code = form.code
  228.             for i in range(len(form.code)):
  229.                 if random() < MUTATE_PROB:
  230.                     new_code = mutate_code(new_code)
  231.             form.hp -= 50
  232.             child = LifeForm(self, new_code, rx, ry)
  233.             self.worldmap[(rx, ry)] = child
  234.             self.lifeforms.append(child)
  235.             return True
  236.         return False
  237.  
  238.     def check_bites(self):
  239.         for form in self.lifeforms:
  240.             if form.hp <= 0:
  241.                 continue
  242.             if form.lastact != ACT_BITE:
  243.                 continue
  244.             dx, dy = DIRECTS[form.direct]
  245.             rx = form.x + dx
  246.             ry = form.y + dy
  247.             target = self.worldmap.get((rx, ry), None)
  248.             if target is None:
  249.                 continue
  250.             if target.lastact == ACT_SHIELD and (target.direct + 2) % 4 == form.direct:
  251.                 continue
  252.             val = force_range(50, 0, max(0, target.hp))
  253.             target.hp -= val
  254.             form.hp += val // 2
  255.  
  256.     def check_deaths(self):
  257.         for i in range(len(self.lifeforms) - 1, -1, -1):
  258.             form = self.lifeforms[i]
  259.             if form.hp <= 0:
  260.                 self.worldmap[(form.x, form.y)] = None
  261.                 self.lifeforms.pop(i)
  262.  
  263.     def tick(self):
  264.         for form in self.lifeforms:
  265.             form.lastact = None
  266.             form.age_tick()
  267.             for i in range(10):
  268.                 form.brain_tick()
  269.                 if form.lastact is not None:
  270.                     break
  271.         self.check_bites()
  272.         self.check_deaths()
  273.         if self.frame % 100 == 0:
  274.             self.cleanup_lev()
  275.         self.frame += 1
  276.  
  277.     def create_random_form(self):
  278.         code = ''
  279.         for i in range(randint(4, 15)):
  280.             code += rand_choice(COMMANDS)
  281.         tries = 5
  282.         while tries > 0:
  283.             x = randint(0, WORLD_SIZE - 1)
  284.             y = randint(0, WORLD_SIZE - 1)
  285.             if self.worldmap[(x, y)] is None:
  286.                 form = LifeForm(self, code, x, y)
  287.                 self.lifeforms.append(form)
  288.                 self.worldmap[(x, y)] = form
  289.                 break
  290.             tries -= 1
  291.  
  292.  
  293. def start_gtk():
  294.     from gi.repository import Gtk, GObject
  295.     import cairo
  296.  
  297.     world = World()
  298.     for i in range(10):
  299.         world.create_random_form()
  300.  
  301.     def OnDraw(w, cr):
  302.         cr.set_line_width(1)
  303.         for form in world.lifeforms:
  304.             cr.rectangle(
  305.                 CELL_SIZE * form.x,
  306.                 CELL_SIZE * form.y,
  307.                 CELL_SIZE,
  308.                 CELL_SIZE,
  309.             )
  310.             cr.set_source_rgb(*form.color)
  311.             cr.fill()
  312.             if False and form.lastact is not None and form.lastact != ACT_GO:
  313.                 direct = form.direct
  314.                 if form.lastact == ACT_BREED:
  315.                     direct = (direct + 2) % 4
  316.                 if direct == 0:
  317.                     cr.move_to(CELL_SIZE * form.x, CELL_SIZE * form.y + 1)
  318.                     cr.rel_line_to(CELL_SIZE, 0)
  319.                 elif direct == 1:
  320.                     cr.move_to(CELL_SIZE * form.x + CELL_SIZE - 1, CELL_SIZE * form.y)
  321.                     cr.rel_line_to(0, CELL_SIZE)
  322.                 elif direct == 2:
  323.                     cr.move_to(CELL_SIZE * form.x, CELL_SIZE * form.y + CELL_SIZE - 1)
  324.                     cr.rel_line_to(CELL_SIZE, 0)
  325.                 elif direct == 3:
  326.                     cr.move_to(CELL_SIZE * form.x + 1, CELL_SIZE * form.y)
  327.                     cr.rel_line_to(0, CELL_SIZE)
  328.                 if form.lastact == ACT_BITE:
  329.                     cr.set_source_rgb(1, 0, 0)
  330.                 elif form.lastact == ACT_BREED:
  331.                     cr.set_source_rgb(0, 1, 0)
  332.                 elif form.lastact == ACT_SHIELD:
  333.                     cr.set_source_rgb(0, 0, 1)
  334.                 cr.stroke()
  335.  
  336.     def on_timeout(x):
  337.         world.tick()
  338.         if world.frame % 100 == 0:
  339.             ml = ''
  340.             codemap = {}
  341.             for form in world.lifeforms:
  342.                 if len(form.code) > len(ml):
  343.                     ml = form.code
  344.                 codemap[form.code] = codemap.get(form.code, 0) + 1
  345.             pc = 1
  346.             best = []
  347.             for k, v in reversed(sorted(codemap.items(), key=lambda x: x[1])):
  348.                 best.append('{}: {} ({})'.format(pc, k, v))
  349.                 pc += 1
  350.                 if pc > 3:
  351.                     break
  352.             print('Best: {} ::: Longest: {} ::: lev {}'.format(' ::: '.join(best), ml, len(world.levenstein_cache)))
  353.         a.queue_draw_area(0, 0, WORLD_SIZE * CELL_SIZE, WORLD_SIZE * CELL_SIZE)
  354.         GObject.timeout_add(10, on_timeout, None)
  355.  
  356.     w = Gtk.Window()
  357.     w.set_default_size(WORLD_SIZE * CELL_SIZE, WORLD_SIZE * CELL_SIZE)
  358.     a = Gtk.DrawingArea()
  359.     w.add(a)
  360.     w.connect('destroy', Gtk.main_quit)
  361.     a.connect('draw', OnDraw)
  362.     w.show_all()
  363.  
  364.     on_timeout(None)
  365.     Gtk.main()
  366.  
  367.  
  368. if __name__ == '__main__':
  369.     start_gtk()
Advertisement
Add Comment
Please, Sign In to add comment