Загрузка данных
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
unsafe class Program
{
const int WIDTH = 30;
const int HEIGHT = 15;
// Звено двусвязного списка (часть тела змейки)
struct Node
{
public int x, y;
public Node* prev;
public Node* next;
}
// Еда
struct Food
{
public int x, y;
}
static Node* head = null; // голова змейки
static Node* tail = null; // хвост змейки
static Food* food = null; // еда
static int dx = 1, dy = 0; // направление движения
static int score = 0;
static Random rnd = new Random();
// Создание нового звена в динамической памяти
static Node* NewNode(int x, int y)
{
Node* n = (Node*)Marshal.AllocHGlobal(sizeof(Node));
n->x = x;
n->y = y;
n->prev = null;
n->next = null;
return n;
}
// Добавить новую голову
static void AddHead(int x, int y)
{
Node* n = NewNode(x, y);
n->next = head;
if (head != null) head->prev = n;
head = n;
if (tail == null) tail = n;
}
// Удалить хвост и освободить память
static void RemoveTail()
{
Node* t = tail;
tail = t->prev;
if (tail != null) tail->next = null;
else head = null;
Marshal.FreeHGlobal((IntPtr)t);
}
// Есть ли змейка в клетке (x, y)
static bool InSnake(int x, int y)
{
for (Node* p = head; p != null; p = p->next)
if (p->x == x && p->y == y) return true;
return false;
}
// Поставить еду на свободную клетку
static void PlaceFood()
{
do
{
food->x = rnd.Next(WIDTH);
food->y = rnd.Next(HEIGHT);
} while (InSnake(food->x, food->y));
}
// Отрисовка поля
static void Draw()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Счёт: " + score + " ");
sb.AppendLine("+" + new string('-', WIDTH) + "+");
for (int y = 0; y < HEIGHT; y++)
{
sb.Append('|');
for (int x = 0; x < WIDTH; x++)
{
if (head->x == x && head->y == y) sb.Append('@');
else if (InSnake(x, y)) sb.Append('o');
else if (food->x == x && food->y == y) sb.Append('*');
else sb.Append(' ');
}
sb.AppendLine("|");
}
sb.AppendLine("+" + new string('-', WIDTH) + "+");
Console.SetCursorPosition(0, 0);
Console.Write(sb.ToString());
}
static void Main()
{
Console.CursorVisible = false;
Console.Clear();
// Змейка и еда в динамической памяти
AddHead(WIDTH / 2, HEIGHT / 2);
food = (Food*)Marshal.AllocHGlobal(sizeof(Food));
PlaceFood();
while (true)
{
Draw();
Thread.Sleep(150);
// Неблокирующее чтение клавиатуры
while (Console.KeyAvailable)
{
ConsoleKey key = Console.ReadKey(true).Key;
if (key == ConsoleKey.LeftArrow && dx != 1) { dx = -1; dy = 0; }
else if (key == ConsoleKey.RightArrow && dx != -1) { dx = 1; dy = 0; }
else if (key == ConsoleKey.UpArrow && dy != 1) { dx = 0; dy = -1; }
else if (key == ConsoleKey.DownArrow && dy != -1) { dx = 0; dy = 1; }
}
int nx = head->x + dx;
int ny = head->y + dy;
// Столкновение с границей или с собой
if (nx < 0 || nx >= WIDTH || ny < 0 || ny >= HEIGHT || InSnake(nx, ny))
break;
AddHead(nx, ny);
if (nx == food->x && ny == food->y)
{
score++; // съели еду: хвост не удаляем
PlaceFood();
}
else
{
RemoveTail(); // еды нет: хвост удаляем
}
}
// Освобождение памяти
while (head != null) RemoveTail();
Marshal.FreeHGlobal((IntPtr)food);
Console.SetCursorPosition(0, HEIGHT + 4);
Console.WriteLine("Игра окончена! Счёт: " + score);
Console.CursorVisible = true;
}
}