Skip to content

Instantly share code, notes, and snippets.

@frafra
Created August 29, 2017 23:10
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 frafra/7931c18d2161e7e51da6898ad8693026 to your computer and use it in GitHub Desktop.
Save frafra/7931c18d2161e7e51da6898ad8693026 to your computer and use it in GitHub Desktop.
Bruteforce Conway's "Game of Life"
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2014 Francesco Frassinelli <fraph24@gmail.com>
#
# pylife is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" See: http://en.wikipedia.org/wiki/Conway's_Game_of_Life """
from itertools import chain, product
from multiprocessing import Pool, cpu_count
from sys import argv
def nextstage(board, rows, columns, rrows, rcolumns):
""" Calculates the next stage """
new = list(map(list, board))
for r in rrows:
row = new[r]
for c in rcolumns:
near = (board[r - 1][c - 1] +
board[r - 1][c] +
board[r - 1][c + 1] +
board[r][c - 1] +
board[r][c + 1] +
board[r + 1][c - 1] +
board[r + 1][c] +
board[r + 1][c + 1])
item = row[c]
if near != 2 and near != 3 and item:
new[r][c] = 0
elif near == 3 and not item:
new[r][c] = 1
return new
#def dumps(board):
# return hash(imap(tuple, board)) # = id(...) # Error!
#def dumps(board):
# return hash(tuple(map(tuple, board)))
def dumps(board):
res = int()
for r in range(len(board)):
row = board[r]
for c in range(len(row)):
res += (row[c]<<c)*r
return res
def discover(args):
board, rows, columns = args
first, dump = board, dumps(board)
history = set()
rrows, rcolumns = range(1, rows + 1), range(1, columns + 1)
while 1:
history.add(dump)
board = nextstage(board, rows, columns, rrows, rcolumns)
dump = dumps(board)
if dump in history:
if board == first:
return first, rows, columns
return None
def gen(exp, space):
for part in exp:
yield list(chain(space, part, space))
def generator(rows, columns):
for board in (gen(product(gen(product((0, 1), repeat=columns),
(0,)), repeat=rows), [[0,]*(columns+2),])):
yield board, rows, columns
def printboard(board, rows, columns):
for r in range(1, rows + 1):
row = board[r]
line = []
for c in range(1, columns + 1):
line.append("@" if row[c] else "x")
print("".join(line))
print("")
def bruteforce(rows, columns, processes = cpu_count()):
#print("[info] %d cpu(s) detected\n" % processes)
pool = Pool(processes+1)
for board in pool.imap(discover, generator(rows, columns), 64):
if board:
printboard(*board)
if __name__ == "__main__":
try:
rows, columns = int(argv[1]), int(argv[2])
except IndexError:
print("Usage: %s [rows] [columns]" % argv[0])
except ValueError:
print("Usage: %s [rows] [columns]" % argv[0])
else:
bruteforce(rows, columns)
@frafra
Copy link
Author

frafra commented Aug 29, 2017

I implemented a Rust version that is ~100 faster (or ~50 times faster if compared to PyPy) : https://github.com/frafra/brutegol

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment