1// snake.c
2// ๋ฑ ๊ฒ์ ํต์ฌ ๋ก์ง ๊ตฌํ
3// ๋ฑ์ ์์ฑ, ์ด๋, ์ถฉ๋ ๊ฒ์ฌ ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
4
5#include <stdio.h>
6#include <stdlib.h>
7#include "snake_types.h"
8
9// ============ ๋ฑ ์์ฑ ๋ฐ ํด์ ============
10
11/**
12 * ๋ฑ ์์ฑ
13 *
14 * @param start_x ์์ X ์ขํ (๋จธ๋ฆฌ ์์น)
15 * @param start_y ์์ Y ์ขํ (๋จธ๋ฆฌ ์์น)
16 * @param initial_dir ์ด๊ธฐ ์ด๋ ๋ฐฉํฅ
17 * @return ์์ฑ๋ ๋ฑ ํฌ์ธํฐ (์คํจ ์ NULL)
18 */
19Snake* snake_create(int start_x, int start_y, Direction initial_dir) {
20 Snake* snake = malloc(sizeof(Snake));
21 if (!snake) {
22 return NULL;
23 }
24
25 // ๋ฑ ์ด๊ธฐํ
26 snake->head = NULL;
27 snake->tail = NULL;
28 snake->length = 0;
29 snake->dir = initial_dir;
30
31 // ์ด๊ธฐ ๋ชธํต ์์ฑ (๊ธฐ๋ณธ 3์นธ)
32 // ๋จธ๋ฆฌ๋ถํฐ ๊ผฌ๋ฆฌ ์์๋ก ์ถ๊ฐ
33 for (int i = 0; i < INITIAL_SNAKE_LENGTH; i++) {
34 SnakeNode* node = malloc(sizeof(SnakeNode));
35 if (!node) {
36 // ๋ฉ๋ชจ๋ฆฌ ํ ๋น ์คํจ ์ ์ด๋ฏธ ์์ฑ๋ ๋
ธ๋๋ค ํด์
37 snake_destroy(snake);
38 return NULL;
39 }
40
41 // ๋ฐฉํฅ์ ๋ฐ๋ผ ์ด๊ธฐ ์์น ์ค์
42 node->pos.x = start_x;
43 node->pos.y = start_y;
44
45 switch (initial_dir) {
46 case DIR_RIGHT:
47 node->pos.x -= i;
48 break;
49 case DIR_LEFT:
50 node->pos.x += i;
51 break;
52 case DIR_DOWN:
53 node->pos.y -= i;
54 break;
55 case DIR_UP:
56 node->pos.y += i;
57 break;
58 }
59
60 node->next = NULL;
61
62 // ์ฐ๊ฒฐ ๋ฆฌ์คํธ์ ์ถ๊ฐ
63 if (snake->head == NULL) {
64 // ์ฒซ ๋ฒ์งธ ๋
ธ๋
65 snake->head = node;
66 snake->tail = node;
67 } else {
68 // ๊ผฌ๋ฆฌ์ ์ถ๊ฐ
69 snake->tail->next = node;
70 snake->tail = node;
71 }
72 snake->length++;
73 }
74
75 return snake;
76}
77
78/**
79 * ๋ฑ ๋ฉ๋ชจ๋ฆฌ ํด์
80 *
81 * @param snake ํด์ ํ ๋ฑ ํฌ์ธํฐ
82 */
83void snake_destroy(Snake* snake) {
84 if (!snake) return;
85
86 SnakeNode* current = snake->head;
87 while (current) {
88 SnakeNode* next = current->next;
89 free(current);
90 current = next;
91 }
92 free(snake);
93}
94
95// ============ ๋ฑ ์ ์ด ============
96
97/**
98 * ๋ฑ์ ๋ฐฉํฅ ๋ณ๊ฒฝ
99 * ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก๋ ๋ณ๊ฒฝํ ์ ์์ (์๊ธฐ ๋ชธ๊ณผ ์ถฉ๋ ๋ฐฉ์ง)
100 *
101 * @param snake ๋ฑ ํฌ์ธํฐ
102 * @param new_dir ์๋ก์ด ๋ฐฉํฅ
103 */
104void snake_change_direction(Snake* snake, Direction new_dir) {
105 if (!snake) return;
106
107 // ํ์ฌ ์งํ๋ฐฉํฅ์ ๋ฐ๋๋ก๋ ๋ชป ๊ฐ
108 if (IS_OPPOSITE_DIR(snake->dir, new_dir)) {
109 return;
110 }
111
112 snake->dir = new_dir;
113}
114
115/**
116 * ๋ค์ ๋จธ๋ฆฌ ์์น ๊ณ์ฐ (์ค์ ์ด๋์ ํ์ง ์์)
117 *
118 * @param snake ๋ฑ ํฌ์ธํฐ
119 * @return ๋ค์ ๋จธ๋ฆฌ๊ฐ ์์นํ ์ขํ
120 */
121Point snake_next_head_position(const Snake* snake) {
122 Point next = snake->head->pos;
123
124 switch (snake->dir) {
125 case DIR_UP:
126 next.y--;
127 break;
128 case DIR_DOWN:
129 next.y++;
130 break;
131 case DIR_LEFT:
132 next.x--;
133 break;
134 case DIR_RIGHT:
135 next.x++;
136 break;
137 }
138
139 return next;
140}
141
142/**
143 * ๋ฑ ์ด๋
144 * ๋จธ๋ฆฌ๋ฅผ ํ ์นธ ์์ผ๋ก ์ด๋ํ๊ณ , ์์์ ๋จน์ง ์์์ผ๋ฉด ๊ผฌ๋ฆฌ ์ ๊ฑฐ
145 *
146 * @param snake ๋ฑ ํฌ์ธํฐ
147 * @param food_pos ์์ ์์น
148 * @return true = ์์์ ๋จน์, false = ์์์ ๋จน์ง ์์
149 */
150bool snake_move(Snake* snake, Point food_pos) {
151 if (!snake || !snake->head) return false;
152
153 // ๋ค์ ๋จธ๋ฆฌ ์์น ๊ณ์ฐ
154 Point next = snake_next_head_position(snake);
155
156 // ์ ๋จธ๋ฆฌ ๋
ธ๋ ์์ฑ
157 SnakeNode* new_head = malloc(sizeof(SnakeNode));
158 if (!new_head) {
159 return false; // ๋ฉ๋ชจ๋ฆฌ ํ ๋น ์คํจ
160 }
161
162 new_head->pos = next;
163 new_head->next = snake->head;
164 snake->head = new_head;
165 snake->length++;
166
167 // ์์์ ๋จน์๋์ง ํ์ธ
168 if (POINT_EQUALS(next, food_pos)) {
169 // ์์์ ๋จน์์ผ๋ฉด ๊ผฌ๋ฆฌ๋ฅผ ์ ์ง (๊ธธ์ด ์ฆ๊ฐ)
170 return true;
171 }
172
173 // ์์์ ๋จน์ง ์์์ผ๋ฉด ๊ผฌ๋ฆฌ ์ ๊ฑฐ
174 if (snake->length > 1) {
175 // ๊ผฌ๋ฆฌ ์ด์ ๋
ธ๋ ์ฐพ๊ธฐ
176 SnakeNode* current = snake->head;
177 while (current->next != snake->tail) {
178 current = current->next;
179 }
180
181 // ๊ผฌ๋ฆฌ ์ ๊ฑฐ
182 free(snake->tail);
183 snake->tail = current;
184 snake->tail->next = NULL;
185 snake->length--;
186 }
187
188 return false;
189}
190
191// ============ ์ถฉ๋ ๊ฒ์ฌ ============
192
193/**
194 * ๋ฑ์ด ๋ฒฝ์ ๋ถ๋ชํ๋์ง ํ์ธ
195 *
196 * @param snake ๋ฑ ํฌ์ธํฐ
197 * @return true = ๋ฒฝ ์ถฉ๋, false = ์ถฉ๋ ์์
198 */
199bool snake_hits_wall(const Snake* snake) {
200 if (!snake || !snake->head) return false;
201
202 Point head = snake->head->pos;
203
204 // ํ
๋๋ฆฌ์ ๋ฟ์ผ๋ฉด ์ถฉ๋
205 return (head.x <= 0 || head.x >= SCREEN_WIDTH - 1 ||
206 head.y <= 0 || head.y >= SCREEN_HEIGHT - 1);
207}
208
209/**
210 * ๋ฑ์ด ์๊ธฐ ๋ชธ์ ๋ถ๋ชํ๋์ง ํ์ธ
211 *
212 * @param snake ๋ฑ ํฌ์ธํฐ
213 * @return true = ์๊ธฐ ๋ชธ ์ถฉ๋, false = ์ถฉ๋ ์์
214 */
215bool snake_hits_self(const Snake* snake) {
216 if (!snake || !snake->head) return false;
217
218 Point head = snake->head->pos;
219 SnakeNode* current = snake->head->next; // ๋จธ๋ฆฌ ๋ค์ ๋
ธ๋๋ถํฐ ํ์ธ
220
221 while (current) {
222 if (POINT_EQUALS(head, current->pos)) {
223 return true;
224 }
225 current = current->next;
226 }
227
228 return false;
229}
230
231/**
232 * ํน์ ์์น์ ๋ฑ์ด ์๋์ง ํ์ธ
233 * ์์ ์์ฑ ์ ๋ฑ๊ณผ ๊ฒน์น์ง ์๋๋ก ํ ๋ ์ฌ์ฉ
234 *
235 * @param snake ๋ฑ ํฌ์ธํฐ
236 * @param x X ์ขํ
237 * @param y Y ์ขํ
238 * @return true = ๋ฑ์ด ํด๋น ์์น์ ์์, false = ์์
239 */
240bool snake_occupies_position(const Snake* snake, int x, int y) {
241 if (!snake) return false;
242
243 SnakeNode* current = snake->head;
244 while (current) {
245 if (current->pos.x == x && current->pos.y == y) {
246 return true;
247 }
248 current = current->next;
249 }
250
251 return false;
252}
253
254// ============ ์ ํธ๋ฆฌํฐ ํจ์ ============
255
256/**
257 * ๋ฑ์ ๊ธธ์ด ๋ฐํ
258 *
259 * @param snake ๋ฑ ํฌ์ธํฐ
260 * @return ๋ฑ์ ๊ธธ์ด
261 */
262int snake_get_length(const Snake* snake) {
263 if (!snake) return 0;
264 return snake->length;
265}
266
267/**
268 * ๋ฑ ๋จธ๋ฆฌ์ ์์น ๋ฐํ
269 *
270 * @param snake ๋ฑ ํฌ์ธํฐ
271 * @return ๋จธ๋ฆฌ ์์น ์ขํ
272 */
273Point snake_get_head_position(const Snake* snake) {
274 Point invalid = {-1, -1};
275 if (!snake || !snake->head) {
276 return invalid;
277 }
278 return snake->head->pos;
279}