Advertisement
Guest User

Untitled

a guest
Aug 21st, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.97 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. import re
  4. import sys
  5. import argparse
  6.  
  7. def fail(msg):
  8. sys.stderr.write(sys.argv[0] + ": " + msg + "\n")
  9. sys.exit(1)
  10.  
  11. parser = argparse.ArgumentParser(description="Generate LLS input grid for finding spaceships and oscillators.")
  12. parser.add_argument('width', type=int, help="width of pattern bounding box")
  13. parser.add_argument('height', type=int, help="height of pattern bounding box")
  14. parser.add_argument('-f', '--first-gen', type=int, nargs=2, help="width and height of first generation")
  15. parser.add_argument('-p', '--period', type=int, default=2, help="period until first generation reappears")
  16. parser.add_argument('-x', '--shift-x', type=int, default=0, help="horizontal shift over period")
  17. parser.add_argument('-y', '--shift-y', type=int, default=0, help="vertical shift over period")
  18. parser.add_argument('-m', '--mirror', choices=("", "none", "x", "y", "d", "diag", "a", "antidiag", "9", "90", "1", "180", "2", "270"), help="mirror or rotate pattern after period")
  19. parser.add_argument('--fixed', nargs='+', default=[], help="fixed cell values in initial pattern (e.g. \"a1=1 a2=b1=b2=0\"")
  20. parser.add_argument('--wide', action='store_true', help="allow intermediate generations to use the whole (width+x)*(height+y) cell area")
  21. parser.add_argument('--strobe', action='store_true', help="use a strobing background for B0 rules")
  22. parser.add_argument('--partial-x', action='store_true', help="search for a partial travelling in -ve x-direction, use with --fixed \"aY=1\" for 0<Y<height")
  23. args = parser.parse_args()
  24.  
  25. # validate pattern dimensions
  26. if args.period < 1:
  27. fail("Period must be positive.")
  28. if args.strobe and args.period % 2:
  29. fail("Period must be even for strobing rules.")
  30. if args.width < 1 or args.height < 1:
  31. fail("Width and height must be at least 1.")
  32.  
  33. if args.partial_x:
  34. if args.shift_x > 0:
  35. fail("Horizantal shift must be <= 0 to use partial_x")
  36. if args.fixed is None:
  37. fail("Must set an On cell in the front row when searching for partials (e.g. --fixed \"a4=1\")")
  38.  
  39. if args.first_gen is None:
  40. gen0_width = args.width
  41. gen0_height = args.height
  42. else:
  43. gen0_width, gen0_height = args.first_gen
  44. if gen0_width < 1 or gen0_height < 1:
  45. fail("First generation width and height must be at least 1.")
  46. if gen0_width > args.width or gen0_height > args.height:
  47. fail("First generation width and height may not be greater than for later generations.")
  48.  
  49. total_width = args.width + 4 + abs(args.shift_x)
  50. total_height = args.height + 4 + abs(args.shift_y)
  51.  
  52. # glide / rotate symmetry handling
  53. mirror_x = args.mirror in ("x", "a", "antidiag", "9", "90", "1", "180")
  54. mirror_y = args.mirror in ("y", "a", "antidiag", "1", "180", "2", "270")
  55. transpose = args.mirror in ("d", "diag", "a", "antidiag", "9", "90", "2", "270")
  56.  
  57. if transpose and gen0_width != gen0_height:
  58. fail("Only square grids are supported for --mirror=%s." % args.mirror)
  59.  
  60. # build dictionary of fixed cells
  61. fixed = {}
  62. for eqn in args.fixed:
  63. eqn = eqn.strip()
  64. if eqn == "": continue
  65. terms = eqn.split("=")
  66. if len(terms) < 2:
  67. fail("Invalid equation \"%s\" in --fixed=\"%s\"." % (eqn, args.fixed))
  68. val = terms.pop().strip()
  69. if val != "0" and val != "1":
  70. fail("Invalid constant \"%s\" in equation \"%s\"." % (val, eqn))
  71. for term in terms:
  72. term = term.strip()
  73. if not re.match(r'^[a-z]+[1-9][0-9]*$', term):
  74. fail("Invalid term \"%s\" in equation \"%s\"." % (term, eqn))
  75. if term in fixed and fixed[term] != val:
  76. fail("Inconsistent assignment for \"%s\" in --fixed=\"%s\"." % (term, args.fixed))
  77. fixed[term] = val
  78.  
  79. # helper function for generating cell symbol names
  80. def cellname(row, col):
  81. name = ""
  82. while col >= 0:
  83. col, letter = divmod(col, 26)
  84. name = chr(ord('a') + letter) + name
  85. col -= 1
  86. return name + str(row+1)
  87.  
  88. maxlen = max(2, len(cellname(args.width-1, args.height-1)))
  89. cellfmt = "%%-%ss" % maxlen
  90.  
  91. for gen in range(args.period + 1):
  92. # initialize grid to all empty cells
  93. void = str(gen % 2) if args.strobe else "0"
  94. grid = [[void] * total_width for i in range(total_height)]
  95. # set fixed borders
  96. for row in range(total_height):
  97. grid[row][0] = grid[row][total_width-1] = void + "'"
  98. for col in range(1, total_width-1):
  99. grid[0][col] = grid[total_height-1][col] = void + "'"
  100. # draw in the search area
  101. if gen in (0, args.period):
  102. dy = 2 + (args.height - gen0_height) // 2 + max(0, args.shift_y if gen else -args.shift_y)
  103. dx = 2 + (args.width - gen0_width) // 2 + max(0, args.shift_x if gen else -args.shift_x)
  104. for y in range(gen0_height):
  105. for x in range(gen0_width):
  106. row = y
  107. col = x
  108. if gen and mirror_y: row = gen0_height - row - 1
  109. if gen and mirror_x: col = gen0_width - col - 1
  110. if gen and transpose: row, col = col, row
  111. name = cellname(row, col)
  112. grid[y + dy][x + dx] = fixed[name] if name in fixed else name
  113. if args.partial_x:
  114. for x in range(x + dx + 1, total_width):
  115. grid[y + dy][x] = "*'"
  116. else:
  117. if args.wide:
  118. top = left = 2
  119. bottom = total_height - 2
  120. right = total_width - 2
  121. else:
  122. dy = int(round(args.shift_y * gen * 1.0 / args.period))
  123. top = 2 + (dy if args.shift_y >= 0 else dy - args.shift_y)
  124. dx = int(round(args.shift_x * gen * 1.0 / args.period))
  125. left = 2 + (dx if args.shift_x >= 0 else dx - args.shift_x)
  126. bottom = top + args.height
  127. right = left + args.width
  128. for row in range(top, bottom):
  129. for col in range(left, right):
  130. grid[row][col] = '*'
  131. if args.partial_x:
  132. for col in range(right, total_width):
  133. grid[row][col] = "*'"
  134. # print output
  135. if gen > 0:
  136. print("")
  137. for line in grid:
  138. print(" ".join(cellfmt % cell for cell in line))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement