44from api .world import World
55from api .entity .entity import Entity
66import random
7+ from collections import deque
78
89
910class Snake (Entity ):
@@ -12,12 +13,12 @@ class Snake(Entity):
1213 world.
1314
1415 Attributes:
15- __x ( int): The X-coordinate of the snake's head.
16- __y (int): The Y-coordinate of the snake's head .
17- __body (list[tuple[int, int]]): A list representing the snake's body
18- segments .
19- __world (World): The game world where the snake exists.
20- __last_direction (Direction): The last movement direction of the snake.
16+ __body (deque[tuple[ int, int]]):
17+ Deque of tuples representing the snake's body segments .
18+ __world (World):
19+ The game world where the snake exists .
20+ __last_direction (Direction):
21+ The last movement direction of the snake.
2122 """
2223
2324 def __init__ (self , world : World , x : int , y : int , direction : Direction ):
@@ -33,7 +34,7 @@ def __init__(self, world: World, x: int, y: int, direction: Direction):
3334 """
3435 super ().__init__ (x , y )
3536
36- self .__body : list [tuple [int , int ]] = []
37+ self .__body : deque [tuple [int , int ]] = deque ()
3738 self .__world : World = world
3839 self .__last_direction : Direction = direction
3940
@@ -44,57 +45,67 @@ def __init__(self, world: World, x: int, y: int, direction: Direction):
4445 x += dir_x
4546 y += dir_y
4647 self .__body .append ((x , y ))
47-
48- def teleport (self , x , y ):
49- super ().teleport (x , y )
5048
51- for i in range (len (self .__body )):
52- del self .__body [i ]
49+ def teleport (self , x : int , y : int ) -> None :
50+ """
51+ Teleports the snake to a new position and resets its body direction.
52+
53+ Args:
54+ x (int): The new X position.
55+ y (int): The new Y position.
56+ """
57+ super ().teleport (x , y )
5358
54- self .__last_direction = random .choice ([ x for x in list (Direction ) if x .name != self .__last_direction .name ])
59+ new_body = deque ()
60+ for _ in range (len (self .__body )):
61+ dir_name = self .__last_direction .name
62+ self .__last_direction = random .choice ([
63+ d for d in list (Direction ) if d .name != dir_name
64+ ])
5565 dir_x , dir_y = self .__last_direction .value
5666
5767 x += dir_x
5868 y += dir_y
5969
60- self . __body . insert ( i , (x , y ))
70+ new_body . append ( (x , y ))
6171
62- def move (self , direction : Direction ):
72+ self .__body = new_body
73+
74+ def move (self , direction : Direction ) -> None :
6375 """
6476 Moves the snake in the given direction. If the new location is not
6577 passable, the game ends.
6678
6779 Args:
6880 direction (Direction): The direction in which the snake should
69- move.
81+ move.
7082
7183 Raises:
7284 GameOver: If the snake collides with an obstacle or itself.
7385 """
7486 x , y = direction .value
75- info = self .__world .get_location (self .get_x () + x , self .get_y () + y )
76-
77- if info .is_wall ():
78- raise GameOver ("End game" )
87+ new_x = self .get_x () + x
88+ new_y = self .get_y () + y
89+ info = self .__world .get_location (new_x , new_y )
7990
80- if ( self . get_x () + x , self . get_y () + y ) in self .__body :
91+ if info . is_wall () or ( new_x , new_y ) in self .__body :
8192 raise GameOver ("End game" )
8293
8394 if isinstance (info .get_entity (), Apple ):
8495 self .eat (info .get_entity ())
8596
86- self .set_x (self . get_x () + x )
87- self .set_y (self . get_y () + y )
97+ self .set_x (new_x )
98+ self .set_y (new_y )
8899 self .__last_direction = direction
89100
90101 # Move the body segments following the head
91- self .__body .insert ( 0 , (self .get_x () - x , self .get_y () - y ))
92- del self .__body [ - 1 ]
102+ self .__body .appendleft ( (self .get_x () - x , self .get_y () - y ))
103+ self .__body . pop ()
93104
94- def eat (self , apple : Apple ):
105+ def eat (self , apple : Apple ) -> None :
95106 """
96- Handles the snake eating an apple. The snake grows if the apple is
97- green, otherwise, it loses a segment.
107+ Handles the snake eating an apple.
108+ The snake grows if the apple is green, otherwise, it loses a segment.
98109
99110 Args:
100111 apple (Apple): The apple that the snake is eating.
@@ -109,12 +120,12 @@ def eat(self, apple: Apple):
109120 # Grow the snake by adding a new body segment
110121 self .__body .append ((last_body [0 ] + x , last_body [1 ] + y ))
111122 else :
112- if len ( self .__body ) == 0 :
123+ if not self .__body :
113124 raise GameOver ("End game" )
114125
115126 # Remove the last body segment
116- del self .__body [ - 1 ]
117-
127+ self .__body . pop ()
128+
118129 apple .consume ()
119130
120131 def size (self ) -> int :
@@ -127,33 +138,33 @@ def size(self) -> int:
127138 """
128139 return len (self .__body ) + 1
129140
130- def get_body (self ) -> list [tuple [int , int ]]:
141+ def get_body (self ) -> deque [tuple [int , int ]]:
131142 """
132143 Returns the list of body segments of the snake.
133144
134145 Returns:
135- list [tuple[int, int]]: The body segments of the snake.
146+ deque [tuple[int, int]]: The body segments of the snake.
136147 """
137148 return self .__body
138149
139150 def get_char (self ) -> str :
140151 """
141- Returns the character representation of the snake, colored for
142- terminal output.
152+ Returns the character representation of the snake, colored for terminal
153+ output.
143154
144155 Returns:
145156 str: A string representing the snake, colored in yellow.
146157 """
147158 return "\033 [33m#\033 [0m"
148159
149- def render (self ):
160+ def render (self ) -> list [ tuple [ str , int , int ]] :
150161 """
151162 Renders the snake and its body in the world.
152163
153164 Returns:
154- list: A list containing the snake's head and body positions.
165+ list[tuple[str, int, int]]: A list containing the snake's head and
166+ body positions.
155167 """
156168 render = super ().render ()
157- [render .append (("#" , body [0 ], body [1 ])) for body in self .__body ]
158-
169+ render .extend (("#" , body [0 ], body [1 ]) for body in self .__body )
159170 return render
0 commit comments