A Pythonic implementation of Conway's Game of Life

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
10
down vote
favorite
I've just finished implementing Conway's Game of Life in python-3.6:
import curses
import numpy as np
import time
from collections import defaultdict
from enum import Enum
from typing import List
class State(Enum):
''' enum class to represent possible cell states '''
dead = 0
alive = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, m : int, n : int, init : List[List[int]]):
self.m = m # the number of rows
self.n = n # the number of columns
self.board_ = [
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
@property
def population(self):
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
count = 0
for i in range(x - 1, x + 2):
for j in range(y - 1, y + 2):
if (i == x and j == y) or i < 0 or j < 0:
continue
# handle IndexErrors raised during invalid indexing operations
try:
count += self.board_[i][j].value
except IndexError:
continue
return count
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
cur_state = self.board_[x][y]
# determine the next state based on the current state and
# number of live neighbours
if count in 2, 3 and cur_state == State.alive:
return cur_state
elif count == 3 and cur_state == State.dead:
return State.alive
return State.dead
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[self.next_cell_state(i, j) for j in range(self.n)] for i in range(self.m)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
To run the code, just invoke python3.6 conway.py. The board shape is fixed; but the configuration is randomly generated with NumPy.
My aim with this project was:
- Implement a concise and pythonic version of the algorithm
- Get better with Python's OOP constructs
- Kill time :-)
There are a few redundant functions and properties which felt would be useful at some point of time.
My next step with this program would likely be to host it on a server and let people run it on their browser with a Step and Run button. This might influence how I'd need to structure my code.
python python-3.x game game-of-life
 |Â
show 1 more comment
up vote
10
down vote
favorite
I've just finished implementing Conway's Game of Life in python-3.6:
import curses
import numpy as np
import time
from collections import defaultdict
from enum import Enum
from typing import List
class State(Enum):
''' enum class to represent possible cell states '''
dead = 0
alive = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, m : int, n : int, init : List[List[int]]):
self.m = m # the number of rows
self.n = n # the number of columns
self.board_ = [
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
@property
def population(self):
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
count = 0
for i in range(x - 1, x + 2):
for j in range(y - 1, y + 2):
if (i == x and j == y) or i < 0 or j < 0:
continue
# handle IndexErrors raised during invalid indexing operations
try:
count += self.board_[i][j].value
except IndexError:
continue
return count
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
cur_state = self.board_[x][y]
# determine the next state based on the current state and
# number of live neighbours
if count in 2, 3 and cur_state == State.alive:
return cur_state
elif count == 3 and cur_state == State.dead:
return State.alive
return State.dead
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[self.next_cell_state(i, j) for j in range(self.n)] for i in range(self.m)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
To run the code, just invoke python3.6 conway.py. The board shape is fixed; but the configuration is randomly generated with NumPy.
My aim with this project was:
- Implement a concise and pythonic version of the algorithm
- Get better with Python's OOP constructs
- Kill time :-)
There are a few redundant functions and properties which felt would be useful at some point of time.
My next step with this program would likely be to host it on a server and let people run it on their browser with a Step and Run button. This might influence how I'd need to structure my code.
python python-3.x game game-of-life
As a bonus, I'd like to know if/how it would be possible to print to stdout using thecursesmodule (so as to overwrite the previous state's output).
â coldspeed
May 3 at 4:56
Is it just me not finding it or are you actually not using yourimport cursesat all at the moment?
â Mathias Ettinger
May 3 at 9:24
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56
 |Â
