Flood-It-Bot/main/BotFloodIt.java
2012-01-11 16:55:25 +02:00

198 lines
7.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main;
import java.util.ArrayList;
/**
* Класс логики бота.
* @author aNNiMON
*/
public class BotFloodIt {
/* Количество цветов в игре */
private static final int MAX_COLORS = 6;
/* На сколько шагов вперёд просчитывать ход */
private static final int FILL_STEPS = 4;
/* Игровое поле */
private byte[][] table;
/* Цвета, соответствующие ID */
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);
}
/**
* Получить цвета клеток в палитре
* @return массив цветов RGB
*/
public int[] getColors() {
return colors;
}
/**
* Получить последовательность заливки цветов
* @return массив с идентификаторами цветов для заливки
*/
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;
}
/*
* Получить индекс следующего цвета для заливки
*/
private byte getNextFillColor(byte[][] table) {
// Количество вариантов заливок
int fillSize = (int) Math.pow(MAX_COLORS, FILL_STEPS);
int[] fillRate = new int[fillSize];
// Заполняем значениями степени заливки
int[] fillPow = new int[FILL_STEPS];
for (int i = 0; i < FILL_STEPS; i++) {
fillPow[i] = (int) Math.pow(MAX_COLORS, i);
}
// Заливаем FILL_STEPS раз MAX_COLORS вариантов
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);
}
// Подсчитываем число залитых ячеек
fillRate[i] = getFillCount(iteration);
}
// Теперь ищем максимально залитый участок из FILL_STEPS итераций заливки
int maxArea = fillRate[0];
int maxColor = 0;
for (int i = 1; i < fillSize; i++) {
if (fillRate[i] > maxArea) {
maxColor = i;
maxArea = fillRate[i];
}
}
// Получаем цвет с наибольшей площадью дальнейшей заливки
byte colorID = (byte) (maxColor % MAX_COLORS);
fillTable(table, colorID);
return colorID;
}
/*
* Преобразование массива с цветами в массив с идентификаторами
*/
private byte[][] colorsToIds(int[][] tableColor) {
int size = tableColor.length;
byte[][] out = new byte[size][size];
int colorsReaded = 1; // сколько цветов распознано
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++) {
// Добавляем цвет в палитру
if (colors[k] == -1) {
colors[k] = color;
colorsReaded++;
if (colorsReaded > MAX_COLORS) colorsReaded = MAX_COLORS;
}
// Если цвет уже в палитре, то присваиваем ему ID
if (color == colors[k]) {
out[i][j] = k;
break;
}
}
}
}
return out;
}
/**
* Залить заданное поле цветом color
* @param table игровое поле для заливки
* @param color цвет заливки
*/
private void fillTable(byte[][] table, byte color) {
if (table[0][0] == color) return;
fill(table, 0, 0, table[0][0], color);
}
/*
* Заливка поля по координатам
*/
private void fill(byte[][] table, int x, int y, byte prevColor, byte color) {
// Проверка на выход за границы игрового поля
if ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return;
if (table[x][y] == prevColor) {
table[x][y] = color;
// Заливаем смежные области
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);
}
}
/**
* Получить количество залитых ячеек
* @param table игровое поле
*/
private int getFillCount(byte[][] table) {
return getCount(table, 0, 0, table[0][0]);
}
/*
* Подсчет залитых ячеек по координатам
*/
private int getCount(byte[][] table, int x, int y, byte color) {
// Проверка на выход за границы игрового поля
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;
// Считаем смежные ячейки
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;
}
/*
* Проверка, залита ли вся область одним цветом
*/
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;
}
/*
* Копирование массива игрового поля
*/
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;
}
}