snake.c

Download
c 280 lines 6.5 KB
  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}