-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# `rplife` | ||
|
||
Conway's Game of Life in your terminal. | ||
|
||
## Installation | ||
|
||
1. Create and activate a Python virtual environment | ||
|
||
```sh | ||
$ python -m venv ./venv | ||
$ source venv/bin/activate | ||
(venv) $ | ||
``` | ||
|
||
2. Install the `rplife` in editable mode | ||
|
||
```sh | ||
(venv) $ cd rplife | ||
(venv) $ pip install -e . | ||
``` | ||
|
||
## Execution | ||
|
||
To execute `rplife`, go ahead and run the following command: | ||
|
||
```sh | ||
(venv) $ rplife -a | ||
``` | ||
|
||
## Author | ||
|
||
Real Python - Email: [email protected] | ||
|
||
## License | ||
|
||
Distributed under the MIT license. See `LICENSE` for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[build-system] | ||
requires = ["setuptools>=64.0.0", "wheel"] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[project] | ||
name = "rplife" | ||
dynamic = ["version"] | ||
description = "Conway's Game of Life in your terminal" | ||
readme = "README.md" | ||
authors = [{ name = "Real Python", email = "[email protected]" }] | ||
dependencies = [ | ||
'tomli; python_version < "3.11"', | ||
] | ||
|
||
[project.scripts] | ||
rplife = "rplife.__main__:main" | ||
|
||
[tool.setuptools.dynamic] | ||
version = {attr = "rplife.__version__"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__version__ = "1.0.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import sys | ||
|
||
from rplife import patterns, views | ||
from rplife.cli import get_command_line_args | ||
|
||
|
||
def main(): | ||
args = get_command_line_args() | ||
View = getattr(views, args.view) | ||
if args.all: | ||
for pattern in patterns.get_all_patterns(): | ||
_show_pattern(View, pattern, args) | ||
else: | ||
_show_pattern(View, patterns.get_pattern(name=args.pattern), args) | ||
|
||
|
||
def _show_pattern(View, pattern, args): | ||
try: | ||
View(pattern=pattern, gen=args.gen, framerate=args.fps).show() | ||
except Exception as error: | ||
print(error, file=sys.stderr) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import argparse | ||
|
||
from rplife import __version__, patterns, views | ||
|
||
|
||
def get_command_line_args(): | ||
parser = argparse.ArgumentParser( | ||
prog="rplife", | ||
description="Conway's Game of Life in your terminal", | ||
) | ||
parser.add_argument( | ||
"--version", action="version", version=f"%(prog)s v{__version__}" | ||
) | ||
parser.add_argument( | ||
"-p", | ||
"--pattern", | ||
choices=[pat.name for pat in patterns.get_all_patterns()], | ||
default="Blinker", | ||
help="take a pattern for the Game of Life (default: %(default)s)", | ||
) | ||
parser.add_argument( | ||
"-a", | ||
"--all", | ||
action="store_true", | ||
help="show all available patterns in a sequence", | ||
) | ||
parser.add_argument( | ||
"-g", | ||
"--gen", | ||
metavar="NUM_GENERATIONS", | ||
type=int, | ||
default=10, | ||
help="number of generations (default: %(default)s)", | ||
) | ||
parser.add_argument( | ||
"-v", | ||
"--view", | ||
choices=views.__all__, | ||
default="CursesView", | ||
help="display the life grid in a specific view (default: %(default)s)", | ||
) | ||
parser.add_argument( | ||
"-f", | ||
"--fps", | ||
metavar="FRAMES_PER_SECOND", | ||
type=int, | ||
default=7, | ||
help="frames per second (default: %(default)s)", | ||
) | ||
return parser.parse_args() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import collections | ||
|
||
ALIVE = "♥" | ||
DEAD = "‧" | ||
|
||
|
||
class LifeGrid: | ||
def __init__(self, pattern): | ||
self.pattern = pattern | ||
|
||
def evolve(self): | ||
neighbors = ( | ||
(-1, -1), | ||
(-1, 0), | ||
(-1, 1), | ||
(0, -1), | ||
(0, 1), | ||
(1, -1), | ||
(1, 0), | ||
(1, 1), | ||
) | ||
num_neighbors = collections.defaultdict(int) | ||
for row, col in self.pattern.alive_cells: | ||
for drow, dcol in neighbors: | ||
num_neighbors[(row + drow, col + dcol)] += 1 | ||
|
||
stay_alive = { | ||
cell for cell, num in num_neighbors.items() if num in {2, 3} | ||
} & self.pattern.alive_cells | ||
come_alive = { | ||
cell for cell, num in num_neighbors.items() if num == 3 | ||
} - self.pattern.alive_cells | ||
|
||
self.pattern.alive_cells = stay_alive | come_alive | ||
|
||
def as_string(self, bbox): | ||
start_col, start_row, end_col, end_row = bbox | ||
display = [self.pattern.name.center(2 * (end_col - start_col))] | ||
for row in range(start_row, end_row): | ||
display_row = [ | ||
ALIVE if (row, col) in self.pattern.alive_cells else DEAD | ||
for col in range(start_col, end_col) | ||
] | ||
display.append(" ".join(display_row)) | ||
return "\n ".join(display) | ||
|
||
def __str__(self): | ||
return ( | ||
f"{self.pattern.name}:\nAlive cells -> {self.pattern.alive_cells}" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from dataclasses import dataclass | ||
from pathlib import Path | ||
|
||
try: | ||
import tomllib as toml | ||
except ImportError: | ||
import tomli as toml | ||
|
||
PATTERNS_FILE = Path(__file__).parent / "patterns.toml" | ||
|
||
|
||
@dataclass | ||
class Pattern: | ||
name: str | ||
alive_cells: set[tuple[int, int]] | ||
|
||
@classmethod | ||
def from_toml(cls, name, toml_data): | ||
return cls( | ||
name, | ||
alive_cells={tuple(cell) for cell in toml_data["alive_cells"]}, | ||
) | ||
|
||
|
||
def get_pattern(name, file_name=PATTERNS_FILE): | ||
data = toml.loads(file_name.read_text(encoding="utf-8")) | ||
return Pattern.from_toml(name, toml_data=data[name]) | ||
|
||
|
||
def get_all_patterns(file_name=PATTERNS_FILE): | ||
data = toml.loads(file_name.read_text(encoding="utf-8")) | ||
return [ | ||
Pattern.from_toml(name, toml_data) for name, toml_data in data.items() | ||
] |
142 changes: 142 additions & 0 deletions
142
game-of-life-python/source_code_final/rplife/patterns.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
["Blinker"] | ||
alive_cells = [[2, 1], [2, 2], [2, 3]] | ||
|
||
["Toad"] | ||
alive_cells = [[2, 2], [2, 3], [2, 4], [3, 1], [3, 2], [3, 3]] | ||
|
||
["Beacon"] | ||
alive_cells = [[1, 1], [1, 2], [2, 1], [4, 3], [4, 4], [3, 4]] | ||
|
||
["Pulsar"] | ||
alive_cells = [ | ||
[2, 4], | ||
[2, 5], | ||
[2, 6], | ||
[2, 10], | ||
[2, 11], | ||
[2, 12], | ||
[4, 2], | ||
[5, 2], | ||
[6, 2], | ||
[4, 7], | ||
[5, 7], | ||
[6, 7], | ||
[4, 9], | ||
[5, 9], | ||
[6, 9], | ||
[4, 14], | ||
[5, 14], | ||
[6, 14], | ||
[7, 4], | ||
[7, 5], | ||
[7, 6], | ||
[7, 10], | ||
[7, 11], | ||
[7, 12], | ||
[9, 4], | ||
[9, 5], | ||
[9, 6], | ||
[9, 10], | ||
[9, 11], | ||
[9, 12], | ||
[10, 2], | ||
[11, 2], | ||
[12, 2], | ||
[10, 7], | ||
[11, 7], | ||
[12, 7], | ||
[10, 9], | ||
[11, 9], | ||
[12, 9], | ||
[10, 14], | ||
[11, 14], | ||
[12, 14], | ||
[14, 4], | ||
[14, 5], | ||
[14, 6], | ||
[14, 10], | ||
[14, 11], | ||
[14, 12] | ||
] | ||
|
||
["Penta Decathlon"] | ||
alive_cells = [ | ||
[5, 4], | ||
[6, 4], | ||
[7, 4], | ||
[8, 4], | ||
[9, 4], | ||
[10, 4], | ||
[11, 4], | ||
[12, 4], | ||
[5, 5], | ||
[7, 5], | ||
[8, 5], | ||
[9, 5], | ||
[10, 5], | ||
[12, 5], | ||
[5, 6], | ||
[6, 6], | ||
[7, 6], | ||
[8, 6], | ||
[9, 6], | ||
[10, 6], | ||
[11, 6], | ||
[12, 6] | ||
] | ||
|
||
["Glider"] | ||
alive_cells = [[0, 2], [1, 0], [1, 2], [2, 1], [2, 2]] | ||
|
||
["Glider Gun"] | ||
alive_cells = [ | ||
[0, 24], | ||
[1, 22], | ||
[1, 24], | ||
[2, 12], | ||
[2, 13], | ||
[2, 20], | ||
[2, 21], | ||
[2, 34], | ||
[2, 35], | ||
[3, 11], | ||
[3, 15], | ||
[3, 20], | ||
[3, 21], | ||
[3, 34], | ||
[3, 35], | ||
[4, 0], | ||
[4, 1], | ||
[4, 10], | ||
[4, 16], | ||
[4, 20], | ||
[4, 21], | ||
[5, 0], | ||
[5, 1], | ||
[5, 10], | ||
[5, 14], | ||
[5, 16], | ||
[5, 17], | ||
[5, 22], | ||
[5, 24], | ||
[6, 10], | ||
[6, 16], | ||
[6, 24], | ||
[7, 11], | ||
[7, 15], | ||
[8, 12], | ||
[8, 13] | ||
] | ||
|
||
["Bunnies"] | ||
alive_cells = [ | ||
[10, 10], | ||
[10, 16], | ||
[11, 12], | ||
[11, 16], | ||
[12, 12], | ||
[12, 15], | ||
[12, 17], | ||
[13, 11], | ||
[13, 13] | ||
] |
Oops, something went wrong.