show 1 more comment
up vote
10
down vote
favorite
up vote
10
down vote
favorite
I've just finished implementing Conway's Game of Life in python-3.6:
import curses
import numpy as np
import time
from collections import defaultdict
from enum import Enum
from typing import List
class State(Enum):
''' enum class to represent possible cell states '''
dead = 0
alive = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, m : int, n : int, init : List[List[int]]):
self.m = m # the number of rows
self.n = n # the number of columns
self.board_ = [
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
@property
def population(self):
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
count = 0
for i in range(x - 1, x + 2):
for j in range(y - 1, y + 2):
if (i == x and j == y) or i < 0 or j < 0:
continue
# handle IndexErrors raised during invalid indexing operations
try:
count += self.board_[i][j].value
except IndexError:
continue
return count
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
cur_state = self.board_[x][y]
# determine the next state based on the current state and
# number of live neighbours
if count in 2, 3 and cur_state == State.alive:
return cur_state
elif count == 3 and cur_state == State.dead:
return State.alive
return State.dead
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[self.next_cell_state(i, j) for j in range(self.n)] for i in range(self.m)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
To run the code, just invoke python3.6 conway.py. The board shape is fixed; but the configuration is randomly generated with NumPy.
My aim with this project was:
- Implement a concise and pythonic version of the algorithm
- Get better with Python's OOP constructs
- Kill time :-)
There are a few redundant functions and properties which felt would be useful at some point of time.
My next step with this program would likely be to host it on a server and let people run it on their browser with a Step and Run button. This might influence how I'd need to structure my code.
python python-3.x game game-of-life
I've just finished implementing Conway's Game of Life in python-3.6:
import curses
import numpy as np
import time
from collections import defaultdict
from enum import Enum
from typing import List
class State(Enum):
''' enum class to represent possible cell states '''
dead = 0
alive = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, m : int, n : int, init : List[List[int]]):
self.m = m # the number of rows
self.n = n # the number of columns
self.board_ = [
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
@property
def population(self):
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
count = 0
for i in range(x - 1, x + 2):
for j in range(y - 1, y + 2):
if (i == x and j == y) or i < 0 or j < 0:
continue
# handle IndexErrors raised during invalid indexing operations
try:
count += self.board_[i][j].value
except IndexError:
continue
return count
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
cur_state = self.board_[x][y]
# determine the next state based on the current state and
# number of live neighbours
if count in 2, 3 and cur_state == State.alive:
return cur_state
elif count == 3 and cur_state == State.dead:
return State.alive
return State.dead
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[self.next_cell_state(i, j) for j in range(self.n)] for i in range(self.m)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
To run the code, just invoke python3.6 conway.py. The board shape is fixed; but the configuration is randomly generated with NumPy.
My aim with this project was:
- Implement a concise and pythonic version of the algorithm
- Get better with Python's OOP constructs
- Kill time :-)
There are a few redundant functions and properties which felt would be useful at some point of time.
My next step with this program would likely be to host it on a server and let people run it on their browser with a Step and Run button. This might influence how I'd need to structure my code.
python python-3.x game game-of-life
edited May 13 at 22:40
Jamalâ¦
30.1k11114225
30.1k11114225
asked May 3 at 4:32
coldspeed
220110
220110
As a bonus, I'd like to know if/how it would be possible to print to stdout using thecursesmodule (so as to overwrite the previous state's output).
â coldspeed
May 3 at 4:56
Is it just me not finding it or are you actually not using yourimport cursesat all at the moment?
â Mathias Ettinger
May 3 at 9:24
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56
 |Â
