Пишем бота для игры. Будем решать задачу с помощью ДП. Для начала введём некоторые переменные:
- state -- закодированное состояние матрицы.
- player -- принимает значения 0 или 1, в зависимости от того, кто сейчас ходит.
Для начала определим всевозможные победные состояния для игроков 0 и 1, пусть этим состояниям будут соответсвовать state_win_0[] и state_win_1[]. Сделать это можно с помощью полного перебора всех вариантов матрицы. Заметим, кстати, что если покрасить матрицу в шахматную раскраску, то при любом ходе все числа будут сохранять свой цвет. Это значит, что все возможные состояния матрицы -- всевозможные перестановки чисел по клеткам одного цвета. Обоснуем это: любые два элемента стоящие рядом по диагонали (они имеют одинаковый цвет) можно переставить местами при отражении в матрице 2 x 2, далее применяя "пузырьковую сортировку" (по сути на декартовом произведении массивов), можем получить любую перестановку. Такие состояния и будем перебирать.
Сначала рассмотрим несколько возможных эвристик для игры, затем поговорим про построение самого массива dp[].
- dp[state][k][player] -- принимает значение 1, если из текущего состояния матрицы state игроку player можно добраться до победы за не более чем k шагов; 0 -- в противном случае.
Предложим алгоритм-эвристику для игры. Пусть боту (без ограничения общности будем считать его player = 1) на вход дан state.
- посмотрим все возможные переходы из state, найдём такое минимальное k, что dp[state][k][1] = 1 и затем найдём переход в такой state_1, что для любого state_2, в который можно перейти из state_1, dp[state_2][k - 2][1] = 1. Выполним переход в данное состояние -- state_1.
- Из построения массива dp[] поиск минимального k может длиться бесконечно долго, если не существует победного алгоритма из данного состояния. В таком случае, ограничимся некоторым k < k_inf (это заранее заданная константа) и будем пытаться спровоцировать соперника на ошибку.
- Для этого попытаемся найти такой state_1, в которой можно перейти из текущего, что dp[state][k][0] = 0 -- для максимального k. То есть сопернику придётся дольше идти до победы, больше вероятность, что он допустит ошибку.
Сначала поймём как можно проинициализировать массив dp[]. Нам известны массивы state_win_0[] и state_win_1[]. Соответственно имеем для элементов из state_win_0[]: dp[state_win_0[i]][k][0] = 1 -- для любого k_inf > k >= 0. Аналогично заполним для игрока с номером 1. Затем будем заполнять массив dp[] следующим образом:
- Пусть заполнено dp[state][k][1] и k_min -- минимальное количество шагов, за которое можно выиграть. Тогда посмотрим в какие состояния state[i] можно попасть из state и заполним: dp[state[i]][k + 1][1] = 1 для всех k >= k_min.
- Аналогично для player = 0.