Основа для автоматизации игр типа "три в ряд".
"Сокровища Мантесумы", бой в "Небеса" и т.п.вопрос возникал здесь
http://crapware.aidf.org/forum/index.php?topic=359.0 и ВКонтакте
http://vk.com/topic-14410794_29283841Захотелось решить хотя бы основы. Базис для подобных игр.
Скрипт писался для версии
Clickermann v4.9 004Пробовал и отлаживал на Небеса-х.
Скрипт ищет и выстраивает элементы в комбинации. Проходит последовательно по каждому рисунку и определяет возможный ход. По нахождению определяется "вес" хода - сколько фишек совпало. Вес "сквозной" через все изображения, т.е. итоговый ход будет по элементу с большим весом и встретившийся раньше.
Возможно применение общего
COLORMODE и
% совпадения для каждого.
Оптимизации: - один GETSCREEN,
- при нахождении большего веса, варианты с меньшим уже не анализируются,
- поиск начинается с большего веса, чтобы отбросить возможно ненужный поиск меньшего,
- при предварительном отборе вариантов хода, во избежании повторений и заходов в одну комбинацию с разных сторон, отобрал только необходимые и сделал основной поиск парной клетки только вправо-вниз (за исключением 2-х трёшек которые ищутся отдельно),
- в переменные не определяются элементы за краем поля.
Как работает:- Если нужно, определяем положение поля.
- Делаем скрин, если необходимо применяем COLORMODE.
- По очереди обрабатываем все типы элементов (цвета):
- Производим поиск в массив всех элементов данного типа.
- Определяем в какую клетку попадает каждый найденный элемент и формируем псевдо-двумерный массив-карту для элемента. (остановился на этом варианте, т.к. удобнее задавать возможные комбинации, вычислять ход и в дальнейшем масштабировать решения)
- Обходим по очереди все занятые места на поле-карте и в каждой ищем возможные варианты комбинаций. При этом переходим на "локальные" координаты-смещения относительно главной сканируемой клетки.
- Если находим записываем в глобальные переменные значения "массы" и хода (пересчитанное в глобальное смещение
- Пересчитываем глобальные смещения хода в конкретные координаты
- Делаем ход.
Зачем заносил поля вокруг главной анализируемой клетки в переменные когда они и так в переменных массива? Чтобы не пересчитывать необходимый индекс массива для каждого опорного случая. Попробовал сразу на прямую, но после написания проверочных условий на 2 самых простейших комбинации из 3 элементов код выглядел жутко и уже начал немного путаться. Испугавшись того, что будет дальше, решил ввести дополнительные лишние действия для упрощения восприятия. И редактировать/дополнять будет намного проще.
Код модульный разбил на подпрограммы.
Болванку кода можно дописывать под конкретную игру с её особенностями и желание выбора приоритетов в очерёдности ходов. Для мантесумы можно ввести на поле универсальные элементы, которые подходят всем цветам или не подходят никому. Можно отдать предпочтение ходам подряд одного цвета и т.д.
Сам код:
#name "Три в ряд"
// Author: Vint
// Version: 0.4 (09.02.2014)
// For Clickermann v4.9 004
//===== ОПЦИИ ==========================//
//////////////////////////////////////////
// выводить окно лога (1 - Выводить, 0 - Не выводить)
$log = 0
// Размер поля
$max_X = 6
$max_Y = 6
// Размер ячейки
$step = 41
// Координаты левого верхнего угла (или находить потом)
$startcoord_X = 518
$startcoord_Y = 413
// Имена картинок участников
$bmp_1 = "skull.bmp"
$bmp_2 = "kross.bmp"
$bmp_3 = "red.bmp"
$bmp_4 = "green.bmp"
$bmp_5 = "yellow.bmp"
// Префикс. Папка с картинками
$prefix = "textures\"
$colormode = 0 // режим колормода
// " строка для правильного отображения на форуме. Убрать!
//////////////////////////////////////////
// автоопределение ЛВУ в игре
//MOVE($_xmax, $_ymax)
//WAITMS(30)
//GETSCREEN
//IF_PICTURE_IN (0,0, $_xmax,$_ymax, STRCONCAT($prefix,"base.bmp"))
// $startcoord_X = $_return1-119
// $startcoord_Y = $_return2+93
//ELSE
// LOGWRITE ("Не привязались")
// HINTPOPUP("Не привязались", "Внимание!")
// HALT
//END_IF
//==============================================================================
SUB(LOG_c) //==== переменные "с" в лог. Отладка ===============================
LOGWRITE ("$c1 = ", $c1)
LOGWRITE ("$c2 = ", $c2)
LOGWRITE ("$c3 = ", $c3)
LOGWRITE ("$c4 = ", $c4)
LOGWRITE ("$c5 = ", $c5)
LOGWRITE ("$c6 = ", $c6)
LOGWRITE ("$c7 = ", $c7)
LOGWRITE ("$c8 = ", $c8)
LOGWRITE ("$c9 = ", $c9)
LOGWRITE ("$c10 = ", $c10)
LOGWRITE ("$c12 = ", $c12)
LOGWRITE ("$c13 = ", $c13)
LOGWRITE ("$c15 = ", $c15)
LOGWRITE ("$c16 = ", $c16)
LOGWRITE ("$c17 = ", $c17)
LOGWRITE ("$c18 = ", $c18)
LOGWRITE ("$c19 = ", $c19)
LOGWRITE ("$c20 = ", $c20)
LOGWRITE ("$c21 = ", $c21)
LOGWRITE ("$c22 = ", $c22)
LOGWRITE ("$c25 = ", $c25)
LOGWRITE ("$c26 = ", $c26)
LOGWRITE ("$c27 = ", $c27)
END_SUB
//==============================================================================
SUB(FIND, $name_image, $percent, $num) //==== поиск картинки ==================
SCANPICTURE($arr_find, $startcoord_X,$startcoord_Y,$startcoord_X+($max_X*$step), $startcoord_Y+($max_Y*$step), STRCONCAT($prefix,$name_image), -1, $percent)
IF($log=1)
LOGWRITE ("найдено ", $num, "-х элементов: ", ARRSIZE($arr_find)/2)
END_IF
//UNDEFINE($arr_find)
END_SUB
//==============================================================================
SUB(GET, $dif_X, $dif_Y) //==== проверка клетки ===============================
$target_X = $main_X+$dif_X
$target_Y = $main_Y+$dif_Y
IF(($target_X > -1) & ($target_Y > -1) & ($target_X < $max_X) & ($target_Y < $max_Y))
$ret = $map[$target_X+$target_Y*$max_X] // читаем ячейку
ELSE
$ret = -1 // вышли за край поля
END_IF
END_SUB
//==============================================================================
SUB(SET, $tmass, $trun_X,$trun_Y,$trunin_X,$trunin_Y) //=== установка хода ====
IF($tmass > $mass)
$mass = $tmass
$run_X = $trun_X + $main_X
$run_Y = $trun_Y + $main_Y
$runin_X = $trunin_X + $main_X
$runin_Y = $trunin_Y + $main_Y
IF($log=1)
LOGWRITE ("$mass ", $mass)
LOGWRITE ("$main ", $main_X, " / ", $main_Y)
LOGWRITE ("Относит. ", $trun_X, " / ", $trun_Y, ", ", $trunin_X, " / ", $trunin_Y)
END_IF
END_IF
END_SUB
//==============================================================================
SUB(OBRABOTKA_CELL) //==== обработка ячейки главная ===========================
// формат хода (вес, откудаX,Y, кудаX,Y)
// пропускаем поиск, когда уже лучший вариант
IF($mass < 7)
//SET(0,0,0,0,0) // сбрасываем массу
$c1 = 0
$c2 = 0
$c3 = 0
$c4 = 0
$c5 = 0
$c6 = 0
$c7 = 0
$c8 = 0
$c9 = 0
$c10 = 0
$c12 = 0
$c13 = 0
$c15 = 0
$c16 = 0
$c17 = 0
$c18 = 0
$c19 = 0
$c20 = 0
$c21 = 0
$c22 = 0
$c25 = 0
$c26 = 0
$c27 = 0
GET(1,0)
$c1 = $ret
IF($c1 ! -1)
GET(2,0)
$c2 = $ret
GET(3,0)
$c3 = $ret
GET(4,0)
$c4 = $ret
END_IF
GET(-1,0)
$c9 = $ret
IF($c9 ! -1)
GET(-2,0)
$c10 = $ret
END_IF
GET(0,1)
$c15 = $ret
IF($c15 ! -1)
GET(0,3)
$c17 = $ret
GET(0,4)
$c18 = $ret
END_IF
GET(0,-1)
$c12 = $ret
IF($c12 ! -1)
GET(0,-2)
$c13 = $ret
END_IF
IF(($c1 ! -1) & ($c15 ! -1))
GET(2,1)
$c7 = $ret
GET(2,2)
$c8 = $ret
GET(1,2)
$c26 = $ret
END_IF
IF(($c1 ! -1) & ($c12 ! -1))
GET(2,-1)
$c5 = $ret
GET(2,-2)
$c6 = $ret
GET(1,-1)
$c25 = $ret
END_IF
IF(($c9 ! -1) & ($c12 ! -1))
GET(-1,-1)
$c19 = $ret
GET(-1,-2)
$c20 = $ret
END_IF
IF(($c9 ! -1) & ($c15 ! -1))
GET(-1,1)
$c21 = $ret
GET(-1,2)
$c22 = $ret
END_IF
// горизонтальные
IF($c1 = 1)
IF($mass < 7)
IF(($c5=1) & ($c6=1) & ($c7=1) & ($c8=1) & ($c3=1))
SET(7,3,0,2,0)
ELSE
IF(($c19=1) & ($c20=1) & ($c21=1) & ($c22=1) & ($c10=1))
SET(7,-2,0,-1,0)
ELSE
IF(($c3=1) & ($c4=1) & ($c7=1) & ($c8=1) & ($c5=1))
SET(7,2,-1,2,0)
ELSE
IF(($c3=1) & ($c4=1) & ($c5=1) & ($c6=1) & ($c7=1))
SET(7,2,1,2,0)
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 6)
IF(($c5=1) & ($c6=1) & ($c3=1) & ($c7=1))
SET(6,3,0,2,0)
ELSE
IF(($c19=1) & ($c20=1) & ($c10=1) & ($c21=1))
SET(6,-2,0,-1,0)
ELSE
IF(($c7=1) & ($c8=1) & ($c3=1) & ($c5=1))
SET(6,3,0,2,0)
ELSE
IF(($c21=1) & ($c22=1) & ($c19=1) & ($c10=1))
SET(6,-2,0,-1,0)
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 5)
IF(($c5=1) & ($c7=1) & ($c3=1))
SET(5,3,0,2,0)
ELSE
IF(($c19=1) & ($c21=1) & ($c10=1))
SET(5,-2,0,-1,0)
ELSE
IF(($c3=1) & ($c4=1) & ($c5=1))
SET(5,2,-1,2,0)
ELSE
IF(($c3=1) & ($c4=1) & ($c7=1))
SET(5,2,1,2,0)
ELSE
IF(($c5=1) & ($c6=1) & ($c3=1))
SET(5,3,0,2,0)
ELSE
IF(($c5=1) & ($c6=1) & ($c7=1))
SET(5,2,1,2,0)
ELSE
IF(($c19=1) & ($c20=1) & ($c10=1))
SET(5,-2,0,-1,0)
ELSE
IF(($c19=1) & ($c20=1) & ($c21=1))
SET(5,-1,1,-1,0)
ELSE
IF(($c7=1) & ($c8=1) & ($c3=1))
SET(5,3,0,2,0)
ELSE
IF(($c7=1) & ($c8=1) & ($c5=1))
SET(5,2,-1,2,0)
ELSE
IF(($c21=1) & ($c22=1) & ($c10=1))
SET(5,-2,0,-1,0)
ELSE
IF(($c21=1) & ($c22=1) & ($c19=1))
SET(5,-1,-1,-1,0)
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 4)
IF(($c3=1) & ($c5=1))
SET(4,2,-1,2,0)
ELSE
IF(($c3=1) & ($c7=1))
SET(4,2,1,2,0)
ELSE
IF(($c10=1) & ($c19=1))
SET(4,-1,-1,-1,0)
ELSE
IF(($c10=1) & ($c21=1))
SET(4,-1,1,-1,0)
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 3)
IF(($c3=1))
SET(3,3,0,2,0)
ELSE
IF(($c5=1))
SET(3,2,-1,2,0)
ELSE
IF(($c7=1))
SET(3,2,1,2,0)
ELSE
IF(($c10=1))
SET(3,-2,0,-1,0)
ELSE
IF(($c19=1))
SET(3,-1,-1,-1,0)
ELSE
IF(($c21=1))
SET(3,-1,1,-1,0)
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
// вертикальные
IF($c15 = 1)
IF($mass < 5)
IF(($c22=1) & ($c26=1) & ($c17=1))
SET(5,0,3,0,2)
ELSE
IF(($c19=1) & ($c25=1) & ($c13=1))
SET(5,0,-2,0,-1)
ELSE
IF(($c17=1) & ($c18=1) & ($c22=1))
SET(5,-1,2,0,2)
ELSE
IF(($c17=1) & ($c18=1) & ($c26=1))
SET(5,1,2,0,2)
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 4)
IF(($c17=1) & ($c22=1))
SET(4,-1,2,0,2)
ELSE
IF(($c17=1) & ($c26=1))
SET(4,1,2,0,2)
ELSE
IF(($c13=1) & ($c19=1))
SET(4,-1,-1,0,-1)
ELSE
IF(($c13=1) & ($c25=1))
SET(4,1,-1,0,-1)
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 3)
IF(($c13=1))
SET(3,0,-2,0,-1)
ELSE
IF(($c19=1))
SET(3,-1,-1,0,-1)
ELSE
IF(($c25=1))
SET(3,1,-1,0,-1)
ELSE
IF(($c17=1))
SET(3,0,3,0,2)
ELSE
IF(($c22=1))
SET(3,-1,2,0,2)
ELSE
IF(($c26=1))
SET(3,1,2,0,2)
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
END_IF
IF($mass < 3)
GET(1,1)
$c27 = $ret
GET(0,2)
$c16 = $ret
// уникальная тройка гор.
IF(($c2=1) & ($c25=1))
SET(3,1,-1,1,0)
ELSE
IF(($c2=1) & ($c27=1))
SET(3,1,1,1,0)
ELSE
// уникальная тройка вер.
IF(($c16=1) & ($c21=1))
SET(3,-1,1,0,1)
ELSE
IF(($c16=1) & ($c27=1))
SET(3,1,1,0,1)
END_IF
END_IF
END_IF
END_IF
END_IF
// IF(($main_X=4) & ($main_Y=2))
// LOGWRITE ("$main ", $main_X, " / ", $main_Y)
// LOG_c()
// END_IF
END_IF
END_SUB
//==============================================================================
SUB(RUN) //=== ход ============================================================
$CStart_X = ($startcoord_X + $run_X*$step) + RND(10,$step-10)
$CStart_Y = ($startcoord_Y + $run_Y*$step) + RND(10,$step-10)
$CEnd_X = ($startcoord_X + $runin_X*$step) + RND(10,$step-10)
$CEnd_Y = ($startcoord_Y + $runin_Y*$step) + RND(10,$step-10)
LCLICK($CStart_X,$CStart_Y)
WAITMS(200)
LCLICK($CEnd_X,$CEnd_Y)
WAITMS(200)
MOVE($_xmax, $_ymax)
WAITMS(300)
END_SUB
//==============================================================================
SUB(PROCESSING) //==== обработка полученного массива ==========================
// заполняем массив 0
UNDEFINE($map)
FOR($i,$i < $max_X*$max_Y)
ARRPUSH($map, 0)
END_CYC
//LOGWRITE ("размер $map ", ARRSIZE($map))
// строим карту найденных
FOR($i, $i < ARRSIZE($arr_find), 2)
$find_X = $arr_find[$i]
$find_Y = $arr_find[$i+1]
$sost_X = INT(($find_X-$startcoord_X)/$step)
$sost_Y = INT(($find_Y-$startcoord_Y)/$step)
//LOGWRITE ("ячейка ",$sost_X+$sost_Y*$max_X)
//LOGWRITE ("коорд. ",$sost_X, " / ", $sost_Y)
$map[$sost_X+$sost_Y*$max_X] = 1
END_CYC
// выводим поле в лог
IF($log=1)
FOR($i, $i < ARRSIZE($map), $max_X)
LOGWRITE ($map[$i],$map[$i+1],$map[$i+2],$map[$i+3],$map[$i+4],$map[$i+5])
END_CYC
LOGWRITE (" ")
END_IF
UNDEFINE($arr_find)
// обходим поле
FOR($cell, $cell < ARRSIZE($map))
$main_Y = INT($cell/$max_X)
$main_X = $cell-$main_Y*$max_X
//LOGWRITE ("ячейка ", $main_X, " / ", $main_Y)
IF($map[$cell] = 1)
OBRABOTKA_CELL()
END_IF
END_CYC
IF($log=1)
LOGWRITE ("$mass ", $mass)
LOGWRITE ("Лучший на цвет ", $run_X, " / ", $run_Y, ", ", $runin_X, " / ", $runin_Y)
END_IF
END_SUB
//==============================================================================
//===== ПРОГРАММА ==============================================================
LOGCLEAR
IF($log=1)
LOGSHOW (1,$_xmax-335,28) // отображение окна лога
WNDSIZE(WNDFIND("Clickermann - Лог"),336,560) // изменения размеров окна лога 260
END_IF
$start = $_ms
$mass = 0
$run_X = 0
$run_Y = 0
$runin_X = 0
$runin_Y = 0
$ret = 0
// делаем скрин
MOVE($_xmax, $_ymax)
WAITMS(30)
GETSCREEN
IF($colormode ! 0)
COLORMODE($colormode, $startcoord_X,$startcoord_Y,$startcoord_X+($max_X*$step), $startcoord_Y+($max_Y*$step))
END_IF
// ищем все первые элементы и заносим в массив
FIND($bmp_1, 100, 1)
PROCESSING()
// ищем все вторые элементы и заносим в массив
FIND($bmp_2, 75, 2)
PROCESSING()
// ищем все третьи элементы и заносим в массив
FIND($bmp_3, 100, 3)
PROCESSING()
// ищем все четвёртые элементы и заносим в массив
FIND($bmp_4, 100, 4)
PROCESSING()
// ищем все пятые элементы и заносим в массив
FIND($bmp_5, 100, 5)
PROCESSING()
LOGWRITE ("Время выполнения ", $_ms-$start, " мс")
IF($mass ! 0)
RUN()
END_IF
HALT
Схемы отобранных комбинаций и скрипт во вложении.
Некоторые тесты, на которых тренировался из "небеса" здесь:
http://yadi.sk/d/i-qJoA5jHgcNo