Change encoding
This commit is contained in:
parent
59fdc4a3c0
commit
b2473cdc2e
@ -3,19 +3,19 @@ package main;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс логики бота.
|
* Класс логики бота.
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public class BotFloodIt {
|
public class BotFloodIt {
|
||||||
|
|
||||||
/* Количество цветов в игре */
|
/* Количество цветов в игре */
|
||||||
private static final int MAX_COLORS = 6;
|
private static final int MAX_COLORS = 6;
|
||||||
/* На сколько шагов вперёд просчитывать ход */
|
/* На сколько шагов вперёд просчитывать ход */
|
||||||
private static final int FILL_STEPS = 4;
|
private static final int FILL_STEPS = 4;
|
||||||
|
|
||||||
/* Игровое поле */
|
/* Игровое поле */
|
||||||
private byte[][] table;
|
private byte[][] table;
|
||||||
/* Цвета, соответствующие ID */
|
/* Цвета, соответствующие ID */
|
||||||
private int[] colors;
|
private int[] colors;
|
||||||
|
|
||||||
public BotFloodIt(int[][] table) {
|
public BotFloodIt(int[][] table) {
|
||||||
@ -27,16 +27,16 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить цвета клеток в палитре
|
* Получить цвета клеток в палитре
|
||||||
* @return массив цветов RGB
|
* @return массив цветов RGB
|
||||||
*/
|
*/
|
||||||
public int[] getColors() {
|
public int[] getColors() {
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить последовательность заливки цветов
|
* Получить последовательность заливки цветов
|
||||||
* @return массив с идентификаторами цветов для заливки
|
* @return массив с идентификаторами цветов для заливки
|
||||||
*/
|
*/
|
||||||
public byte[] getFillSequence() {
|
public byte[] getFillSequence() {
|
||||||
byte[][] copyTable = copyTable(table);
|
byte[][] copyTable = copyTable(table);
|
||||||
@ -52,28 +52,28 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Получить индекс следующего цвета для заливки
|
* Получить индекс следующего цвета для заливки
|
||||||
*/
|
*/
|
||||||
private byte getNextFillColor(byte[][] table) {
|
private byte getNextFillColor(byte[][] table) {
|
||||||
// Количество вариантов заливок
|
// Количество вариантов заливок
|
||||||
int fillSize = (int) Math.pow(MAX_COLORS, FILL_STEPS);
|
int fillSize = (int) Math.pow(MAX_COLORS, FILL_STEPS);
|
||||||
int[] fillRate = new int[fillSize];
|
int[] fillRate = new int[fillSize];
|
||||||
// Заполняем значениями степени заливки
|
// Заполняем значениями степени заливки
|
||||||
int[] fillPow = new int[FILL_STEPS];
|
int[] fillPow = new int[FILL_STEPS];
|
||||||
for (int i = 0; i < FILL_STEPS; i++) {
|
for (int i = 0; i < FILL_STEPS; i++) {
|
||||||
fillPow[i] = (int) Math.pow(MAX_COLORS, i);
|
fillPow[i] = (int) Math.pow(MAX_COLORS, i);
|
||||||
}
|
}
|
||||||
// Заливаем FILL_STEPS раз MAX_COLORS вариантов
|
// Заливаем FILL_STEPS раз MAX_COLORS вариантов
|
||||||
for (int i = 0; i < fillSize; i++) {
|
for (int i = 0; i < fillSize; i++) {
|
||||||
byte[][] iteration = copyTable(table);
|
byte[][] iteration = copyTable(table);
|
||||||
for (int j = 0; j < FILL_STEPS; j++) {
|
for (int j = 0; j < FILL_STEPS; j++) {
|
||||||
byte fillColor = (byte) (i / fillPow[j] % MAX_COLORS);
|
byte fillColor = (byte) (i / fillPow[j] % MAX_COLORS);
|
||||||
fillTable(iteration, fillColor);
|
fillTable(iteration, fillColor);
|
||||||
}
|
}
|
||||||
// Подсчитываем число залитых ячеек
|
// Подсчитываем число залитых ячеек
|
||||||
fillRate[i] = getFillCount(iteration);
|
fillRate[i] = getFillCount(iteration);
|
||||||
}
|
}
|
||||||
// Теперь ищем максимально залитый участок из FILL_STEPS итераций заливки
|
// Теперь ищем максимально залитый участок из FILL_STEPS итераций заливки
|
||||||
int maxArea = fillRate[0];
|
int maxArea = fillRate[0];
|
||||||
int maxColor = 0;
|
int maxColor = 0;
|
||||||
for (int i = 1; i < fillSize; i++) {
|
for (int i = 1; i < fillSize; i++) {
|
||||||
@ -82,30 +82,30 @@ public class BotFloodIt {
|
|||||||
maxArea = fillRate[i];
|
maxArea = fillRate[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Получаем цвет с наибольшей площадью дальнейшей заливки
|
// Получаем цвет с наибольшей площадью дальнейшей заливки
|
||||||
byte colorID = (byte) (maxColor % MAX_COLORS);
|
byte colorID = (byte) (maxColor % MAX_COLORS);
|
||||||
fillTable(table, colorID);
|
fillTable(table, colorID);
|
||||||
return colorID;
|
return colorID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Преобразование массива с цветами в массив с идентификаторами
|
* Преобразование массива с цветами в массив с идентификаторами
|
||||||
*/
|
*/
|
||||||
private byte[][] colorsToIds(int[][] tableColor) {
|
private byte[][] colorsToIds(int[][] tableColor) {
|
||||||
int size = tableColor.length;
|
int size = tableColor.length;
|
||||||
byte[][] out = new byte[size][size];
|
byte[][] out = new byte[size][size];
|
||||||
int colorsReaded = 1; // сколько цветов распознано
|
int colorsReaded = 1; // сколько цветов распознано
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
for (int j = 0; j < size; j++) {
|
for (int j = 0; j < size; j++) {
|
||||||
int color = tableColor[i][j];
|
int color = tableColor[i][j];
|
||||||
for (byte k = 0; k < colorsReaded; k++) {
|
for (byte k = 0; k < colorsReaded; k++) {
|
||||||
// Добавляем цвет в палитру
|
// Добавляем цвет в палитру
|
||||||
if (colors[k] == -1) {
|
if (colors[k] == -1) {
|
||||||
colors[k] = color;
|
colors[k] = color;
|
||||||
colorsReaded++;
|
colorsReaded++;
|
||||||
if (colorsReaded > MAX_COLORS) colorsReaded = MAX_COLORS;
|
if (colorsReaded > MAX_COLORS) colorsReaded = MAX_COLORS;
|
||||||
}
|
}
|
||||||
// Если цвет уже в палитре, то присваиваем ему ID
|
// Если цвет уже в палитре, то присваиваем ему ID
|
||||||
if (color == colors[k]) {
|
if (color == colors[k]) {
|
||||||
out[i][j] = k;
|
out[i][j] = k;
|
||||||
break;
|
break;
|
||||||
@ -117,9 +117,9 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Залить заданное поле цветом color
|
* Залить заданное поле цветом color
|
||||||
* @param table игровое поле для заливки
|
* @param table игровое поле для заливки
|
||||||
* @param color цвет заливки
|
* @param color цвет заливки
|
||||||
*/
|
*/
|
||||||
private void fillTable(byte[][] table, byte color) {
|
private void fillTable(byte[][] table, byte color) {
|
||||||
if (table[0][0] == color) return;
|
if (table[0][0] == color) return;
|
||||||
@ -127,14 +127,14 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Заливка поля по координатам
|
* Заливка поля по координатам
|
||||||
*/
|
*/
|
||||||
private void fill(byte[][] table, int x, int y, byte prevColor, byte 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 ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return;
|
||||||
if (table[x][y] == prevColor) {
|
if (table[x][y] == prevColor) {
|
||||||
table[x][y] = color;
|
table[x][y] = color;
|
||||||
// Заливаем смежные области
|
// Заливаем смежные области
|
||||||
fill(table, x-1, y, prevColor, color);
|
fill(table, x-1, y, prevColor, 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);
|
||||||
@ -143,24 +143,24 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить количество залитых ячеек
|
* Получить количество залитых ячеек
|
||||||
* @param table игровое поле
|
* @param table игровое поле
|
||||||
*/
|
*/
|
||||||
private int getFillCount(byte[][] table) {
|
private int getFillCount(byte[][] table) {
|
||||||
return getCount(table, 0, 0, table[0][0]);
|
return getCount(table, 0, 0, table[0][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Подсчет залитых ячеек по координатам
|
* Подсчет залитых ячеек по координатам
|
||||||
*/
|
*/
|
||||||
private int getCount(byte[][] table, int x, int y, byte color) {
|
private int getCount(byte[][] table, int x, int y, byte color) {
|
||||||
// Проверка на выход за границы игрового поля
|
// Проверка на выход за границы игрового поля
|
||||||
if ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return 0;
|
if ( (x < 0) || (y < 0) || (x >= table.length) || (y >= table.length) ) return 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if (table[x][y] == color) {
|
if (table[x][y] == color) {
|
||||||
table[x][y] = -1;
|
table[x][y] = -1;
|
||||||
count = 1;
|
count = 1;
|
||||||
// Считаем смежные ячейки
|
// Считаем смежные ячейки
|
||||||
count += getCount(table, x-1, y, color);
|
count += getCount(table, x-1, y, color);
|
||||||
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);
|
||||||
@ -170,7 +170,7 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Проверка, залита ли вся область одним цветом
|
* Проверка, залита ли вся область одним цветом
|
||||||
*/
|
*/
|
||||||
private boolean gameCompleted(byte[][] table) {
|
private boolean gameCompleted(byte[][] table) {
|
||||||
byte color = table[0][0];
|
byte color = table[0][0];
|
||||||
@ -184,7 +184,7 @@ public class BotFloodIt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Копирование массива игрового поля
|
* Копирование массива игрового поля
|
||||||
*/
|
*/
|
||||||
private byte[][] copyTable(byte[][] table) {
|
private byte[][] copyTable(byte[][] table) {
|
||||||
int size = table.length;
|
int size = table.length;
|
||||||
|
@ -5,32 +5,32 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс обработки изображений.
|
* Класс обработки изображений
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public class ImageUtils {
|
public class ImageUtils {
|
||||||
|
|
||||||
/* За сколько точек мы будем узнавать преобладающий фон */
|
/* За сколько точек мы будем узнавать преобладающий фон */
|
||||||
private static final int MAX_COLOR_POINTS = 50;
|
private static final int MAX_COLOR_POINTS = 50;
|
||||||
|
|
||||||
/* Чувствительность к поиску кнопок */
|
/* Чувствительность к поиску кнопок */
|
||||||
private static final int FIND_BUTTON_TOLERANCE = 20;
|
private static final int FIND_BUTTON_TOLERANCE = 20;
|
||||||
|
|
||||||
/* Изображение окна */
|
/* Изображение окна */
|
||||||
private BufferedImage image;
|
private BufferedImage image;
|
||||||
/* Размер изображения */
|
/* Размер изображения */
|
||||||
private int w, h;
|
private int w, h;
|
||||||
/* Размерность поля */
|
/* Размерность поля */
|
||||||
private int boardSize;
|
private int boardSize;
|
||||||
/* Размер ячеек */
|
/* Размер ячеек */
|
||||||
private int cellSize;
|
private int cellSize;
|
||||||
/* Координата угла игрового поля */
|
/* Координата угла игрового поля */
|
||||||
private Point board;
|
private Point board;
|
||||||
/* Монохромное представление изображения */
|
/* Монохромное представление изображения */
|
||||||
private boolean[] monochrome;
|
private boolean[] monochrome;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор для определения настроек
|
* Конструктор для определения настроек
|
||||||
* @param image
|
* @param image
|
||||||
* @param boardSize
|
* @param boardSize
|
||||||
*/
|
*/
|
||||||
@ -42,7 +42,7 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор для проверки настроек
|
* Конструктор для проверки настроек
|
||||||
* @param image
|
* @param image
|
||||||
* @param boardSize
|
* @param boardSize
|
||||||
* @param cellSize
|
* @param cellSize
|
||||||
@ -59,7 +59,7 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить размер ячейки
|
* Получить размер ячейки
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int getCellSize() {
|
public int getCellSize() {
|
||||||
@ -67,8 +67,8 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить координаты игрового поля
|
* Получить координаты игрового поля
|
||||||
* @return точка с координатами левого верхнего угла поля
|
* @return точка с координатами левого верхнего угла поля
|
||||||
*/
|
*/
|
||||||
public Point getBoardParameters() {
|
public Point getBoardParameters() {
|
||||||
int[] pixels = new int[w * h];
|
int[] pixels = new int[w * h];
|
||||||
@ -79,8 +79,8 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить изображение игрового поля
|
* Получить изображение игрового поля
|
||||||
* @return картинка игрового поля
|
* @return картинка игрового поля
|
||||||
*/
|
*/
|
||||||
public BufferedImage getBoardImage() {
|
public BufferedImage getBoardImage() {
|
||||||
int size = cellSize * boardSize;
|
int size = cellSize * boardSize;
|
||||||
@ -92,34 +92,34 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить координаты кнопок для автоматического нажатия
|
* Получить координаты кнопок для автоматического нажатия
|
||||||
* @param colors массив цветов, по которым будем искать кнопки
|
* @param colors массив цветов, по которым будем искать кнопки
|
||||||
* @return массив координат с точками, или null - если не удалось найти
|
* @return массив координат с точками, или null - если не удалось найти
|
||||||
*/
|
*/
|
||||||
public Point[] getButtons(int[] colors) {
|
public Point[] getButtons(int[] colors) {
|
||||||
Point[] out = new Point[colors.length];
|
Point[] out = new Point[colors.length];
|
||||||
// Размер игрового поля в пикселах
|
// Размер игрового поля в пикселах
|
||||||
int size = boardSize * cellSize;
|
int size = boardSize * cellSize;
|
||||||
// Размеры частей изображения, на которых будем искать кнопки
|
// Размеры частей изображения, на которых будем искать кнопки
|
||||||
Rectangle[] partsOfImage = new Rectangle[] {
|
Rectangle[] partsOfImage = new Rectangle[] {
|
||||||
new Rectangle(0, board.y, board.x, size), // слева от поля
|
new Rectangle(0, board.y, board.x, size), // слева от поля
|
||||||
new Rectangle(0, 0, w, board.y), // сверху от поля
|
new Rectangle(0, 0, w, board.y), // сверху от поля
|
||||||
new Rectangle(board.x+size, board.y,
|
new Rectangle(board.x+size, board.y,
|
||||||
w-board.x-size, size), // справа от поля
|
w-board.x-size, size), // справа от поля
|
||||||
new Rectangle(0, board.y+size,
|
new Rectangle(0, board.y+size,
|
||||||
w, h-board.x-size) // снизу от поля
|
w, h-board.x-size) // снизу от поля
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < partsOfImage.length; i++) {
|
for (int i = 0; i < partsOfImage.length; i++) {
|
||||||
Rectangle rect = partsOfImage[i];
|
Rectangle rect = partsOfImage[i];
|
||||||
BufferedImage part = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
|
BufferedImage part = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
|
||||||
// Вырезаем часть изображения, в котором будем искать
|
// Вырезаем часть изображения, в котором будем искать
|
||||||
boolean found = true;
|
boolean found = true;
|
||||||
for (int j = 0; j < colors.length; j++) {
|
for (int j = 0; j < colors.length; j++) {
|
||||||
if (colors[i] == -1) continue;
|
if (colors[i] == -1) continue;
|
||||||
Point pt = findButton(part, colors[j]);
|
Point pt = findButton(part, colors[j]);
|
||||||
if (pt != null) {
|
if (pt != null) {
|
||||||
// Учитываем смещения относительно частей картинок
|
// Учитываем смещения относительно частей картинок
|
||||||
pt.translate(rect.x, rect.y);
|
pt.translate(rect.x, rect.y);
|
||||||
out[j] = pt;
|
out[j] = pt;
|
||||||
} else {
|
} else {
|
||||||
@ -129,19 +129,19 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
if (found) return out;
|
if (found) return out;
|
||||||
}
|
}
|
||||||
// Не удалось найти все точки
|
// Не удалось найти все точки
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Преобразовать массив цветов в графический вид
|
* Преобразовать массив цветов в графический вид
|
||||||
* @param ids массив идентификаторов последовательности
|
* @param ids массив идентификаторов последовательности
|
||||||
* @param palette массив палитры цветов
|
* @param palette массив палитры цветов
|
||||||
* @return изображение последовательности цветов
|
* @return изображение последовательности цветов
|
||||||
*/
|
*/
|
||||||
public BufferedImage sequenceToImage(byte[] ids, int[] palette) {
|
public BufferedImage sequenceToImage(byte[] ids, int[] palette) {
|
||||||
final int size = 20; // размер каждой ячейки
|
final int size = 20; // размер каждой ячейки
|
||||||
// Разбивать будем по 10 клеток на строку
|
// Разбивать будем по 10 клеток на строку
|
||||||
final int CELLS_IN_ROW = 10;
|
final int CELLS_IN_ROW = 10;
|
||||||
int width = CELLS_IN_ROW * size;
|
int width = CELLS_IN_ROW * size;
|
||||||
if (width == 0) width = size;
|
if (width == 0) width = size;
|
||||||
@ -160,13 +160,13 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Преобразовать цветное изображение в монохромное.
|
* Преобразовать цветное изображение в монохромное.
|
||||||
* Нужно также учесть, что если поле расположено на светлом
|
* Нужно также учесть, что если поле расположено на светлом
|
||||||
* фоне, то необходимо инвертировать изображение, чтобы
|
* фоне, то необходимо инвертировать изображение, чтобы
|
||||||
* получить сплошную белую область на месте поля.
|
* получить сплошную белую область на месте поля.
|
||||||
* @param pixels массив пикселей изображения
|
* @param pixels массив пикселей изображения
|
||||||
* @param value разделяющее значение
|
* @param value разделяющее значение
|
||||||
* @return массив boolean, true - белый, false - чёрный
|
* @return массив boolean, true - белый, false - чёрный
|
||||||
*/
|
*/
|
||||||
private boolean[] threshold(int[] pixels, int value) {
|
private boolean[] threshold(int[] pixels, int value) {
|
||||||
boolean inverse = isBackgroundLight(MAX_COLOR_POINTS);
|
boolean inverse = isBackgroundLight(MAX_COLOR_POINTS);
|
||||||
@ -180,12 +180,12 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получение состояния яркости фона.
|
* Получение состояния яркости фона.
|
||||||
* @param numPoints сколько точек нужно для определения.
|
* @param numPoints сколько точек нужно для определения.
|
||||||
* @return true - фон светлый, false - тёмный
|
* @return true - фон светлый, false - тёмный
|
||||||
*/
|
*/
|
||||||
private boolean isBackgroundLight(int numPoints) {
|
private boolean isBackgroundLight(int numPoints) {
|
||||||
// Получаем numPoints случайных точек
|
// Получаем numPoints случайных точек
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
int[] colors = new int[numPoints];
|
int[] colors = new int[numPoints];
|
||||||
for (int i = 0; i < numPoints; i++) {
|
for (int i = 0; i < numPoints; i++) {
|
||||||
@ -193,7 +193,7 @@ public class ImageUtils {
|
|||||||
int y = rnd.nextInt(h);
|
int y = rnd.nextInt(h);
|
||||||
colors[i] = image.getRGB(x, y);
|
colors[i] = image.getRGB(x, y);
|
||||||
}
|
}
|
||||||
// Находим среднюю яркость всех numPoints точек
|
// Находим среднюю яркость всех numPoints точек
|
||||||
long sum = 0;
|
long sum = 0;
|
||||||
for (int i = 0; i < numPoints; i++) {
|
for (int i = 0; i < numPoints; i++) {
|
||||||
int brightness = getBrightness(colors[i]);
|
int brightness = getBrightness(colors[i]);
|
||||||
@ -204,13 +204,13 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Определить координаты левой верхней ячейки игрового поля.
|
* Определить координаты левой верхней ячейки игрового поля.
|
||||||
* @param boardSize размерность поля (10x10, 14x14 и т.д.)
|
* @param boardSize размерность поля (10x10, 14x14 и т.д.)
|
||||||
* @return координата левого верхнего прямоугольника
|
* @return координата левого верхнего прямоугольника
|
||||||
*/
|
*/
|
||||||
private Point getBoardXY(int boardSize) {
|
private Point getBoardXY(int boardSize) {
|
||||||
/*
|
/*
|
||||||
* Сначала подсчитаем количество белых точек по горизонтали и вертикали
|
* Сначала подсчитаем количество белых точек по горизонтали и вертикали
|
||||||
*/
|
*/
|
||||||
int[] horizontal = new int[h];
|
int[] horizontal = new int[h];
|
||||||
for (int i = 0; i < h; i++) {
|
for (int i = 0; i < h; i++) {
|
||||||
@ -231,15 +231,15 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Затем "отфильтруем" лишнее: подсчитаем среднее значение
|
* Затем "отфильтруем" лишнее: подсчитаем среднее значение
|
||||||
* и на его основе уберём малозначимые строки и столбцы.
|
* и на его основе уберём малозначимые строки и столбцы.
|
||||||
*/
|
*/
|
||||||
horizontal = filterByMean(horizontal);
|
horizontal = filterByMean(horizontal);
|
||||||
vertical = filterByMean(vertical);
|
vertical = filterByMean(vertical);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ищем наибольшую ненулевую последовательность.
|
* Ищем наибольшую ненулевую последовательность.
|
||||||
* Индексы границ последовательности и будут граничными точками поля.
|
* Индексы границ последовательности и будут граничными точками поля.
|
||||||
*/
|
*/
|
||||||
int[] vParam = getParamsFromSequence(horizontal);
|
int[] vParam = getParamsFromSequence(horizontal);
|
||||||
int[] hParam = getParamsFromSequence(vertical);
|
int[] hParam = getParamsFromSequence(vertical);
|
||||||
@ -249,15 +249,15 @@ public class ImageUtils {
|
|||||||
int outY = vParam[0];
|
int outY = vParam[0];
|
||||||
int outWidth = hParam[1];
|
int outWidth = hParam[1];
|
||||||
int outHeight = vParam[1];
|
int outHeight = vParam[1];
|
||||||
// Подсчет размера ячейки
|
// Подсчет размера ячейки
|
||||||
cellSize = Math.max((outWidth / boardSize), (outHeight / boardSize));
|
cellSize = Math.max((outWidth / boardSize), (outHeight / boardSize));
|
||||||
return new Point(outX, outY);
|
return new Point(outX, outY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Фильтр последовательности от малозначимых значений.
|
* Фильтр последовательности от малозначимых значений.
|
||||||
* @param source последовательность вхождений цвета
|
* @param source последовательность вхождений цвета
|
||||||
* @return отфильтрованный массив со значениями 0 и 1
|
* @return отфильтрованный массив со значениями 0 и 1
|
||||||
*/
|
*/
|
||||||
private int[] filterByMean(int[] source) {
|
private int[] filterByMean(int[] source) {
|
||||||
long mean = 0;
|
long mean = 0;
|
||||||
@ -272,9 +272,9 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Поиск самой длинной последовательности в массиве.
|
* Поиск самой длинной последовательности в массиве.
|
||||||
* @param source входная последовательность из нулей и единиц
|
* @param source входная последовательность из нулей и единиц
|
||||||
* @return массив параметров - индекс начала последовательности и её длина
|
* @return массив параметров - индекс начала последовательности и её длина
|
||||||
*/
|
*/
|
||||||
private int[] getParamsFromSequence(int[] source) {
|
private int[] getParamsFromSequence(int[] source) {
|
||||||
int maxStart = 0, start = 0;
|
int maxStart = 0, start = 0;
|
||||||
@ -292,7 +292,7 @@ public class ImageUtils {
|
|||||||
maxLength = length;
|
maxLength = length;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Если предыдущий элемент был нулевым - начинаем новую последовательность
|
// Если предыдущий элемент был нулевым - начинаем новую последовательность
|
||||||
start = i;
|
start = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,14 +300,14 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Поиск координаты кнопки с цветом template
|
* Поиск координаты кнопки с цветом template
|
||||||
* @param img изображение, на котором будем искать
|
* @param img изображение, на котором будем искать
|
||||||
* @param template шаблон цвета
|
* @param template шаблон цвета
|
||||||
* @return координата X. Y, или null если не нашли
|
* @return координата X. Y, или null если не нашли
|
||||||
*/
|
*/
|
||||||
private Point findButton(BufferedImage img, int template) {
|
private Point findButton(BufferedImage img, int template) {
|
||||||
int h2 = img.getHeight() / 2;
|
int h2 = img.getHeight() / 2;
|
||||||
// Искать будем с середины по вертикали, так быстрее найдём
|
// Искать будем с середины по вертикали, так быстрее найдём
|
||||||
for (int y = 0; y < h2; y++) {
|
for (int y = 0; y < h2; y++) {
|
||||||
for (int x = 0; x < img.getWidth(); x++) {
|
for (int x = 0; x < img.getWidth(); x++) {
|
||||||
int color = img.getRGB(x, h2 - y);
|
int color = img.getRGB(x, h2 - y);
|
||||||
@ -320,16 +320,16 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Не нашли
|
// Не нашли
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Проверка на соответствие цветов друг другу
|
* Проверка на соответствие цветов друг другу
|
||||||
* @param color1 первый цвет
|
* @param color1 первый цвет
|
||||||
* @param color2 второй цвет
|
* @param color2 второй цвет
|
||||||
* @param tolerance чувствительность
|
* @param tolerance чувствительность
|
||||||
* @return true - соответствуют, false - нет
|
* @return true - соответствуют, false - нет
|
||||||
*/
|
*/
|
||||||
private boolean isEquals(int color1, int color2, int tolerance) {
|
private boolean isEquals(int color1, int color2, int tolerance) {
|
||||||
if (tolerance < 2) return color1 == color2;
|
if (tolerance < 2) return color1 == color2;
|
||||||
@ -346,9 +346,9 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получение яркости цвета
|
* Получение яркости цвета
|
||||||
* @param color исходный цвет
|
* @param color исходный цвет
|
||||||
* @return яркость (0..255)
|
* @return яркость (0..255)
|
||||||
*/
|
*/
|
||||||
private int getBrightness(int color) {
|
private int getBrightness(int color) {
|
||||||
int qr = (color >> 16) & 0xff;
|
int qr = (color >> 16) & 0xff;
|
||||||
@ -358,8 +358,8 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Получение цвета из монохромного изображения.
|
* Получение цвета из монохромного изображения.
|
||||||
* return true - белый, false - чёрный
|
* return true - белый, false - чёрный
|
||||||
*/
|
*/
|
||||||
private boolean getBWPixel(int x, int y) {
|
private boolean getBWPixel(int x, int y) {
|
||||||
if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return false;
|
if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return false;
|
||||||
|
@ -6,12 +6,12 @@ import java.awt.image.BufferedImage;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Окно приложения.
|
* Окно приложения
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public class RobotFrame extends JFrame {
|
public class RobotFrame extends JFrame {
|
||||||
|
|
||||||
/* Статус работы приложения */
|
/* Статус работы приложения */
|
||||||
private boolean isRunning;
|
private boolean isRunning;
|
||||||
|
|
||||||
private Thread robotAction;
|
private Thread robotAction;
|
||||||
@ -201,7 +201,7 @@ public class RobotFrame extends JFrame {
|
|||||||
int windowX, windowY, boardSize, cellSize;
|
int windowX, windowY, boardSize, cellSize;
|
||||||
BufferedImage detectImage;
|
BufferedImage detectImage;
|
||||||
RobotUtils robot;
|
RobotUtils robot;
|
||||||
// Получаем настройки
|
// Получаем настройки
|
||||||
try {
|
try {
|
||||||
robot = new RobotUtils();
|
robot = new RobotUtils();
|
||||||
detectImage = robot.getImage(-1, -1, -1, -1);
|
detectImage = robot.getImage(-1, -1, -1, -1);
|
||||||
@ -214,9 +214,9 @@ public class RobotFrame extends JFrame {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ImageUtils iu = new ImageUtils(detectImage, boardSize, cellSize, windowX, windowY);
|
ImageUtils iu = new ImageUtils(detectImage, boardSize, cellSize, windowX, windowY);
|
||||||
// Обрезаем картинку до вида игрового поля
|
// Обрезаем картинку до вида игрового поля
|
||||||
detectImage = iu.getBoardImage();
|
detectImage = iu.getBoardImage();
|
||||||
// Получаем цвета из картинки
|
// Получаем цвета из картинки
|
||||||
int[][] table = new int[boardSize][boardSize];
|
int[][] table = new int[boardSize][boardSize];
|
||||||
int offset = cellSize / 2;
|
int offset = cellSize / 2;
|
||||||
for (int i = 0; i < boardSize; i++) {
|
for (int i = 0; i < boardSize; i++) {
|
||||||
@ -226,17 +226,17 @@ public class RobotFrame extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BotFloodIt bfi = new BotFloodIt(table);
|
BotFloodIt bfi = new BotFloodIt(table);
|
||||||
// Получаем результирующую последовательность цветов
|
// Получаем результирующую последовательность цветов
|
||||||
byte[] result = bfi.getFillSequence();
|
byte[] result = bfi.getFillSequence();
|
||||||
int[] colors = bfi.getColors();
|
int[] colors = bfi.getColors();
|
||||||
// Пытаемся получить координаты кнопок для автоматической игры
|
// Пытаемся получить координаты кнопок для автоматической игры
|
||||||
Point[] buttons = iu.getButtons(colors);
|
Point[] buttons = iu.getButtons(colors);
|
||||||
if (buttons == null) {
|
if (buttons == null) {
|
||||||
// Если не удалось найти кнопки, то просто выводим последовательность в виде картинки
|
// Если не удалось найти кнопки, то просто выводим последовательность в виде картинки
|
||||||
BufferedImage out = iu.sequenceToImage(result, colors);
|
BufferedImage out = iu.sequenceToImage(result, colors);
|
||||||
showImageWindow("Result: "+result.length+" steps", out);
|
showImageWindow("Result: "+result.length+" steps", out);
|
||||||
} else {
|
} else {
|
||||||
// Запускаем автоигру
|
// Запускаем автоигру
|
||||||
robot.autoClick(buttons, result);
|
robot.autoClick(buttons, result);
|
||||||
}
|
}
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
@ -249,7 +249,7 @@ public class RobotFrame extends JFrame {
|
|||||||
}//GEN-LAST:event_startStopActionPerformed
|
}//GEN-LAST:event_startStopActionPerformed
|
||||||
|
|
||||||
private void checkButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkButtonActionPerformed
|
private void checkButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkButtonActionPerformed
|
||||||
if (isRunning) return; // нельзя проверять настройки во время работы
|
if (isRunning) return; // нельзя проверять настройки во время работы
|
||||||
int windowX, windowY, boardSize, cellSize;
|
int windowX, windowY, boardSize, cellSize;
|
||||||
BufferedImage detectImage;
|
BufferedImage detectImage;
|
||||||
RobotUtils robot;
|
RobotUtils robot;
|
||||||
@ -269,7 +269,7 @@ public class RobotFrame extends JFrame {
|
|||||||
}//GEN-LAST:event_checkButtonActionPerformed
|
}//GEN-LAST:event_checkButtonActionPerformed
|
||||||
|
|
||||||
private void detectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detectButtonActionPerformed
|
private void detectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detectButtonActionPerformed
|
||||||
if (isRunning) return; // нельзя определять настройки во время работы
|
if (isRunning) return; // нельзя определять настройки во время работы
|
||||||
RobotUtils robot;
|
RobotUtils robot;
|
||||||
try {
|
try {
|
||||||
robot = new RobotUtils();
|
robot = new RobotUtils();
|
||||||
@ -287,9 +287,9 @@ public class RobotFrame extends JFrame {
|
|||||||
}//GEN-LAST:event_detectButtonActionPerformed
|
}//GEN-LAST:event_detectButtonActionPerformed
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Показать модальное окно с изображением
|
* Показать модальное окно с изображением
|
||||||
* @param title заголовок окна
|
* @param title заголовок окна
|
||||||
* @param image изображение
|
* @param image изображение
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
*/
|
*/
|
||||||
private void showImageWindow(String title, BufferedImage image) throws SecurityException {
|
private void showImageWindow(String title, BufferedImage image) throws SecurityException {
|
||||||
|
@ -6,7 +6,7 @@ import java.awt.event.KeyEvent;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Работа с классом Robot.
|
* Работа с классом Robot.
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public class RobotUtils {
|
public class RobotUtils {
|
||||||
@ -15,16 +15,16 @@ public class RobotUtils {
|
|||||||
private Robot robot;
|
private Robot robot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
* @throws AWTException ошибка инициализации Robot
|
* @throws AWTException ошибка инициализации Robot
|
||||||
*/
|
*/
|
||||||
public RobotUtils() throws AWTException {
|
public RobotUtils() throws AWTException {
|
||||||
robot = new Robot();
|
robot = new Robot();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Кликнуть в нужную точку
|
* Кликнуть в нужную точку
|
||||||
* @param click точка по которой нужно кликнуть
|
* @param click точка по которой нужно кликнуть
|
||||||
*/
|
*/
|
||||||
public void clickPoint(Point click) {
|
public void clickPoint(Point click) {
|
||||||
robot.mouseMove(click.x, click.y);
|
robot.mouseMove(click.x, click.y);
|
||||||
@ -34,9 +34,9 @@ public class RobotUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Автоматически воспроизвести заданную последовательность нажатий
|
* Автоматически воспроизвести заданную последовательность нажатий
|
||||||
* @param buttons координаты точек, куда следует нажимать
|
* @param buttons координаты точек, куда следует нажимать
|
||||||
* @param result последовательность id для указания на нужную кнопку
|
* @param result последовательность id для указания на нужную кнопку
|
||||||
*/
|
*/
|
||||||
public void autoClick(Point[] buttons, byte[] result) {
|
public void autoClick(Point[] buttons, byte[] result) {
|
||||||
for (int i = 0; i < result.length; i++) {
|
for (int i = 0; i < result.length; i++) {
|
||||||
@ -44,8 +44,8 @@ public class RobotUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Автоматическое написание сообщения
|
* Автоматическое написание сообщения
|
||||||
* @param text "печатаемый" текст
|
* @param text "печатаемый" текст
|
||||||
*/
|
*/
|
||||||
public void writeMessage(String text) {
|
public void writeMessage(String text) {
|
||||||
for (char symbol : text.toCharArray()) {
|
for (char symbol : text.toCharArray()) {
|
||||||
@ -64,8 +64,8 @@ public class RobotUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Получение картинки размером [width x height] с экрана с позиции [x, y]
|
* Получение картинки размером [width x height] с экрана с позиции [x, y]
|
||||||
* Если width или height равны -1, то возвращаем весь экран.
|
* Если width или height равны -1, то возвращаем весь экран.
|
||||||
*/
|
*/
|
||||||
public BufferedImage getImage(int x, int y, int width, int height) {
|
public BufferedImage getImage(int x, int y, int width, int height) {
|
||||||
Rectangle area;
|
Rectangle area;
|
||||||
|
Loading…
Reference in New Issue
Block a user