Skip to content

Instantly share code, notes, and snippets.

@CAridorc
Created December 7, 2015 19:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CAridorc/a26f8f44ed0248d46044 to your computer and use it in GitHub Desktop.
Save CAridorc/a26f8f44ed0248d46044 to your computer and use it in GitHub Desktop.
A pair of necessary modules
"""
Simlates Conway's game of life.
"""
import doctest
import time
def in_chunks_of(n, list_):
"""
Yield successive n-sized chunks from l.
Credit to: http://stackoverflow.com/users/14343/ned-batchelder
>>> list(in_chunks_of(3, [1, 2, 3, 4, 5, 6, 7]))
[[1, 2, 3], [4, 5, 6], [7]]
"""
for i in xrange(0, len(list_), n):
yield list_[i:i+n]
def neightbors(x, y, matrix):
"""
>>> list(sorted(neightbors(1, 1, [ [1,2,3], [4,5,6], [7,8,9] ])))
[1, 2, 3, 4, 6, 7, 8, 9]
"""
for x_, y_ in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1),
(x + 1, y + 1), (x + 1, y - 1), (x - 1, y + 1), (x - 1, y - 1)):
if x_ < 0 or y_ < 0:
continue
try:
yield matrix[x_][y_]
except IndexError:
pass
def with_neightbors(matrix):
"""
>>> list(with_neightbors( [ [1, 2, 3], [4, 5, 6] ] ))
[(1, [4, 2, 5]), (2, [5, 3, 1, 6, 4]), (3, [6, 2, 5]), (4, [1, 5, 2]), (5, [2, 6, 4, 3, 1]), (6, [3, 5, 2])]
"""
for x in range(len(matrix)):
for y in range(len(matrix[0])):
yield (matrix[x][y], list(neightbors(x, y, matrix)))
def rules(x, nears):
"""
>>> rules(True, [True, True, False, False, False, True, False, False])
True
"""
return sum(nears) in (2, 3) if x else sum(nears) == 3
def next_generation(universe):
"""
>>> next_generation([ [0,0,1], [1,1,0], [0, 0, 1] ])
[[False, True, False], [False, True, True], [False, True, False]]
"""
return list(in_chunks_of(len(universe[0]),
[rules(x, neightbors) for x, neightbors in with_neightbors(universe)]))
def stringify_board(board):
"""
>>> start = " \\n ** \\n ** \\n "
>>> start == '\\n'.join(stringify_board(read_board(start)))
True
"""
for row in board:
yield ''.join('*' if i else ' ' for i in row)
def read_board(string_board):
"""
>>> read_board(" \\n ** \\n ** \\n ")
[[False, False, False, False], [False, True, True, False], [False, True, True, False], [False, False, False, False]]
"""
board = []
for line in string_board.split("\n"):
board.append( [True if i == '*' else False for i in line] )
return board
def ascii_life(board = None, generations=10**6):
board=read_board(board)
for _ in xrange(generations):
print('\n'.join(stringify_board(board)))
board = next_generation(board)
time.sleep(0.2)
print('\n'*50)
def main():
doctest.testmod()
TOAD = """
***
***
"""
RANDOM = """
*** ***
****
****
** ***
"""
for figure in (TOAD, RANDOM):
try:
ascii_life(figure)
except KeyboardInterrupt:
continue
if __name__ == "__main__":
main()
import sys
input = raw_input if sys.version_info[0] == 2 else input
def general_input(prompt="", type_=str, min_=None, max_=None,
max_length=None, set_=None, cap_sensitive=True,
help_=lambda: 0, costum_validation=lambda x: True,
costum_validation_error="Error in input"):
"""
Takes care of input validation, by diplaying meaningful
messages to the user in case of invalid input.
@ prompt: The text to be shown to the user.
@ type_: The type the input must be convertible to. (And will be converted to).
@ max_length: The maximum length of the input.
@ set_: The set of things the input must in. (This may be a `range` object or any iterable).
@ cap_sensitive: If False the input will be lowercased. (Defult True)
@ help_: What to do when the user types in `help`
@ costum_validation: A costum way to check if the input is valid.
@ costum_validation_error: Error to show when costum_validation fails
"""
while True:
input_ = input(prompt)
input_ = input_ if cap_sensitive else input_.lower()
if not costum_validation(input_):
print(costum_validation_error)
continue
if input_ == "help":
help_()
continue
try:
if not type_:
type_ = type(input_)
input_ = type_(input_)
except ValueError:
print("Expected input of type {} but got {}".format(
type_, type(input_)))
continue
if max_length and len(input_) > max_length:
print("Input is too long, the max length allowed is {}".format(
max_length))
continue
if set_ and input_ not in set_:
# Fixing that the last item in ranges is exclusive (weird for normal users)
to_print_set = None
if type(set_) == range:
to_print_set = range(min(set_), max(set_))
print("Input is not in the set of possible inputs, enter one of {}".format(
to_print_set or set_))
continue
return input_
def menu(functions):
"""
Allows for easy presentation to the user of functions, also
allowing him to get fast help.
"""
functions = list(sorted(functions, key=lambda fun: fun.__name__))
for index, func in enumerate(functions):
print("{} - {}".format(
index + 1, func.__name__))
def help_():
function_to_be_explained = general_input("Which function do you want help on? ",
type_=int, set_=range(0,len(functions))) - 1
help(functions[function_to_be_explained])
user_choice = general_input("Which function do you want to execute? (Type `help` for help). ",
type_=int, set_=range(0,len(functions)+1),
help_= help_) - 1
print(functions[user_choice](eval(input("Comma separated args for `{}`: ".format(
functions[user_choice].__name__))))); print()
def menu_for_module(module, private_shown=False):
"""
Shows a menu containing all the functions in a module
"""
priv_cond = lambda fun: fun.__name__.startswith('_') if not private_shown else False
menu([i for i in module.__dict__.values() if type(i) == type(lambda:0) and not priv_cond(i)])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment