Что может заставить это начать просчитываться через некоторое время? - PullRequest
1 голос
/ 06 сентября 2010

Я пытаюсь реализовать NegaMax для игры в шашки.Сейчас я просто тестирую его с глубиной 0, то есть текущий игрок просто оценивает все свои ходы, независимо от того, что другой игрок может сделать дальше.Он отлично работает примерно половину игры (правильно вычисляет баллы), а затем частично начинает выплевывать бессмысленные ответы.

Например, у белых может остаться 1 фигура, а у черных - 5, но он оценит ходы белых как 7, например, когда все они должны быть отрицательными, потому что они проигрывают.Черные могут выиграть на следующем ходу, но они оценят выигрышный ход как -4, хотя это должно быть 1000.

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

private static Move GetBestMove(Color color, Board board, int depth)
{
    var bestMoves = new List<Move>();
    IEnumerable<Move> validMoves = board.GetValidMoves(color);
    int highestScore = int.MinValue;
    Board boardAfterMove;
    int tmpScore;
    var rand = new Random();

    Debug.WriteLine("{0}'s Moves:", color);

    foreach (Move move in validMoves)
    {
        boardAfterMove = board.Clone().ApplyMove(move);

        if (move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())
            tmpScore = NegaMax(color, boardAfterMove, depth);
        else
            tmpScore = -NegaMax(Board.Opposite(color), boardAfterMove, depth);

        Debug.WriteLine("{0}: {1}", move, tmpScore);

        if (tmpScore > highestScore)
        {
            bestMoves.Clear();
            bestMoves.Add(move);
            highestScore = tmpScore;
        }
        else if (tmpScore == highestScore)
        {
            bestMoves.Add(move);
        }
    }

    return bestMoves[rand.Next(bestMoves.Count)];
}

private static int NegaMax(Color color, Board board, int depth)
{
    return BoardScore(color, board);
}

private static int BoardScore(Color color, Board board)
{
    if (!board.GetValidMoves(color).Any()) return -1000;
    return board.OfType<Checker>().Sum(c => (c.Color == color ? 1 : -1) * (c.Class == Class.Man ? 2 : 3));
}

Я выделил состояние доски, которое ему не нравится, на доске 6x6:

 . . .
. w B 
 W . .
. . . 
 . w .
. . W 

w = white, b = black, capital letter = king

Похоже, что это не проблема времени или количества ходов, просто не нравятся конкретные состояния доски.Хотя я не вижу ничего особенного в этом состоянии.

В этом состоянии все 4 хода черных оцениваются как -13.Если вы посмотрите, как я набрал очки, там написано 2 очка на человека, 3 очка на короля, отрицательно, если они принадлежат другому игроку.Похоже, что он рассматривает все фигуры как белые ... это единственный способ получить 13.


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

2: White 
4: White 
6: White 
13: White 
17: White 

Где квадраты доски пронумерованы так:

  00  01  02
03  04  05
  06  07  08
09  10  11
  12  13  14
15  16  17

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


Итак ... теперь я знаю, что цвет неправильный, но только дляBoardScore функция.Моя обычная процедура показа никогда не уловила этого, иначе я бы понял проблему несколько часов назад.Я думаю, что это может быть в функции ApplyMove, что цвет переключается ..

public Board ApplyMove(Move m)
{
    if (m.IsJump)
    {
        bool indented = m.Start % Width < _rowWidth;
        int offset = indented ? 1 : 0;
        int enemy = (m.Start + m.End) / 2 + offset;
        this[m.Color, enemy] = Tile.Empty;
    }

    this[m.Color, m.End] = this[m.Color, m.Start];
    this[m.Color, m.Start] = Tile.Empty;

    var checker = this[m.Color, m.End] as Checker;
    if (m.IsCrowned) checker.Class = Class.King;

    return this;
}

Но это тоже не имеет большого смысла ... кусок просто скопирован изНачальная позиция до конечной позиции.Необходимо выяснить, что такое m.Color ... возможно, это даст больше подсказок!Я чувствую себя детективом.

Ответы [ 2 ]

2 голосов
/ 06 сентября 2010

Учитывая ваше описание, я подозреваю, что данные о цвете фигуры. Если бы он был как-то настроен на что-то неправильное, он бы оценил все как отрицательное.

Я не слишком доволен вашей функцией BoardScore - подобные сложные формулы хороши для сокрытия ошибок и трудны для отладки.

Я бы добавил функцию Checker.Value (Color), чтобы упростить BoardScore и позволить вам более легко просматривать происходящее.

Вы не показали тип данных Color, если он допускает больше, чем черно-белое, искаженное значение может вызвать поведение, которое вы наблюдаете.

Учитывая ваше последнее обновление, я посмотрел на boardAfterMove и убедился, что он генерируется правильно.

Снова отредактируйте: есть два вызова - правильно ли клонируется?

0 голосов
/ 06 сентября 2010

Нашел проблему.

        foreach (char ch in checkers)
        {
            switch (ch)
            {
                case 'w':
                    Add(new Checker(Color.White, Class.Man));
                    break;
                case 'W':
                    Add(new Checker(Color.White, Class.King));
                    break;
                case 'b':
                    Add(new Checker(Color.Black, Class.Man));
                    break;
                case 'B':
                    Add(new Checker(Color.White, Class.King));
                    break;
                default:
                    Add(Tile.Empty);
                    break;
            }
        }

Только случается с Черными Королями. Глупое клонирование !! Почему глубокое копирование не может быть проще?

...