show 1 more comment
As a bonus, I'd like to know if/how it would be possible to print to stdout using thecursesmodule (so as to overwrite the previous state's output).
â coldspeed
May 3 at 4:56
Is it just me not finding it or are you actually not using yourimport cursesat all at the moment?
â Mathias Ettinger
May 3 at 9:24
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56
As a bonus, I'd like to know if/how it would be possible to print to stdout using the
curses module (so as to overwrite the previous state's output).â coldspeed
May 3 at 4:56
As a bonus, I'd like to know if/how it would be possible to print to stdout using the
curses module (so as to overwrite the previous state's output).â coldspeed
May 3 at 4:56
Is it just me not finding it or are you actually not using your
import curses at all at the moment?â Mathias Ettinger
May 3 at 9:24
Is it just me not finding it or are you actually not using your
import curses at all at the moment?â Mathias Ettinger
May 3 at 9:24
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
1
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56
 |Â
show 1 more comment
1 Answer
1
active
oldest
votes
up vote
8
down vote
accepted
Your code is pretty good, and there's not much I'd change. However I would change it in the following ways:
- It's standard to use
UPPER_SNAKE_CASEfor Enum values. - It's preferred to use
typing.Sequenceovertyping.Listto annotate arguments. - When you have to comment what a variable is, it indicates you've chosen a bad name. Instead use
rowsoverm. Either put your comprehensions on one line or split them out.
# Current way
[
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
# One line
[[State(init[i][j]) for j in range(self.n)] for i in range(self.m)]
# Multiple lines
[
[
State(init[i][j])
for j in range(self.n)
]
for i in range(self.m)
]It's easier to read a comprehension in a function if you keep the brackets together.
# Current
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
# Together
return 'n'.join([
''.join(['*' if cell.value else ' '
for cell in row])
for row in self.board_])
# Together and multiple lines
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])You don't need to use the surrounding brackets if your comprehension is the only argument to a function. However, this may be a couple of u seconds slower, which shouldn't matter to most people.
return 'n'.join(
''.join(
'*' if cell.value else ' '
for cell in row
)
for row in self.board_
)I'd make another function
neighbours. I find this nicer, as finding the neighbors can be a little annoying, and take away from the actual algorithm.I'd also make the algorithm use a premade list, that filters out
x==ialready.NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i][j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))Your
next_cell_statefunction can be simplified.- Your two
ifs returnState.ALIVE. - They can be merged together.
- You can return early if
countis three. - You can simplify the rest of the checks.
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD- Your two
import numpy as np
import time
from enum import Enum
from typing import List, Iterator, Sequence, Tuple
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
class State(Enum):
''' enum class to represent possible cell states '''
DEAD = 0
ALIVE = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]):
self.rows = rows # the number of rows
self.columns = columns # the number of columns
self.board_ = [
[
State(init[i][j])
for j in range(self.columns)
]
for i in range(self.rows)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])
@property
def population(self) -> int:
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i, j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[
self.next_cell_state(i, j)
for j in range(self.columns)
]
for i in range(self.rows)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
Okay, thanks. A couple of other things. In the same function, you're yieldingself.board_[i, j], while I believe you meant...[i][j], but that's a small thing. For consistency, would it also be better fornext_board_stateto hint a return type ofList[List[State]]orSequence[Sequence[State]]?
â coldspeed
May 3 at 11:46
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to useSequence, however I wouldn't. First the docs say not to. "Generic version oflist. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. WhereListis just a class. And so you want to work on interfaces, and return classes / interfaces.
â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forcesjointo call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦
â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
8
down vote
accepted
Your code is pretty good, and there's not much I'd change. However I would change it in the following ways:
- It's standard to use
UPPER_SNAKE_CASEfor Enum values. - It's preferred to use
typing.Sequenceovertyping.Listto annotate arguments. - When you have to comment what a variable is, it indicates you've chosen a bad name. Instead use
rowsoverm. Either put your comprehensions on one line or split them out.
# Current way
[
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
# One line
[[State(init[i][j]) for j in range(self.n)] for i in range(self.m)]
# Multiple lines
[
[
State(init[i][j])
for j in range(self.n)
]
for i in range(self.m)
]It's easier to read a comprehension in a function if you keep the brackets together.
# Current
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
# Together
return 'n'.join([
''.join(['*' if cell.value else ' '
for cell in row])
for row in self.board_])
# Together and multiple lines
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])You don't need to use the surrounding brackets if your comprehension is the only argument to a function. However, this may be a couple of u seconds slower, which shouldn't matter to most people.
return 'n'.join(
''.join(
'*' if cell.value else ' '
for cell in row
)
for row in self.board_
)I'd make another function
neighbours. I find this nicer, as finding the neighbors can be a little annoying, and take away from the actual algorithm.I'd also make the algorithm use a premade list, that filters out
x==ialready.NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i][j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))Your
next_cell_statefunction can be simplified.- Your two
ifs returnState.ALIVE. - They can be merged together.
- You can return early if
countis three. - You can simplify the rest of the checks.
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD- Your two
import numpy as np
import time
from enum import Enum
from typing import List, Iterator, Sequence, Tuple
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
class State(Enum):
''' enum class to represent possible cell states '''
DEAD = 0
ALIVE = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]):
self.rows = rows # the number of rows
self.columns = columns # the number of columns
self.board_ = [
[
State(init[i][j])
for j in range(self.columns)
]
for i in range(self.rows)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])
@property
def population(self) -> int:
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i, j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[
self.next_cell_state(i, j)
for j in range(self.columns)
]
for i in range(self.rows)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
Okay, thanks. A couple of other things. In the same function, you're yieldingself.board_[i, j], while I believe you meant...[i][j], but that's a small thing. For consistency, would it also be better fornext_board_stateto hint a return type ofList[List[State]]orSequence[Sequence[State]]?
â coldspeed
May 3 at 11:46
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to useSequence, however I wouldn't. First the docs say not to. "Generic version oflist. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. WhereListis just a class. And so you want to work on interfaces, and return classes / interfaces.
â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forcesjointo call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦
â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
add a comment |Â
up vote
8
down vote
accepted
Your code is pretty good, and there's not much I'd change. However I would change it in the following ways:
- It's standard to use
UPPER_SNAKE_CASEfor Enum values. - It's preferred to use
typing.Sequenceovertyping.Listto annotate arguments. - When you have to comment what a variable is, it indicates you've chosen a bad name. Instead use
rowsoverm. Either put your comprehensions on one line or split them out.
# Current way
[
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
# One line
[[State(init[i][j]) for j in range(self.n)] for i in range(self.m)]
# Multiple lines
[
[
State(init[i][j])
for j in range(self.n)
]
for i in range(self.m)
]It's easier to read a comprehension in a function if you keep the brackets together.
# Current
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
# Together
return 'n'.join([
''.join(['*' if cell.value else ' '
for cell in row])
for row in self.board_])
# Together and multiple lines
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])You don't need to use the surrounding brackets if your comprehension is the only argument to a function. However, this may be a couple of u seconds slower, which shouldn't matter to most people.
return 'n'.join(
''.join(
'*' if cell.value else ' '
for cell in row
)
for row in self.board_
)I'd make another function
neighbours. I find this nicer, as finding the neighbors can be a little annoying, and take away from the actual algorithm.I'd also make the algorithm use a premade list, that filters out
x==ialready.NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i][j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))Your
next_cell_statefunction can be simplified.- Your two
ifs returnState.ALIVE. - They can be merged together.
- You can return early if
countis three. - You can simplify the rest of the checks.
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD- Your two
import numpy as np
import time
from enum import Enum
from typing import List, Iterator, Sequence, Tuple
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
class State(Enum):
''' enum class to represent possible cell states '''
DEAD = 0
ALIVE = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]):
self.rows = rows # the number of rows
self.columns = columns # the number of columns
self.board_ = [
[
State(init[i][j])
for j in range(self.columns)
]
for i in range(self.rows)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])
@property
def population(self) -> int:
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i, j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[
self.next_cell_state(i, j)
for j in range(self.columns)
]
for i in range(self.rows)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
Okay, thanks. A couple of other things. In the same function, you're yieldingself.board_[i, j], while I believe you meant...[i][j], but that's a small thing. For consistency, would it also be better fornext_board_stateto hint a return type ofList[List[State]]orSequence[Sequence[State]]?
â coldspeed
May 3 at 11:46
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to useSequence, however I wouldn't. First the docs say not to. "Generic version oflist. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. WhereListis just a class. And so you want to work on interfaces, and return classes / interfaces.
â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forcesjointo call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦
â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
add a comment |Â
up vote
8
down vote
accepted
up vote
8
down vote
accepted
Your code is pretty good, and there's not much I'd change. However I would change it in the following ways:
- It's standard to use
UPPER_SNAKE_CASEfor Enum values. - It's preferred to use
typing.Sequenceovertyping.Listto annotate arguments. - When you have to comment what a variable is, it indicates you've chosen a bad name. Instead use
rowsoverm. Either put your comprehensions on one line or split them out.
# Current way
[
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
# One line
[[State(init[i][j]) for j in range(self.n)] for i in range(self.m)]
# Multiple lines
[
[
State(init[i][j])
for j in range(self.n)
]
for i in range(self.m)
]It's easier to read a comprehension in a function if you keep the brackets together.
# Current
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
# Together
return 'n'.join([
''.join(['*' if cell.value else ' '
for cell in row])
for row in self.board_])
# Together and multiple lines
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])You don't need to use the surrounding brackets if your comprehension is the only argument to a function. However, this may be a couple of u seconds slower, which shouldn't matter to most people.
return 'n'.join(
''.join(
'*' if cell.value else ' '
for cell in row
)
for row in self.board_
)I'd make another function
neighbours. I find this nicer, as finding the neighbors can be a little annoying, and take away from the actual algorithm.I'd also make the algorithm use a premade list, that filters out
x==ialready.NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i][j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))Your
next_cell_statefunction can be simplified.- Your two
ifs returnState.ALIVE. - They can be merged together.
- You can return early if
countis three. - You can simplify the rest of the checks.
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD- Your two
import numpy as np
import time
from enum import Enum
from typing import List, Iterator, Sequence, Tuple
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
class State(Enum):
''' enum class to represent possible cell states '''
DEAD = 0
ALIVE = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]):
self.rows = rows # the number of rows
self.columns = columns # the number of columns
self.board_ = [
[
State(init[i][j])
for j in range(self.columns)
]
for i in range(self.rows)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])
@property
def population(self) -> int:
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i, j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[
self.next_cell_state(i, j)
for j in range(self.columns)
]
for i in range(self.rows)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
Your code is pretty good, and there's not much I'd change. However I would change it in the following ways:
- It's standard to use
UPPER_SNAKE_CASEfor Enum values. - It's preferred to use
typing.Sequenceovertyping.Listto annotate arguments. - When you have to comment what a variable is, it indicates you've chosen a bad name. Instead use
rowsoverm. Either put your comprehensions on one line or split them out.
# Current way
[
[State(init[i][j]) for j in range(self.n)] for i in range(self.m)
]
# One line
[[State(init[i][j]) for j in range(self.n)] for i in range(self.m)]
# Multiple lines
[
[
State(init[i][j])
for j in range(self.n)
]
for i in range(self.m)
]It's easier to read a comprehension in a function if you keep the brackets together.
# Current
return 'n'.join([
''.join(
['*' if cell.value else ' ' for cell in row]
) for row in self.board_]
)
# Together
return 'n'.join([
''.join(['*' if cell.value else ' '
for cell in row])
for row in self.board_])
# Together and multiple lines
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])You don't need to use the surrounding brackets if your comprehension is the only argument to a function. However, this may be a couple of u seconds slower, which shouldn't matter to most people.
return 'n'.join(
''.join(
'*' if cell.value else ' '
for cell in row
)
for row in self.board_
)I'd make another function
neighbours. I find this nicer, as finding the neighbors can be a little annoying, and take away from the actual algorithm.I'd also make the algorithm use a premade list, that filters out
x==ialready.NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i][j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))Your
next_cell_statefunction can be simplified.- Your two
ifs returnState.ALIVE. - They can be merged together.
- You can return early if
countis three. - You can simplify the rest of the checks.
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD- Your two
import numpy as np
import time
from enum import Enum
from typing import List, Iterator, Sequence, Tuple
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j]
class State(Enum):
''' enum class to represent possible cell states '''
DEAD = 0
ALIVE = 1
class Board:
''' Board class to represent the game board '''
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]):
self.rows = rows # the number of rows
self.columns = columns # the number of columns
self.board_ = [
[
State(init[i][j])
for j in range(self.columns)
]
for i in range(self.rows)
]
def __str__(self) -> str:
''' return the __str__ representation of a Board object
* represents a live cell, and a space represents a dead one
'''
return 'n'.join([
''.join([
'*' if cell.value else ' '
for cell in row
])
for row in self.board_
])
@property
def population(self) -> int:
''' population â the number of live cells on the board '''
return sum(cell.value for row in self.board_ for cell in row)
def has_live_cells(self) -> bool:
''' return whether there are any live cells or not '''
return any(cell.value for row in self.board_ for cell in row)
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]:
for i, j in ((x+i, y+j) for i, j in NEIGHBOURS):
try:
yield self.board_[i, j], i, j
except IndexError:
pass
def count_live_neighbours(self, x : int, y : int) -> int:
''' count the live neighbours of a cell '''
return sum(cell.value for cell, _, _ in self.neighbours(x, y))
def next_cell_state(self, x : int, y : int) -> State:
count = self.count_live_neighbours(x, y)
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE):
return State.ALIVE
return State.DEAD
def next_board_state(self) -> List[List[State]]:
''' return board configuration for the next state '''
return [
[
self.next_cell_state(i, j)
for j in range(self.columns)
]
for i in range(self.rows)
]
def advance_state(self):
''' update the board configuration with the config for the next state '''
self.board_ = self.next_board_state()
if __name__ == '__main__':
arr = np.random.choice([0, 1], (20, 100), p=[0.90, 0.1])
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist())
step = 0
while board.has_live_cells():
step += 1
print(board)
print('fstep board.population')
board.advance_state()
time.sleep(.1)
edited May 3 at 12:18
answered May 3 at 9:53
Peilonrayz
24.3k336102
24.3k336102
Okay, thanks. A couple of other things. In the same function, you're yieldingself.board_[i, j], while I believe you meant...[i][j], but that's a small thing. For consistency, would it also be better fornext_board_stateto hint a return type ofList[List[State]]orSequence[Sequence[State]]?
â coldspeed
May 3 at 11:46
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to useSequence, however I wouldn't. First the docs say not to. "Generic version oflist. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. WhereListis just a class. And so you want to work on interfaces, and return classes / interfaces.
â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forcesjointo call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦
â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
add a comment |Â
Okay, thanks. A couple of other things. In the same function, you're yieldingself.board_[i, j], while I believe you meant...[i][j], but that's a small thing. For consistency, would it also be better fornext_board_stateto hint a return type ofList[List[State]]orSequence[Sequence[State]]?
â coldspeed
May 3 at 11:46
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to useSequence, however I wouldn't. First the docs say not to. "Generic version oflist. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. WhereListis just a class. And so you want to work on interfaces, and return classes / interfaces.
â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forcesjointo call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦
â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
Okay, thanks. A couple of other things. In the same function, you're yielding
self.board_[i, j], while I believe you meant ...[i][j], but that's a small thing. For consistency, would it also be better for next_board_state to hint a return type of List[List[State]] or Sequence[Sequence[State]]?â coldspeed
May 3 at 11:46
Okay, thanks. A couple of other things. In the same function, you're yielding
self.board_[i, j], while I believe you meant ...[i][j], but that's a small thing. For consistency, would it also be better for next_board_state to hint a return type of List[List[State]] or Sequence[Sequence[State]]?â coldspeed
May 3 at 11:46
1
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to use
Sequence, however I wouldn't. First the docs say not to. "Generic version of list. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. Where List is just a class. And so you want to work on interfaces, and return classes / interfaces.â Peilonrayz
May 3 at 11:52
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ Wat, IDK why I did that... Thanks :) You can change your returns to use
Sequence, however I wouldn't. First the docs say not to. "Generic version of list. Useful for annotating return types." This is as abstract collection types are, likely, intended to be like interfaces in languages like C#. Where List is just a class. And so you want to work on interfaces, and return classes / interfaces.â Peilonrayz
May 3 at 11:52
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forces
join to call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦â Jean-François Fabre
May 3 at 11:54
"6. You don't need to use the surrounding brackets if your comprehension is the only argument to a function.": yes you do, performance is better with the brackets, else it forces
join to call the gencomp to build a list anyway (so no memory benefits) and it's slower!!: stackoverflow.com/questions/37782066/â¦â Jean-François Fabre
May 3 at 11:54
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
@Jean-FrançoisFabre The above code works without the brackets. As far as I see it, if you're using Python you don't really care about a couple of ms, as otherwise you'd be using any other language.
â Peilonrayz
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
it works without the brackets, but it works faster with the brackets, so I can't let you suggest to remove something that works faster for the sake of readability, no.
â Jean-François Fabre
May 3 at 11:57
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193523%2fa-pythonic-implementation-of-conways-game-of-life%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
As a bonus, I'd like to know if/how it would be possible to print to stdout using the
cursesmodule (so as to overwrite the previous state's output).â coldspeed
May 3 at 4:56
Is it just me not finding it or are you actually not using your
import cursesat all at the moment?â Mathias Ettinger
May 3 at 9:24
@MathiasEttinger it's not you... that import is there pending future work. Actually, tried a couple of things and failed, forgot to remove before updating!
â coldspeed
May 3 at 10:38
1
@cá´ÂÃÂá´ sá´Âá´Âá´Âá´ you're asking for pythonic? I thought you were the pythonic guy!
â Jean-François Fabre
May 3 at 11:53
@Jean-FrançoisFabre As the answer below indicates, I have a ways to go :p
â coldspeed
May 3 at 11:56