This commit is contained in:
2025-10-20 19:35:38 +05:00
commit 023ccd03d8
42 changed files with 10007 additions and 0 deletions

269
Program.cs Normal file
View File

@@ -0,0 +1,269 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace PaperRacing
{
// Представляет точку на поле
public record Point(int X, int Y)
{
public static Point operator +(Point a, Point b) => new(a.X + b.X, a.Y + b.Y);
public static Point operator -(Point a, Point b) => new(a.X - b.X, a.Y - b.Y);
public double DistanceTo(Point other)
{
return Math.Sqrt(Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2));
}
}
// Состояние игры (позиция, скорость, посещенные чекпоинты)
public class GameState
{
public Point Position { get; init; }
public Point Velocity { get; init; }
public HashSet<int> VisitedCheckpoints { get; init; }
public List<Point> Path { get; init; }
public GameState(Point position, Point velocity, HashSet<int> visitedCheckpoints, List<Point> path)
{
Position = position;
Velocity = velocity;
VisitedCheckpoints = visitedCheckpoints;
Path = path;
}
// Уникальный ключ для состояния (без учета пути)
public string GetKey()
{
var checkpointsMask = string.Join(",", VisitedCheckpoints.OrderBy(x => x));
return $"{Position.X},{Position.Y}|{Velocity.X},{Velocity.Y}|{checkpointsMask}";
}
}
// Игровое поле
public class RaceTrack
{
private readonly int _width;
private readonly int _height;
private readonly HashSet<Point> _obstacles;
private readonly Dictionary<int, Point> _checkpoints;
private readonly Point _start;
public RaceTrack(int width, int height, Point start, Dictionary<int, Point> checkpoints, HashSet<Point> obstacles)
{
_width = width;
_height = height;
_start = start;
_checkpoints = checkpoints;
_obstacles = obstacles;
}
// Проверка, находится ли точка в границах поля
private bool IsInBounds(Point p) => p.X >= 0 && p.X < _width && p.Y >= 0 && p.Y < _height;
// Проверка пересечения отрезка с препятствиями (алгоритм Брезенхема)
private bool IntersectsObstacle(Point from, Point to)
{
int x0 = from.X, y0 = from.Y;
int x1 = to.X, y1 = to.Y;
int dx = Math.Abs(x1 - x0);
int dy = Math.Abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
while (true)
{
if (_obstacles.Contains(new Point(x0, y0)))
return true;
if (x0 == x1 && y0 == y1)
break;
int e2 = 2 * err;
if (e2 > -dy)
{
err -= dy;
x0 += sx;
}
if (e2 < dx)
{
err += dx;
y0 += sy;
}
}
return false;
}
// Поиск оптимального решения методом BFS
public List<Point>? FindSolution()
{
var queue = new Queue<GameState>();
var visited = new HashSet<string>();
var initialState = new GameState(_start, new Point(0, 0), new HashSet<int>(), new List<Point> { _start });
queue.Enqueue(initialState);
visited.Add(initialState.GetKey());
int iterations = 0;
const int maxIterations = 1000000;
while (queue.Count > 0 && iterations < maxIterations)
{
iterations++;
var current = queue.Dequeue();
// Проверяем, собрали ли все чекпоинты
if (current.VisitedCheckpoints.Count == _checkpoints.Count)
{
Console.WriteLine($"Решение найдено за {iterations} итераций");
Console.WriteLine($"Количество ходов: {current.Path.Count - 1}");
return current.Path;
}
// Генерируем все возможные ускорения (-1, 0, +1 по каждой оси)
for (int dx = -1; dx <= 1; dx++)
{
for (int dy = -1; dy <= 1; dy++)
{
var acceleration = new Point(dx, dy);
var newVelocity = current.Velocity + acceleration;
var newPosition = current.Position + newVelocity;
// Проверяем границы
if (!IsInBounds(newPosition))
continue;
// Проверяем препятствия
if (IntersectsObstacle(current.Position, newPosition))
continue;
// Проверяем чекпоинты
var newCheckpoints = new HashSet<int>(current.VisitedCheckpoints);
foreach (var (id, checkpoint) in _checkpoints)
{
if (!newCheckpoints.Contains(id) && newPosition.Equals(checkpoint))
{
newCheckpoints.Add(id);
}
}
var newPath = new List<Point>(current.Path) { newPosition };
var newState = new GameState(newPosition, newVelocity, newCheckpoints, newPath);
var key = newState.GetKey();
if (!visited.Contains(key))
{
visited.Add(key);
queue.Enqueue(newState);
}
}
}
}
Console.WriteLine($"Решение не найдено после {iterations} итераций");
return null;
}
// Визуализация поля
public void Visualize(List<Point>? path = null)
{
var pathSet = path != null ? new HashSet<Point>(path) : new HashSet<Point>();
for (int y = _height - 1; y >= 0; y--)
{
Console.Write($"{y:00}|");
for (int x = 0; x < _width; x++)
{
var point = new Point(x, y);
if (point.Equals(_start))
Console.Write("S ");
else if (_checkpoints.Values.Contains(point))
Console.Write($"{_checkpoints.First(kv => kv.Value.Equals(point)).Key} ");
else if (_obstacles.Contains(point))
Console.Write("# ");
else if (pathSet.Contains(point))
Console.Write(". ");
else
Console.Write(" ");
}
Console.WriteLine();
}
}
// Показать путь с векторами скорости
public void ShowPath(List<Point> path)
{
Console.WriteLine("\nПуть решения:");
Point? prevVelocity = new Point(0, 0);
for (int i = 0; i < path.Count; i++)
{
Point velocity = i > 0 ? path[i] - path[i - 1] : new Point(0, 0);
Point acceleration = velocity - prevVelocity;
Console.WriteLine($"Шаг {i}: Позиция={path[i]}, Скорость={velocity}, Ускорение={acceleration}");
prevVelocity = velocity;
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Гонки на бумаге ===\n");
// Создаем поле 15x15
int width = 42;
int height = 42;
// Стартовая позиция
var start = new Point(1, 1);
// Чекпоинты (нужно посетить все в любом порядке)
var checkpoints = new Dictionary<int, Point>
{
{ 1, new Point(5, 5) },
{ 2, new Point(10, 10) },
{ 3, new Point(12, 3) }
};
// Препятствия
var obstacles = new HashSet<Point>();
// Горизонтальная стена
for (int x = 3; x <= 8; x++)
obstacles.Add(new Point(x, 7));
// Вертикальная стена
for (int y = 2; y <= 6; y++)
obstacles.Add(new Point(8, y));
// Создаем трек
var track = new RaceTrack(width, height, start, checkpoints, obstacles);
Console.WriteLine("Начальное поле:");
Console.WriteLine("S - старт, 1,2,3 - чекпоинты, # - препятствия\n");
track.Visualize();
Console.WriteLine("\nПоиск решения...\n");
var solution = track.FindSolution();
if (solution != null)
{
Console.WriteLine("\n=== РЕШЕНИЕ НАЙДЕНО ===\n");
track.Visualize(solution);
track.ShowPath(solution);
}
else
{
Console.WriteLine("\nРешение не найдено!");
}
}
}
}