2012-01-11 16:38:00 +02:00
|
|
|
|
package main;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Класс логики бота.
|
2012-01-11 16:38:00 +02:00
|
|
|
|
* @author aNNiMON
|
|
|
|
|
*/
|
|
|
|
|
public class BotFloodIt {
|
|
|
|
|
|
2012-01-11 16:55:25 +02:00
|
|
|
|
/* Количество цветов в игре */
|
2012-01-11 16:38:00 +02:00
|
|
|
|
private static final int MAX_COLORS = 6;
|
2012-01-11 16:55:25 +02:00
|
|
|
|
/* На сколько шагов вперёд просчитывать ход */
|
2012-01-11 16:38:00 +02:00
|
|
|
|
private static final int FILL_STEPS = 4;
|
|
|
|
|
|
2012-01-11 16:55:25 +02:00
|
|
|
|
/* Игровое поле */
|
2012-01-11 16:38:00 +02:00
|
|
|
|
private byte[][] table;
|
2012-01-11 16:55:25 +02:00
|
|
|
|
/* Цвета, соответствующие ID */
|
2012-01-11 16:38:00 +02:00
|
|
|
|
private int[] colors;
|
|
|
|
|
|
|
|
|
|
public BotFloodIt(int[][] table) {
|
|
|
|
|
colors = new int[MAX_COLORS];
|
|
|
|
|
for (int i = 0; i < colors.length; i++) {
|
|
|
|
|
colors[i] = -1;
|
|
|
|
|
}
|
|
|
|
|
this.table = colorsToIds(table);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Получить цвета клеток в палитре
|
|
|
|
|
* @return массив цветов RGB
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
public int[] getColors() {
|
|
|
|
|
return colors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Получить последовательность заливки цветов
|
|
|
|
|
* @return массив с идентификаторами цветов для заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
public byte[] getFillSequence() {
|
|
|
|
|
byte[][] copyTable = copyTable(table);
|
|
|
|
|
ArrayList<Byte> seq = new ArrayList<Byte>();
|
|
|
|
|
while(!gameCompleted(copyTable)) {
|
|
|
|
|
seq.add(getNextFillColor(copyTable));
|
|
|
|
|
}
|
|
|
|
|
byte[] out = new byte[seq.size()];
|
|
|
|
|
for (int i = 0; i < out.length; i++) {
|
|
|
|
|
out[i] = seq.get(i).byteValue();
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Получить индекс следующего цвета для заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private byte getNextFillColor(byte[][] table) {
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Количество вариантов заливок
|
2012-01-11 16:38:00 +02:00
|
|
|
|
int fillSize = (int) Math.pow(MAX_COLORS, FILL_STEPS);
|
|
|
|
|
int[] fillRate = new int[fillSize];
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Заполняем значениями степени заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
int[] fillPow = new int[FILL_STEPS];
|
|
|
|
|
for (int i = 0; i < FILL_STEPS; i++) {
|
|
|
|
|
fillPow[i] = (int) Math.pow(MAX_COLORS, i);
|
|
|
|
|
}
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Заливаем FILL_STEPS раз MAX_COLORS вариантов
|
2012-01-11 16:38:00 +02:00
|
|
|
|
for (int i = 0; i < fillSize; i++) {
|
|
|
|
|
byte[][] iteration = copyTable(table);
|
|
|
|
|
for (int j = 0; j < FILL_STEPS; j++) {
|
|
|
|
|
byte fillColor = (byte) (i / fillPow[j] % MAX_COLORS);
|
|
|
|
|
fillTable(iteration, fillColor);
|
|
|
|
|
}
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Подсчитываем число залитых ячеек
|
2012-01-11 16:38:00 +02:00
|
|
|
|
fillRate[i] = getFillCount(iteration);
|
|
|
|
|
}
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Теперь ищем максимально залитый участок из FILL_STEPS итераций заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
int maxArea = fillRate[0];
|
|
|
|
|
int maxColor = 0;
|
|
|
|
|
for (int i = 1; i < fillSize; i++) {
|
|
|
|
|
if (fillRate[i] > maxArea) {
|
|
|
|
|
maxColor = i;
|
|
|
|
|
maxArea = fillRate[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Получаем цвет с наибольшей площадью дальнейшей заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
byte colorID = (byte) (maxColor % MAX_COLORS);
|
|
|
|
|
fillTable(table, colorID);
|
|
|
|
|
return colorID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Преобразование массива с цветами в массив с идентификаторами
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private byte[][] colorsToIds(int[][] tableColor) {
|
|
|
|
|
int size = tableColor.length;
|
|
|
|
|
byte[][] out = new byte[size][size];
|
2012-01-11 16:55:25 +02:00
|
|
|
|
int colorsReaded = 1; // сколько цветов распознано
|
2012-01-11 16:38:00 +02:00
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
for (int j = 0; j < size; j++) {
|
|
|
|
|
int color = tableColor[i][j];
|
|
|
|
|
for (byte k = 0; k < colorsReaded; k++) {
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Добавляем цвет в палитру
|
2012-01-11 16:38:00 +02:00
|
|
|
|
if (colors[k] == -1) {
|
|
|
|
|
colors[k] = color;
|
|
|
|
|
colorsReaded++;
|
|
|
|
|
if (colorsReaded > MAX_COLORS) colorsReaded = MAX_COLORS;
|
|
|
|
|
}
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Если цвет уже в палитре, то присваиваем ему ID
|
2012-01-11 16:38:00 +02:00
|
|
|
|
if (color == colors[k]) {
|
|
|
|
|
out[i][j] = k;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Залить заданное поле цветом color
|
|
|
|
|
* @param table игровое поле для заливки
|
|
|
|
|
* @param color цвет заливки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private void fillTable(byte[][] table, byte color) {
|
|
|
|
|
if (table[0][0] == color) return;
|
|
|
|
|
fill(table, 0, 0, table[0][0], color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Заливка поля по координатам
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private void fill(byte[][] table, int x, int y, byte prevColor, byte color) {
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Проверка на выход за границы игрового поля
|
2012-01-11 16:38:00 +02:00
|
|
|
|
if ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return;
|
|
|
|
|
if (table[x][y] == prevColor) {
|
|
|
|
|
table[x][y] = color;
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Заливаем смежные области
|
2012-01-11 16:38:00 +02:00
|
|
|
|
fill(table, x-1, y, prevColor, color);
|
|
|
|
|
fill(table, x+1, y, prevColor, color);
|
|
|
|
|
fill(table, x, y-1, prevColor, color);
|
|
|
|
|
fill(table, x, y+1, prevColor, color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Получить количество залитых ячеек
|
|
|
|
|
* @param table игровое поле
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private int getFillCount(byte[][] table) {
|
|
|
|
|
return getCount(table, 0, 0, table[0][0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Подсчет залитых ячеек по координатам
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private int getCount(byte[][] table, int x, int y, byte color) {
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Проверка на выход за границы игрового поля
|
2012-01-11 16:38:00 +02:00
|
|
|
|
if ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return 0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
if (table[x][y] == color) {
|
|
|
|
|
table[x][y] = -1;
|
|
|
|
|
count = 1;
|
2012-01-11 16:55:25 +02:00
|
|
|
|
// Считаем смежные ячейки
|
2012-01-11 16:38:00 +02:00
|
|
|
|
count += getCount(table, x-1, y, color);
|
|
|
|
|
count += getCount(table, x+1, y, color);
|
|
|
|
|
count += getCount(table, x, y-1, color);
|
|
|
|
|
count += getCount(table, x, y+1, color);
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Проверка, залита ли вся область одним цветом
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private boolean gameCompleted(byte[][] table) {
|
|
|
|
|
byte color = table[0][0];
|
|
|
|
|
int size = table.length;
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
for (int j = 0; j < size; j++) {
|
|
|
|
|
if (table[i][j] != color) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-11 16:55:25 +02:00
|
|
|
|
* Копирование массива игрового поля
|
2012-01-11 16:38:00 +02:00
|
|
|
|
*/
|
|
|
|
|
private byte[][] copyTable(byte[][] table) {
|
|
|
|
|
int size = table.length;
|
|
|
|
|
byte[][] out = new byte[size][size];
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
System.arraycopy(table[i], 0, out[i], 0, size);
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
}
|