Модель игрока-человека в игре | WPF MVVM

192
09 мая 2017, 02:26

Имеется модель некоторой "настольной" игры (привожу упрощенно), например, крестики-нолики, в ней определен интерфейс игрока:

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. Человек?

Answer 1

Набросал пока такое решение:

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.

Надеюсь, кто-нибудь прокомментирует мой вариант и укажет на его недостатки или может кого-то мой ответ натолкнет на мысли и он напишет свой ответ. Буду рад любым комментариям и замечаниям.

READ ALSO
Почему клиент не хочет получать данные?

Почему клиент не хочет получать данные?

Метод Listen запускается в отдельном потоке, должен получать данные с сервера и проигрывать их(это звук)Но вылазит исключение: Необработанное...

202
Как добавить в ListView определенные файлы

Как добавить в ListView определенные файлы

Как при помощи Button сделать возможность добавлять сразу множество файлов только формата mp3 в компонент ListView?

242
Инициализатор вложенного свойства

Инициализатор вложенного свойства

Я не понимаю это баг какой то, или разработчики языка просто забыли добавить это свойство? В интернете по этому поводу только одна тема в которой...

223
Как сохранить изображение с PictureBox

Как сохранить изображение с PictureBox

Хочу сохранить изображение с PictureBox, но постоянно сохраняется только чёрное изображение или вылетает ошибкаПодскажите в чём проблема

271