Имеется модель некоторой "настольной" игры (привожу упрощенно), например, крестики-нолики, в ней определен интерфейс игрока:
interface IPlayer
{
Position GetMove(GameField field);
}
вспомогательные классы (Position, GameField, GameState и т. д.) и, собственно, сам класс игры:
class Game
{
public GameField Field { get; private set; }
public GameState State { get; private set; }
IPlayer first, second;
public IPlayer CurrentPlayer { get; private set; }
public Game(IPlayer first, IPlayer second)
{
this.first = first;
this.second = second;
Reset();
}
public void Reset()
{
Field = new Field();
State = GameState.Proceed;
CurrentPlayer = first;
}
public void NextMove()
{
... // Проверка состояния игры и выброс исключения если ходы уже невозможны
var position = CurrentPlayer.GetMove(Field.Copy());
... // Проверка корректности хода и его применение или выброс исключения
... // Проверка окончания игры и смена статуса
... // Смена текущего игрока
}
}
Игровой цикл, например, в консольном приложении мог бы выглядеть как-то так:
ComputerPlayer first = new ComputerPlayer();
HumanPlayer second = new HumanPlayer();
Game game = new Game();
ShowField(game.Field);
while (game.State != GameState.Completed)
{
game.NextMove();
ShowField(game.Field);
}
С игроком-компьютером всё просто - реализуем в его коде алгоритм поиска лучшего хода. Он не зависит от представления.
Как быть с игроком-человеком? Он ведь по сути жестко связан с представлением. В консольном приложении я мог бы реализовать его примерно так:
class HumanPlayer : IPlayer
{
public Position GetMove(GameField field)
=> ConvertToPosition(Console.ReadLine());
Position ConvertToPosition(string s)
{
...
}
}
Получается, я должен реализовать игрока в части представления VM+V? Или нужно разделить его как-то на модельную и представленческую части? Как организовать игровой цикл? Как предусмотреть возможность игры Человек vs. Человек?
Набросал пока такое решение:
class HumanPlayer : IPlayer
{
TaskCompletionSource<Position> taskSource;
public Position GetMove(GameField gameField)
{
taskSource = new TaskCompletionSource<Position>();
Position result = taskSource.Task.Result;
taskSource = null;
return result;
}
public void SendPosition(Position position)
=> taskSource?.SetResult(position);
}
При вызове метода GetMove из Game поток, в котором бежит модель блокируется до того момента, пока кто-то (а это будет VM) не подтолкнет его вызовом метода SendPosition.
Надеюсь, кто-нибудь прокомментирует мой вариант и укажет на его недостатки или может кого-то мой ответ натолкнет на мысли и он напишет свой ответ. Буду рад любым комментариям и замечаниям.
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники