Что может привести к тому, что это начнет просчитываться через некоторое время?

Я пытаюсь реализовать 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

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


Итак... теперь я знаю, что цвет неправильный, но только для функции 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... возможно, это даст больше подсказок! Я чувствую себя детективом.


person mpen    schedule 06.09.2010    source источник
comment
Что это за игра? Шашки? Может быть, вы должны указать это, и желательно где-то в начале для лучшего понимания   -  person Oren A    schedule 06.09.2010
comment
Если повторные вызовы этого метода в конечном итоге дают разные результаты (с теми же входными данными), это должно быть связано с внешним состоянием. Мы не можем видеть, как построен ваш класс Board (мы не знаем, как вычисляются Board.GetValidMoves(color) или Board.GetJumps(color)), но я предполагаю, что его состояние медленно портится .   -  person Kirk Woll    schedule 06.09.2010
comment
@Kirk: Единственное, что должно измениться, — это состояние доски. Кажется, я только что определил, что это что-то в состоянии доски, что ему не нравится, но я понятия не имею, что именно. Каждое состояние доски должно оцениваться одинаково...   -  person mpen    schedule 06.09.2010
comment
Я склонен согласиться с Кирком. Вы пробовали распечатать плату и посмотреть, что там происходит? Где именно начинается бардак?   -  person Oren A    schedule 06.09.2010
comment
@Oren: Ну да .. Я только что обнаружил шаткое состояние доски ... которое я добавил к вопросу ... Я собираюсь попытаться выяснить, правильно ли он теперь считывает цвета ..   -  person mpen    schedule 06.09.2010
comment
@Mark: GL (-: держите нас в курсе (-:   -  person Oren A    schedule 06.09.2010
comment
@Марк, я не думаю, что ты сможешь сделать tmpScore = -NegaMax(Board.Opposite(color), boardAfterMove, depth);. Если предполагается сделать это значение отрицательным, попробуйте -1 * NegaMax(...   -  person Jim Schubert    schedule 06.09.2010
comment
@Jim: Почему -someFunc(...) не должно работать? Я сам использовал эту конструкцию раньше, и она всегда давала ожидаемый ответ.   -  person Frank    schedule 06.09.2010
comment
Отладка ЯВЛЯЕТСЯ детективом. Удивительно ли, что вы чувствуете себя таковым?   -  person Loren Pechtel    schedule 06.09.2010
comment
@Novox: я обнаружил, что отсутствие указания -(someMethod()) или -1 * someMethod() иногда приводит к неожиданным результатам. Я не знаю точно, почему, и я всегда предполагал, что - оптимизируется неправильно.   -  person Jim Schubert    schedule 07.09.2010
comment
@ Джим: Не думаю, что это так. Он правильно отрицал это (я проверял до и после). @Loren: Нет... это не удивительно... но обычно ошибки немного более очевидны и их легко отследить - полицейский может раскрыть эти дела;)   -  person mpen    schedule 07.09.2010


Ответы (2)


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

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

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

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

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

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

person Loren Pechtel    schedule 06.09.2010
comment
Нет... это было неправильное клонирование. Хорошая находка, сэр! Он сломался бы только в том случае, если бы на доске был черный король, из-за чего его было трудно найти. Я расширил эту функцию boardscore до цикла for и разбил ее на части при тестировании. - person mpen; 06.09.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;
            }
        }

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

person mpen    schedule 06.09.2010