Guest User

flora.py r2

a guest
Jul 1st, 2012
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.89 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. # This file is called flora.py and the release is 2
  4. # Wolf Mathwig wrote this stuff and uploaded it to the internet on 2012-07-02
  5. # It is a submission for the first NeoGAF Weekly Recreational Programming Challenge
  6. #
  7. # It was a Monday. Windows prompted a change.
  8. #
  9. # This is is a script developed for Python 2.6.7 on Mac OS X
  10. # It needs a terminal that supports UTF-8 and ANSI terminal colors
  11. #
  12. # The output only looks perfect if the font you're using includes block characters,
  13. # and has perfect spacing (this is not necessarily the case for arbitrary reasons)
  14. #
  15. # Optimal font properties:
  16. #                         Menlo Regular 14 pt.
  17. #                         Distance between letters: 1
  18. #                         Distance between rows:    0.81
  19. #
  20. # If something breaks, hit me: [email protected]
  21.  
  22. import random, sys, os, time
  23.  
  24. random.seed()
  25.  
  26. height, width = 0,0
  27.  
  28. bad_start = 0
  29.  
  30. try:
  31.     height, width = os.popen('stty size', 'r').read().split()
  32.     height  = int(height)
  33.     width   = int(width)
  34. except:
  35.     try:
  36.         from ctypes import windll, create_string_buffer
  37.    
  38.         # stdin handle is -10
  39.         # stdout handle is -11
  40.         # stderr handle is -12
  41.    
  42.         h = windll.kernel32.GetStdHandle(-12)
  43.         csbi = create_string_buffer(22)
  44.         res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
  45.    
  46.         if res:
  47.             import struct
  48.             (bufx, bufy, curx, cury, wattr,
  49.              left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
  50.             width = right - left + 1
  51.             height = bottom - top + 1
  52.         else:
  53.             width, height = 80, 25 # can't determine actual size - return default values
  54.     except:
  55.         print "I cannot determine your console size. Please provide your console dimensions in characters."
  56.         try:
  57.             width = int(raw_input('Width: '))
  58.             height = int(raw_input('Height: '))
  59.         except:
  60.             bad_start = 1
  61.             print "You provided input I cannot work with. I will use 20x20"
  62.             width = 20
  63.             height = 20
  64. if not bad_start:
  65.     print "Console dimensions: "+str(width)+"x"+str(height)
  66. if int(height)<15:
  67.   print "Console height is 15 characters minimum. Sorry."
  68.   sys.exit()
  69.  
  70. if bad_start:
  71.   print "I will continue working in 5 seconds."
  72.   time.sleep(5)
  73.  
  74. canvas =  {'dx': ((width-1)/2*2)*2, 'dy': ((height-3)/2*2)*2, 'pic':[]}
  75. color = {'dx':canvas['dx']/2, 'dy':canvas['dy']/2, 'pic':[]}
  76.  
  77. sleep_time = 0.05
  78.  
  79. global_counter = 0
  80. runs = 0
  81.  
  82. max_y = canvas['dy']-2
  83. if max_y<0:
  84.   max_y = 2
  85.  
  86. raster = {  "0000":" ",
  87.             "0001":"▗",
  88.             "0010":"▖",
  89.             "0011":"▄",
  90.             "0100":"▝",
  91.             "0101":"▐",
  92.             "0110":"▞",
  93.             "0111":"▟",
  94.             "1000":"▘",
  95.             "1001":"▚",
  96.             "1010":"▌",
  97.             "1011":"▙",
  98.             "1100":"▀",
  99.             "1101":"▜",
  100.             "1110":"▛",
  101.             "1111":"█",
  102.             }
  103.  
  104. # Raster ANSI escape colours
  105. bl = '\033[30m'
  106. blu = '\033[44m'
  107. b1 = '\033[31m'
  108. b2 = '\033[91m'
  109. g1 = '\033[32m'
  110. g2 = '\033[92m'
  111. p1 = '\033[35m'
  112. p2 = '\033[95m'
  113.  
  114. # Nulling the canvas data structure
  115. for y in range(0, canvas['dy']):
  116.   canvas['pic'].append([])
  117.   for x in range(0, canvas['dx']):
  118.     pp = 0
  119.     # Frame with random pixels (UNUSED because scrolling makes it look weird)
  120.     #if x == 0 or x == canvas['dx']-1 or y == 0 or y == canvas['dy']-1:
  121.     #  pp = random.randint(0,1)
  122.     canvas['pic'][y].append(pp)
  123.  
  124. # Nulling color to blue background
  125. for y in range(0, color['dy']):
  126.   color['pic'].append([])
  127.   for x in range(0, color['dx']):
  128.     color['pic'][y].append(blu)
  129.  
  130. # Hint: We grow downwards, display flipped
  131.  
  132. # Decode data structure and display it
  133. def pic_decode():
  134.   global global_counter, runs
  135.   i = 0
  136.   p = 0
  137.   c = 0
  138.   outp = ""
  139.  
  140.   # Scrolling driver
  141.   init_i = global_counter%color['dx']
  142.  
  143.   trans = []
  144.  
  145.   while p < len(canvas['pic']):
  146.     trans.append([])
  147.     i = 0
  148.     while i < len(canvas['pic'][p]):
  149.       trans[p/2].append(str(canvas['pic'][p][i])+str(canvas['pic'][p][i+1])+\
  150.                         str(canvas['pic'][p+1][i])+str(canvas['pic'][p+1][i+1]))
  151.       i += 2
  152.     p += 2
  153.  
  154.   if os.name == "posix":
  155.     # Unix/Linux/MacOS/BSD/etc
  156.     os.system('clear')
  157.     #print "cls"
  158.   elif os.name in ("nt", "dos", "ce"):
  159.     # DOS/Windows
  160.     os.system('CLS')
  161.    
  162.   # Fill and output data and color
  163.   for f1 in range(0, len(trans)):
  164.     print outp
  165.     outp = ""
  166.     i = init_i
  167.  
  168.     # Scroll: Left portion is what's right of i
  169.     for f2 in range(i, len(trans[f1])):
  170.       outp += color['pic'][f1][f2] + raster[trans[f1][f2]]
  171.     # Scroll: Right portion is what's left of i
  172.     for f2 in range(0, init_i):
  173.       outp += color['pic'][f1][f2] + raster[trans[f1][f2]]
  174.  
  175.   # Stats barf
  176.   print "\033[0mSTEP "+ '_'*(6-len(str(global_counter))) +str(global_counter)+\
  177.         "   RUNS "+str(runs)
  178.  
  179.   global_counter += 1
  180.   time.sleep(sleep_time)
  181.  
  182. # UNUSED -- Randomized pixels
  183. def randomized(runs):
  184.   for i in range(0,runs):
  185.     for y in range(0, canvas['dy']):
  186.       for x in range(0, canvas['dx']):
  187.         canvas['pic'][y][x] = random.randint(0,1)
  188.     pic_decode()
  189.  
  190. # Determine slope and y at x=0
  191. def linfunc(start,end):
  192.   x = end['x'] - start['x']
  193.   y = end['y'] - start['y']
  194.   slope = 0
  195.   b = 0
  196.   try:
  197.     slope = y / x
  198.     b = start['y']-slope*start['x']
  199.   except:
  200.     # Division by zero
  201.     slope = 0
  202.     b = 0
  203.   return {'slope':slope, 'b':b}
  204.  
  205. # Draw a line
  206. # col is a toggle between grass and tree
  207. # hint is for determining which line in a wider segment is drawn
  208. def line(start, end, col, hint=0):
  209.   global max_y, runs
  210.   slope = linfunc(start, end)
  211.   b = slope['b']
  212.   slope = slope['slope']
  213.   x = start['x']
  214.   y = start['y']
  215.   if not slope:
  216.     return start
  217.   for j in range(start['y'], end['y']):
  218.     if j > (max_y-random.randint(0, 15)):
  219.       #print "exceed"
  220.       break
  221.     try:
  222.       old_x = x
  223.       old_y = y
  224.       x = (j-b)/slope
  225.       y = j-1
  226.       try:
  227.         canvas['pic'][len(canvas['pic'])-y][x] = 1
  228.         if col:
  229.           if (end['y']-y) >2:
  230.             c_pick = g1
  231.           else:
  232.             c_pick = g2
  233.         else:
  234.           if not random.randint(0, 30):
  235.             if random.randint(0,1):
  236.               c_pick = p2
  237.             else:
  238.               c_pick = p1
  239.           else:
  240.             if not hint:
  241.               c_pick = b1
  242.             if hint==1:
  243.               c_pick = b2
  244.             if hint==-1:
  245.               c_pick = bl
  246.         color['pic'][(len(canvas['pic'])-y)/2][x/2] = c_pick
  247.       except:
  248.         #print str(x)+"."+str(y)+": out of array"
  249.         x = old_x
  250.         y = old_y
  251.         break
  252.     except:
  253.       #print "div by 0"
  254.       break
  255.     if random.randint(0,runs)==0:
  256.       pic_decode()
  257.  
  258.   # We return the last-drawn position so that segments can continue there
  259.   return {'x':x, 'y':y}
  260.  
  261. # Draw a number of grass leaves with a height range
  262. def grass(stems, height):
  263.   for i in range(0, stems):
  264.     c_height = random.randint(height['min'], height['max'])
  265.     x = random.randint(0, canvas['dx']-2)
  266.     if x > ((height['min']+ height['max']) / 2) and random.randint(0, 5) > 1:
  267.       c_height = random.randint(height['min'],\
  268.                                 height['min'] + (height['min']+ height['max']) / 2)
  269.     target = random.randint(-c_height, c_height)
  270.     line({'x':x, 'y':2}, {'x':x+target, 'y':c_height}, 1)
  271.  
  272. # Draw a flower stem segment
  273. def flowerstem_segment(start, end, thickness, overdraw):
  274.   result = {'x':start['x'], 'y':start['y']}
  275.   slope = linfunc(start, end)
  276.   x = start['x']
  277.   for t in range(0, thickness):
  278.     factor = -1
  279.     c_t = t
  280.     result = line(
  281.                 {'x':start['x'], 'y':start['y']},
  282.                 {'x':end['x'], 'y':end['y']}, 0,1)
  283.     while c_t > 0:
  284.       factor *= -1
  285.       line(
  286.                 {'x':start['x'] +c_t*factor, 'y':start['y']},
  287.                 {'x':end['x']   +c_t*factor, 'y':end['y']}, 0)
  288.       c_t -= 1
  289.     result['y'] += 1
  290.     if not t:
  291.       continue
  292.     line({'x':start['x']+t, 'y':start['y']}, {'x':end['x']+t, 'y':end['y']}, 0)
  293.     # SHADOW
  294.     line({'x':start['x']+t+1, 'y':start['y']}, {'x':end['x']+t+1, 'y':end['y']}, 0, -1)
  295.   return result
  296.  
  297. # Draw a flower stem, which itself consists of flower stem segments
  298. # variance determines height and width variance for segments
  299. # overdraw is unused
  300. def flowerstem(variance, thickness, overdraw, height, segments, pos={'x':-1,'y':-1}):
  301.   if not segments:
  302.     segments = random.randint(3, 15)
  303.   s = 0
  304.   if pos['x']==-1:
  305.     pos = {'x':random.randint(thickness, canvas['dx']-thickness), 'y':0}
  306.   while pos['y']<height and s < segments:
  307.     grass(random.randint(0,1), {'min':2, 'max':canvas['dy']/random.randint(8,12)})
  308.     c_variance_x = random.randint(0, variance)
  309.     c_variance_y = random.randint(1, (int(variance*0.6)%12)+2)
  310.     end = { 'x':random.randint(pos['x']-c_variance_x/2, pos['x']+c_variance_x),
  311.             'y':random.randint(pos['y']+1, pos['y']+c_variance_y)}
  312.     pos = flowerstem_segment(pos, end, thickness, overdraw)
  313.     if thickness > 1 and not random.randint(0,1):
  314.       c_thickness = thickness - 1
  315.       flowerstem(variance*2, c_thickness, overdraw, height, s, {'x':pos['x'],'y':pos['y']})
  316.     s += 1
  317.  
  318. # Draw a bunch of flowers
  319. def flowers(stems):
  320.   global max_y
  321.   for i in range(0, stems):
  322.     flowerstem( random.randint(3, 8),       # variance
  323.                 random.randint(2, 6),       # thickness
  324.                 random.randint(0, 1),       # overdraw
  325.                 random.randint(10, max_y),  # height
  326.                 random.randint(0, 10))      # segments
  327.  
  328. # How many times do we repeat the basic thing?
  329. runs = random.randint(3, 100)
  330. while runs > 0:
  331.   try:
  332.     if random.randint(0,2):
  333.       grass(random.randint(10,35), {'min':2, 'max':canvas['dy']/random.randint(4,9)})
  334.     if random.randint(0,1):
  335.       flowers(random.randint(1,2))
  336.   except KeyboardInterrupt:
  337.     runs = 0
  338.   runs -= 1
  339.  
  340. pic_decode()
  341.  
  342. # We have to reset the terminal color
  343. print "\033[0m"
Advertisement
Add Comment
Please, Sign In to add comment