|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import ast
|
|
|
|
import random as r
|
|
|
|
from blup import frame
|
|
|
|
from blup import animation
|
|
|
|
import blup.writebml
|
|
|
|
import argparse
|
|
|
|
import math
|
|
|
|
|
|
|
|
r.seed()
|
|
|
|
|
|
|
|
WIDTH = 22
|
|
|
|
HEIGHT = 16
|
|
|
|
|
|
|
|
COLOR_DEPTH = 256
|
|
|
|
COLORS = 3
|
|
|
|
|
|
|
|
DEAD = 0
|
|
|
|
DEAD_COLOR = (0, 0, 0)
|
|
|
|
ALIVE = 1
|
|
|
|
ALIVE_COLOR = (r.randint(0, 255), r.randint(0, 255), r.randint(0, 255))
|
|
|
|
|
|
|
|
|
|
|
|
def generate_rand_game_board():
|
|
|
|
board = []
|
|
|
|
for rows in range(HEIGHT):
|
|
|
|
x_coordinates = []
|
|
|
|
for cols in range(WIDTH):
|
|
|
|
x_coordinates.append(r.randint(0, 1))
|
|
|
|
board.append(x_coordinates)
|
|
|
|
return board
|
|
|
|
|
|
|
|
|
|
|
|
def get_neighbors(x, y):
|
|
|
|
for rowNumber in range(y-1, y+2):
|
|
|
|
if 0 <= rowNumber < HEIGHT:
|
|
|
|
for colNumber in range(x-1, x+2):
|
|
|
|
if 0 <= colNumber < WIDTH:
|
|
|
|
if not (y == rowNumber and x == colNumber):
|
|
|
|
yield game_board[rowNumber][colNumber]
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
argument_parser = argparse.ArgumentParser(description="Game of Life bml generator")
|
|
|
|
argument_parser.add_argument('-o', dest="output_path", type=str, help="output file (mandatory)")
|
|
|
|
argument_parser.add_argument('-w', dest="world", type=list, default=None, help="pre-constructed world (optional)")
|
|
|
|
argument_parser.add_argument('-t', dest="secs", type=int, default=90, help="time in seconds (optional)")
|
|
|
|
argument_parser.add_argument('-d', dest="delay", type=int, default=300, help="delay between frames (optional)")
|
|
|
|
args = argument_parser.parse_args()
|
|
|
|
|
|
|
|
frames = int(math.floor(args.secs * 1000 / args.delay))
|
|
|
|
|
|
|
|
dimension = frame.FrameDimension(WIDTH, HEIGHT, COLOR_DEPTH, COLORS)
|
|
|
|
game_of_life_animation = animation.Animation(dimension)
|
|
|
|
|
|
|
|
if args.output_path is None:
|
|
|
|
argument_parser.print_help()
|
|
|
|
exit()
|
|
|
|
|
|
|
|
if args.world is None:
|
|
|
|
game_board = generate_rand_game_board()
|
|
|
|
else:
|
|
|
|
game_board = ast.literal_eval(args.world)
|
|
|
|
|
|
|
|
if len(game_board) != HEIGHT:
|
|
|
|
print("len(gameBoard) != " + str(HEIGHT) + ". counted " + str(len(game_board)))
|
|
|
|
exit()
|
|
|
|
|
|
|
|
for i in game_board:
|
|
|
|
if len(i) != WIDTH:
|
|
|
|
print("len(rows) != "+str(WIDTH)+". counted "+str(len(i)))
|
|
|
|
exit()
|
|
|
|
|
|
|
|
for frame in range(frames):
|
|
|
|
# construct frame
|
|
|
|
new_frame = animation.AnimationFrame(dimension, args.delay)
|
|
|
|
for row_index in range(HEIGHT):
|
|
|
|
for col_index in range(WIDTH):
|
|
|
|
cell_status = game_board[row_index][col_index]
|
|
|
|
if cell_status == ALIVE:
|
|
|
|
new_frame.setPixel(col_index, row_index, ALIVE_COLOR)
|
|
|
|
else:
|
|
|
|
new_frame.setPixel(col_index, row_index, DEAD_COLOR)
|
|
|
|
game_of_life_animation.addFrame(new_frame)
|
|
|
|
|
|
|
|
# calculate next step
|
|
|
|
next_game_board_step = []
|
|
|
|
previous_game_board_step = game_board
|
|
|
|
for row_index in range(HEIGHT):
|
|
|
|
new_row = []
|
|
|
|
for col_index in range(WIDTH):
|
|
|
|
neighbor_list = list(get_neighbors(col_index, row_index))
|
|
|
|
alive_neighbors = neighbor_list.count(1)
|
|
|
|
if alive_neighbors < 2:
|
|
|
|
new_row.append(DEAD)
|
|
|
|
elif alive_neighbors == 2:
|
|
|
|
new_row.append(game_board[row_index][col_index])
|
|
|
|
elif alive_neighbors == 3:
|
|
|
|
new_row.append(ALIVE)
|
|
|
|
elif alive_neighbors >= 4:
|
|
|
|
new_row.append(DEAD)
|
|
|
|
next_game_board_step.append(new_row)
|
|
|
|
game_board = next_game_board_step
|
|
|
|
if game_board == previous_game_board_step:
|
|
|
|
for i in range(20):
|
|
|
|
game_of_life_animation.addFrame(new_frame)
|
|
|
|
break
|
|
|
|
blup.writebml.writeBml(game_of_life_animation, args.output_path)
|