Skip to content

Commit 04fd5c1

Browse files
CaedenPHgithub-actionstianyizheng02
authored
Create langtons ant algorithm (TheAlgorithms#8967)
* updating DIRECTORY.md * feat(cellular_automata): Langonts ant algorithm * updating DIRECTORY.md * Update cellular_automata/langtons_ant.py Co-authored-by: Tianyi Zheng <[email protected]> * Apply suggestions from code review Co-authored-by: Tianyi Zheng <[email protected]> * fix(langtons-ant): Set funcanimation interval to 1 --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Tianyi Zheng <[email protected]>
1 parent b3dc6ef commit 04fd5c1

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

Diff for: DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
## Cellular Automata
7373
* [Conways Game Of Life](cellular_automata/conways_game_of_life.py)
7474
* [Game Of Life](cellular_automata/game_of_life.py)
75+
* [Langtons Ant](cellular_automata/langtons_ant.py)
7576
* [Nagel Schrekenberg](cellular_automata/nagel_schrekenberg.py)
7677
* [One Dimensional](cellular_automata/one_dimensional.py)
7778
* [Wa Tor](cellular_automata/wa_tor.py)

Diff for: cellular_automata/langtons_ant.py

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
Langton's ant
3+
4+
@ https://en.wikipedia.org/wiki/Langton%27s_ant
5+
@ https://upload.wikimedia.org/wikipedia/commons/0/09/LangtonsAntAnimated.gif
6+
"""
7+
8+
from functools import partial
9+
10+
from matplotlib import pyplot as plt
11+
from matplotlib.animation import FuncAnimation
12+
13+
WIDTH = 80
14+
HEIGHT = 80
15+
16+
17+
class LangtonsAnt:
18+
"""
19+
Represents the main LangonsAnt algorithm.
20+
21+
>>> la = LangtonsAnt(2, 2)
22+
>>> la.board
23+
[[True, True], [True, True]]
24+
>>> la.ant_position
25+
(1, 1)
26+
"""
27+
28+
def __init__(self, width: int, height: int) -> None:
29+
# Each square is either True or False where True is white and False is black
30+
self.board = [[True] * width for _ in range(height)]
31+
self.ant_position: tuple[int, int] = (width // 2, height // 2)
32+
33+
# Initially pointing left (similar to the the wikipedia image)
34+
# (0 = 0° | 1 = 90° | 2 = 180 ° | 3 = 270°)
35+
self.ant_direction: int = 3
36+
37+
def move_ant(self, axes: plt.Axes | None, display: bool, _frame: int) -> None:
38+
"""
39+
Performs three tasks:
40+
1. The ant turns either clockwise or anti-clockwise according to the colour
41+
of the square that it is currently on. If the square is white, the ant
42+
turns clockwise, and if the square is black the ant turns anti-clockwise
43+
2. The ant moves one square in the direction that it is currently facing
44+
3. The square the ant was previously on is inverted (White -> Black and
45+
Black -> White)
46+
47+
If display is True, the board will also be displayed on the axes
48+
49+
>>> la = LangtonsAnt(2, 2)
50+
>>> la.move_ant(None, True, 0)
51+
>>> la.board
52+
[[True, True], [True, False]]
53+
>>> la.move_ant(None, True, 0)
54+
>>> la.board
55+
[[True, False], [True, False]]
56+
"""
57+
directions = {
58+
0: (-1, 0), # 0°
59+
1: (0, 1), # 90°
60+
2: (1, 0), # 180°
61+
3: (0, -1), # 270°
62+
}
63+
x, y = self.ant_position
64+
65+
# Turn clockwise or anti-clockwise according to colour of square
66+
if self.board[x][y] is True:
67+
# The square is white so turn 90° clockwise
68+
self.ant_direction = (self.ant_direction + 1) % 4
69+
else:
70+
# The square is black so turn 90° anti-clockwise
71+
self.ant_direction = (self.ant_direction - 1) % 4
72+
73+
# Move ant
74+
move_x, move_y = directions[self.ant_direction]
75+
self.ant_position = (x + move_x, y + move_y)
76+
77+
# Flip colour of square
78+
self.board[x][y] = not self.board[x][y]
79+
80+
if display and axes:
81+
# Display the board on the axes
82+
axes.get_xaxis().set_ticks([])
83+
axes.get_yaxis().set_ticks([])
84+
axes.imshow(self.board, cmap="gray", interpolation="nearest")
85+
86+
def display(self, frames: int = 100_000) -> None:
87+
"""
88+
Displays the board without delay in a matplotlib plot
89+
to visually understand and track the ant.
90+
91+
>>> _ = LangtonsAnt(WIDTH, HEIGHT)
92+
"""
93+
fig, ax = plt.subplots()
94+
# Assign animation to a variable to prevent it from getting garbage collected
95+
self.animation = FuncAnimation(
96+
fig, partial(self.move_ant, ax, True), frames=frames, interval=1
97+
)
98+
plt.show()
99+
100+
101+
if __name__ == "__main__":
102+
import doctest
103+
104+
doctest.testmod()
105+
106+
LangtonsAnt(WIDTH, HEIGHT).display()

0 commit comments

Comments
 (0)