Added sources
This commit is contained in:
commit
59fdc4a3c0
197
main/BotFloodIt.java
Normal file
197
main/BotFloodIt.java
Normal file
@ -0,0 +1,197 @@
|
||||
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;
|
||||
}
|
||||
}
|
369
main/ImageUtils.java
Normal file
369
main/ImageUtils.java
Normal file
@ -0,0 +1,369 @@
|
||||
package main;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Êëàññ îáðàáîòêè èçîáðàæåíèé.
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
||||
/* Çà ñêîëüêî òî÷åê ìû áóäåì óçíàâàòü ïðåîáëàäàþùèé ôîí */
|
||||
private static final int MAX_COLOR_POINTS = 50;
|
||||
|
||||
/* ×óâñòâèòåëüíîñòü ê ïîèñêó êíîïîê */
|
||||
private static final int FIND_BUTTON_TOLERANCE = 20;
|
||||
|
||||
/* Èçîáðàæåíèå îêíà */
|
||||
private BufferedImage image;
|
||||
/* Ðàçìåð èçîáðàæåíèÿ */
|
||||
private int w, h;
|
||||
/* Ðàçìåðíîñòü ïîëÿ */
|
||||
private int boardSize;
|
||||
/* Ðàçìåð ÿ÷ååê */
|
||||
private int cellSize;
|
||||
/* Êîîðäèíàòà óãëà èãðîâîãî ïîëÿ */
|
||||
private Point board;
|
||||
/* Ìîíîõðîìíîå ïðåäñòàâëåíèå èçîáðàæåíèÿ */
|
||||
private boolean[] monochrome;
|
||||
|
||||
/**
|
||||
* Êîíñòðóêòîð äëÿ îïðåäåëåíèÿ íàñòðîåê
|
||||
* @param image
|
||||
* @param boardSize
|
||||
*/
|
||||
public ImageUtils(BufferedImage image, int boardSize) {
|
||||
this.image = image;
|
||||
this.boardSize = boardSize;
|
||||
w = image.getWidth();
|
||||
h = image.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Êîíñòðóêòîð äëÿ ïðîâåðêè íàñòðîåê
|
||||
* @param image
|
||||
* @param boardSize
|
||||
* @param cellSize
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public ImageUtils(BufferedImage image, int boardSize, int cellSize, int x, int y) {
|
||||
this.image = image;
|
||||
this.boardSize = boardSize;
|
||||
this.cellSize = cellSize;
|
||||
this.board = new Point(x, y);
|
||||
w = image.getWidth();
|
||||
h = image.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷èòü ðàçìåð ÿ÷åéêè
|
||||
* @return
|
||||
*/
|
||||
public int getCellSize() {
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷èòü êîîðäèíàòû èãðîâîãî ïîëÿ
|
||||
* @return òî÷êà ñ êîîðäèíàòàìè ëåâîãî âåðõíåãî óãëà ïîëÿ
|
||||
*/
|
||||
public Point getBoardParameters() {
|
||||
int[] pixels = new int[w * h];
|
||||
image.getRGB(0, 0, w, h, pixels, 0, w);
|
||||
monochrome = threshold(pixels, 64);
|
||||
board = getBoardXY(boardSize);
|
||||
return board;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷èòü èçîáðàæåíèå èãðîâîãî ïîëÿ
|
||||
* @return êàðòèíêà èãðîâîãî ïîëÿ
|
||||
*/
|
||||
public BufferedImage getBoardImage() {
|
||||
int size = cellSize * boardSize;
|
||||
try {
|
||||
return image.getSubimage(board.x, board.y, size, size);
|
||||
} catch (Exception e) {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷èòü êîîðäèíàòû êíîïîê äëÿ àâòîìàòè÷åñêîãî íàæàòèÿ
|
||||
* @param colors ìàññèâ öâåòîâ, ïî êîòîðûì áóäåì èñêàòü êíîïêè
|
||||
* @return ìàññèâ êîîðäèíàò ñ òî÷êàìè, èëè null - åñëè íå óäàëîñü íàéòè
|
||||
*/
|
||||
public Point[] getButtons(int[] colors) {
|
||||
Point[] out = new Point[colors.length];
|
||||
// Ðàçìåð èãðîâîãî ïîëÿ â ïèêñåëàõ
|
||||
int size = boardSize * cellSize;
|
||||
// Ðàçìåðû ÷àñòåé èçîáðàæåíèÿ, íà êîòîðûõ áóäåì èñêàòü êíîïêè
|
||||
Rectangle[] partsOfImage = new Rectangle[] {
|
||||
new Rectangle(0, board.y, board.x, size), // ñëåâà îò ïîëÿ
|
||||
new Rectangle(0, 0, w, board.y), // ñâåðõó îò ïîëÿ
|
||||
new Rectangle(board.x+size, board.y,
|
||||
w-board.x-size, size), // ñïðàâà îò ïîëÿ
|
||||
new Rectangle(0, board.y+size,
|
||||
w, h-board.x-size) // ñíèçó îò ïîëÿ
|
||||
};
|
||||
|
||||
for (int i = 0; i < partsOfImage.length; i++) {
|
||||
Rectangle rect = partsOfImage[i];
|
||||
BufferedImage part = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
|
||||
// Âûðåçàåì ÷àñòü èçîáðàæåíèÿ, â êîòîðîì áóäåì èñêàòü
|
||||
boolean found = true;
|
||||
for (int j = 0; j < colors.length; j++) {
|
||||
if (colors[i] == -1) continue;
|
||||
Point pt = findButton(part, colors[j]);
|
||||
if (pt != null) {
|
||||
// Ó÷èòûâàåì ñìåùåíèÿ îòíîñèòåëüíî ÷àñòåé êàðòèíîê
|
||||
pt.translate(rect.x, rect.y);
|
||||
out[j] = pt;
|
||||
} else {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) return out;
|
||||
}
|
||||
// Íå óäàëîñü íàéòè âñå òî÷êè
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïðåîáðàçîâàòü ìàññèâ öâåòîâ â ãðàôè÷åñêèé âèä
|
||||
* @param ids ìàññèâ èäåíòèôèêàòîðîâ ïîñëåäîâàòåëüíîñòè
|
||||
* @param palette ìàññèâ ïàëèòðû öâåòîâ
|
||||
* @return èçîáðàæåíèå ïîñëåäîâàòåëüíîñòè öâåòîâ
|
||||
*/
|
||||
public BufferedImage sequenceToImage(byte[] ids, int[] palette) {
|
||||
final int size = 20; // ðàçìåð êàæäîé ÿ÷åéêè
|
||||
// Ðàçáèâàòü áóäåì ïî 10 êëåòîê íà ñòðîêó
|
||||
final int CELLS_IN_ROW = 10;
|
||||
int width = CELLS_IN_ROW * size;
|
||||
if (width == 0) width = size;
|
||||
int rows = ids.length / CELLS_IN_ROW;
|
||||
|
||||
BufferedImage out = new BufferedImage(width, (rows*size)+size, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics G = out.getGraphics();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
G.setColor(new Color(palette[ids[i]]));
|
||||
G.fillRect(i % CELLS_IN_ROW * size,
|
||||
i / CELLS_IN_ROW * size,
|
||||
size, size);
|
||||
}
|
||||
G.dispose();
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïðåîáðàçîâàòü öâåòíîå èçîáðàæåíèå â ìîíîõðîìíîå.
|
||||
* Íóæíî òàêæå ó÷åñòü, ÷òî åñëè ïîëå ðàñïîëîæåíî íà ñâåòëîì
|
||||
* ôîíå, òî íåîáõîäèìî èíâåðòèðîâàòü èçîáðàæåíèå, ÷òîáû
|
||||
* ïîëó÷èòü ñïëîøíóþ áåëóþ îáëàñòü íà ìåñòå ïîëÿ.
|
||||
* @param pixels ìàññèâ ïèêñåëåé èçîáðàæåíèÿ
|
||||
* @param value ðàçäåëÿþùåå çíà÷åíèå
|
||||
* @return ìàññèâ boolean, true - áåëûé, false - ÷¸ðíûé
|
||||
*/
|
||||
private boolean[] threshold(int[] pixels, int value) {
|
||||
boolean inverse = isBackgroundLight(MAX_COLOR_POINTS);
|
||||
if (inverse) value = 255 - value;
|
||||
boolean[] bw = new boolean[pixels.length];
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int brightNess = getBrightness(pixels[i]);
|
||||
bw[i] = (brightNess >= value) ^ inverse;
|
||||
}
|
||||
return bw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷åíèå ñîñòîÿíèÿ ÿðêîñòè ôîíà.
|
||||
* @param numPoints ñêîëüêî òî÷åê íóæíî äëÿ îïðåäåëåíèÿ.
|
||||
* @return true - ôîí ñâåòëûé, false - ò¸ìíûé
|
||||
*/
|
||||
private boolean isBackgroundLight(int numPoints) {
|
||||
// Ïîëó÷àåì numPoints ñëó÷àéíûõ òî÷åê
|
||||
Random rnd = new Random();
|
||||
int[] colors = new int[numPoints];
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
int x = rnd.nextInt(w);
|
||||
int y = rnd.nextInt(h);
|
||||
colors[i] = image.getRGB(x, y);
|
||||
}
|
||||
// Íàõîäèì ñðåäíþþ ÿðêîñòü âñåõ numPoints òî÷åê
|
||||
long sum = 0;
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
int brightness = getBrightness(colors[i]);
|
||||
sum = sum + brightness;
|
||||
}
|
||||
sum = sum / numPoints;
|
||||
return (sum > 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* Îïðåäåëèòü êîîðäèíàòû ëåâîé âåðõíåé ÿ÷åéêè èãðîâîãî ïîëÿ.
|
||||
* @param boardSize ðàçìåðíîñòü ïîëÿ (10x10, 14x14 è ò.ä.)
|
||||
* @return êîîðäèíàòà ëåâîãî âåðõíåãî ïðÿìîóãîëüíèêà
|
||||
*/
|
||||
private Point getBoardXY(int boardSize) {
|
||||
/*
|
||||
* Ñíà÷àëà ïîäñ÷èòàåì êîëè÷åñòâî áåëûõ òî÷åê ïî ãîðèçîíòàëè è âåðòèêàëè
|
||||
*/
|
||||
int[] horizontal = new int[h];
|
||||
for (int i = 0; i < h; i++) {
|
||||
int count = 0;
|
||||
for (int j = 0; j < w; j++) {
|
||||
if (getBWPixel(j, i)) count++;
|
||||
}
|
||||
horizontal[i] = count;
|
||||
}
|
||||
|
||||
int[] vertical = new int[w];
|
||||
for (int i = 0; i < w; i++) {
|
||||
int count = 0;
|
||||
for (int j = 0; j < h; j++) {
|
||||
if (getBWPixel(i, j)) count++;
|
||||
}
|
||||
vertical[i] = count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Çàòåì "îòôèëüòðóåì" ëèøíåå: ïîäñ÷èòàåì ñðåäíåå çíà÷åíèå
|
||||
* è íà åãî îñíîâå óáåð¸ì ìàëîçíà÷èìûå ñòðîêè è ñòîëáöû.
|
||||
*/
|
||||
horizontal = filterByMean(horizontal);
|
||||
vertical = filterByMean(vertical);
|
||||
|
||||
/*
|
||||
* Èùåì íàèáîëüøóþ íåíóëåâóþ ïîñëåäîâàòåëüíîñòü.
|
||||
* Èíäåêñû ãðàíèö ïîñëåäîâàòåëüíîñòè è áóäóò ãðàíè÷íûìè òî÷êàìè ïîëÿ.
|
||||
*/
|
||||
int[] vParam = getParamsFromSequence(horizontal);
|
||||
int[] hParam = getParamsFromSequence(vertical);
|
||||
|
||||
|
||||
int outX = hParam[0];
|
||||
int outY = vParam[0];
|
||||
int outWidth = hParam[1];
|
||||
int outHeight = vParam[1];
|
||||
// Ïîäñ÷åò ðàçìåðà ÿ÷åéêè
|
||||
cellSize = Math.max((outWidth / boardSize), (outHeight / boardSize));
|
||||
return new Point(outX, outY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ôèëüòð ïîñëåäîâàòåëüíîñòè îò ìàëîçíà÷èìûõ çíà÷åíèé.
|
||||
* @param source ïîñëåäîâàòåëüíîñòü âõîæäåíèé öâåòà
|
||||
* @return îòôèëüòðîâàííûé ìàññèâ ñî çíà÷åíèÿìè 0 è 1
|
||||
*/
|
||||
private int[] filterByMean(int[] source) {
|
||||
long mean = 0;
|
||||
for (int i = 0; i < source.length; i++) {
|
||||
mean += source[i];
|
||||
}
|
||||
mean = mean / source.length;
|
||||
for (int i = 0; i < source.length; i++) {
|
||||
source[i] = (source[i] > mean) ? 1 : 0;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîèñê ñàìîé äëèííîé ïîñëåäîâàòåëüíîñòè â ìàññèâå.
|
||||
* @param source âõîäíàÿ ïîñëåäîâàòåëüíîñòü èç íóëåé è åäèíèö
|
||||
* @return ìàññèâ ïàðàìåòðîâ - èíäåêñ íà÷àëà ïîñëåäîâàòåëüíîñòè è å¸ äëèíà
|
||||
*/
|
||||
private int[] getParamsFromSequence(int[] source) {
|
||||
int maxStart = 0, start = 0;
|
||||
int maxLength = 0, length = 0;
|
||||
for (int i = 1; i < source.length; i++) {
|
||||
if (source[i] == 0) {
|
||||
start = 0;
|
||||
length = 0;
|
||||
continue;
|
||||
}
|
||||
if (source[i] == source[i-1]) {
|
||||
length++;
|
||||
if (maxLength < length) {
|
||||
maxStart = start;
|
||||
maxLength = length;
|
||||
}
|
||||
} else {
|
||||
// Åñëè ïðåäûäóùèé ýëåìåíò áûë íóëåâûì - íà÷èíàåì íîâóþ ïîñëåäîâàòåëüíîñòü
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
return new int[] {maxStart, maxLength};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîèñê êîîðäèíàòû êíîïêè ñ öâåòîì template
|
||||
* @param img èçîáðàæåíèå, íà êîòîðîì áóäåì èñêàòü
|
||||
* @param template øàáëîí öâåòà
|
||||
* @return êîîðäèíàòà X. Y, èëè null åñëè íå íàøëè
|
||||
*/
|
||||
private Point findButton(BufferedImage img, int template) {
|
||||
int h2 = img.getHeight() / 2;
|
||||
// Èñêàòü áóäåì ñ ñåðåäèíû ïî âåðòèêàëè, òàê áûñòðåå íàéä¸ì
|
||||
for (int y = 0; y < h2; y++) {
|
||||
for (int x = 0; x < img.getWidth(); x++) {
|
||||
int color = img.getRGB(x, h2 - y);
|
||||
if (isEquals(color, template, FIND_BUTTON_TOLERANCE)) {
|
||||
return new Point(x, h2 - y);
|
||||
}
|
||||
color = img.getRGB(x, h2 + y);
|
||||
if (isEquals(color, template, FIND_BUTTON_TOLERANCE)) {
|
||||
return new Point(x, h2 + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Íå íàøëè
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïðîâåðêà íà ñîîòâåòñòâèå öâåòîâ äðóã äðóãó
|
||||
* @param color1 ïåðâûé öâåò
|
||||
* @param color2 âòîðîé öâåò
|
||||
* @param tolerance ÷óâñòâèòåëüíîñòü
|
||||
* @return true - ñîîòâåòñòâóþò, false - íåò
|
||||
*/
|
||||
private boolean isEquals(int color1, int color2, int tolerance) {
|
||||
if (tolerance < 2) return color1 == color2;
|
||||
|
||||
int r1 = (color1 >> 16) & 0xff;
|
||||
int g1 = (color1 >> 8) & 0xff;
|
||||
int b1 = color1 & 0xff;
|
||||
int r2 = (color2 >> 16) & 0xff;
|
||||
int g2 = (color2 >> 8) & 0xff;
|
||||
int b2 = color2 & 0xff;
|
||||
return (Math.abs(r1 - r2) <= tolerance) &&
|
||||
(Math.abs(g1 - g2) <= tolerance) &&
|
||||
(Math.abs(b1 - b2) <= tolerance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ïîëó÷åíèå ÿðêîñòè öâåòà
|
||||
* @param color èñõîäíûé öâåò
|
||||
* @return ÿðêîñòü (0..255)
|
||||
*/
|
||||
private int getBrightness(int color) {
|
||||
int qr = (color >> 16) & 0xff;
|
||||
int qg = (color >> 8) & 0xff;
|
||||
int qb = color & 0xff;
|
||||
return (qr + qg + qb) / 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ïîëó÷åíèå öâåòà èç ìîíîõðîìíîãî èçîáðàæåíèÿ.
|
||||
* return true - áåëûé, false - ÷¸ðíûé
|
||||
*/
|
||||
private boolean getBWPixel(int x, int y) {
|
||||
if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return false;
|
||||
return monochrome[y * w + x];
|
||||
}
|
||||
|
||||
}
|
222
main/RobotFrame.form
Normal file
222
main/RobotFrame.form
Normal file
@ -0,0 +1,222 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
<Property name="title" type="java.lang.String" value="FloodItBot"/>
|
||||
<Property name="resizable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="windowPanel" max="32767" attributes="1"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="startStop" pref="172" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="57" max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
|
||||
<Component id="windowPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="startStop" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="startStop">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Start"/>
|
||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="startStopActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="Bot for FloodIt"/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="windowPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Options"/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="detectButton" alignment="0" pref="140" max="32767" attributes="0"/>
|
||||
<Component id="checkButton" alignment="1" pref="140" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="1">
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="windowXTextField" min="-2" pref="35" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="windowYTextField" min="-2" pref="35" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jLabel7" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="boardSizeSpinner" min="-2" pref="45" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cellSizeSpinner" min="-2" pref="45" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="windowXTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="windowYTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cellSizeSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="boardSizeSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="detectButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="checkButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextField" name="windowXTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="0"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="x:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="windowYTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="0"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel3">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="y:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel5">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Window:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel6">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Cell size:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="checkButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Check"/>
|
||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="boardSizeSpinner">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel7">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="11" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Field size:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="cellSizeSpinner">
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="detectButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Detect"/>
|
||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="detectButtonActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="RobotFrame_detectButton"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
362
main/RobotFrame.java
Normal file
362
main/RobotFrame.java
Normal file
@ -0,0 +1,362 @@
|
||||
package main;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* Îêíî ïðèëîæåíèÿ.
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class RobotFrame extends JFrame {
|
||||
|
||||
/* Ñòàòóñ ðàáîòû ïðèëîæåíèÿ */
|
||||
private boolean isRunning;
|
||||
|
||||
private Thread robotAction;
|
||||
|
||||
/** Creates new form RobotFrame */
|
||||
public RobotFrame() {
|
||||
initComponents();
|
||||
isRunning = false;
|
||||
setAlwaysOnTop(true);
|
||||
boardSizeSpinner.setModel(new SpinnerNumberModel(14, 5, 40, 1));
|
||||
cellSizeSpinner.setModel(new SpinnerNumberModel(24, 5, 100, 1));
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
startStop = new javax.swing.JButton();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
windowPanel = new javax.swing.JPanel();
|
||||
windowXTextField = new javax.swing.JTextField();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
windowYTextField = new javax.swing.JTextField();
|
||||
jLabel3 = new javax.swing.JLabel();
|
||||
jLabel5 = new javax.swing.JLabel();
|
||||
jLabel6 = new javax.swing.JLabel();
|
||||
checkButton = new javax.swing.JButton();
|
||||
boardSizeSpinner = new javax.swing.JSpinner();
|
||||
jLabel7 = new javax.swing.JLabel();
|
||||
cellSizeSpinner = new javax.swing.JSpinner();
|
||||
detectButton = new javax.swing.JButton();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
setTitle("FloodItBot");
|
||||
setResizable(false);
|
||||
|
||||
startStop.setText("Start");
|
||||
startStop.setActionCommand("");
|
||||
startStop.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
startStopActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel1.setText("Bot for FloodIt");
|
||||
jLabel1.setFocusable(false);
|
||||
jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
|
||||
windowPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Options"));
|
||||
|
||||
windowXTextField.setText("0");
|
||||
|
||||
jLabel2.setText("x:");
|
||||
|
||||
windowYTextField.setText("0");
|
||||
|
||||
jLabel3.setText("y:");
|
||||
|
||||
jLabel5.setText("Window:");
|
||||
|
||||
jLabel6.setText("Cell size:");
|
||||
|
||||
checkButton.setText("Check");
|
||||
checkButton.setActionCommand("");
|
||||
checkButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
checkButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel7.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
|
||||
jLabel7.setText("Field size:");
|
||||
|
||||
detectButton.setText("Detect");
|
||||
detectButton.setActionCommand("");
|
||||
detectButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
detectButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout windowPanelLayout = new javax.swing.GroupLayout(windowPanel);
|
||||
windowPanel.setLayout(windowPanelLayout);
|
||||
windowPanelLayout.setHorizontalGroup(
|
||||
windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(detectButton, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE)
|
||||
.addComponent(checkButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE)
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addGroup(windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel5)
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(windowXTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(jLabel3)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(windowYTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel7)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(boardSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel6)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cellSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
windowPanelLayout.setVerticalGroup(
|
||||
windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(windowPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel5)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel2)
|
||||
.addComponent(windowXTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel3)
|
||||
.addComponent(windowYTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel6)
|
||||
.addComponent(cellSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(windowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel7)
|
||||
.addComponent(boardSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(detectButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(checkButton))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(windowPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(startStop, javax.swing.GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(57, 57, 57)
|
||||
.addComponent(jLabel1)
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jLabel1)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(windowPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(startStop)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void startStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startStopActionPerformed
|
||||
if (isRunning) {
|
||||
startStop.setText("Start");
|
||||
isRunning = false;
|
||||
} else {
|
||||
startStop.setText("Stop");
|
||||
isRunning = true;
|
||||
robotAction = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int windowX, windowY, boardSize, cellSize;
|
||||
BufferedImage detectImage;
|
||||
RobotUtils robot;
|
||||
// Ïîëó÷àåì íàñòðîéêè
|
||||
try {
|
||||
robot = new RobotUtils();
|
||||
detectImage = robot.getImage(-1, -1, -1, -1);
|
||||
windowX = Integer.valueOf(windowXTextField.getText());
|
||||
windowY = Integer.valueOf(windowYTextField.getText());
|
||||
boardSize = (Integer) boardSizeSpinner.getValue();
|
||||
cellSize = (Integer) cellSizeSpinner.getValue();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
ImageUtils iu = new ImageUtils(detectImage, boardSize, cellSize, windowX, windowY);
|
||||
// Îáðåçàåì êàðòèíêó äî âèäà èãðîâîãî ïîëÿ
|
||||
detectImage = iu.getBoardImage();
|
||||
// Ïîëó÷àåì öâåòà èç êàðòèíêè
|
||||
int[][] table = new int[boardSize][boardSize];
|
||||
int offset = cellSize / 2;
|
||||
for (int i = 0; i < boardSize; i++) {
|
||||
for (int j = 0; j < boardSize; j++) {
|
||||
table[i][j] = detectImage.getRGB(j*cellSize + offset,
|
||||
i*cellSize + offset);
|
||||
}
|
||||
}
|
||||
BotFloodIt bfi = new BotFloodIt(table);
|
||||
// Ïîëó÷àåì ðåçóëüòèðóþùóþ ïîñëåäîâàòåëüíîñòü öâåòîâ
|
||||
byte[] result = bfi.getFillSequence();
|
||||
int[] colors = bfi.getColors();
|
||||
// Ïûòàåìñÿ ïîëó÷èòü êîîðäèíàòû êíîïîê äëÿ àâòîìàòè÷åñêîé èãðû
|
||||
Point[] buttons = iu.getButtons(colors);
|
||||
if (buttons == null) {
|
||||
// Åñëè íå óäàëîñü íàéòè êíîïêè, òî ïðîñòî âûâîäèì ïîñëåäîâàòåëüíîñòü â âèäå êàðòèíêè
|
||||
BufferedImage out = iu.sequenceToImage(result, colors);
|
||||
showImageWindow("Result: "+result.length+" steps", out);
|
||||
} else {
|
||||
// Çàïóñêàåì àâòîèãðó
|
||||
robot.autoClick(buttons, result);
|
||||
}
|
||||
isRunning = false;
|
||||
startStop.setText("Start");
|
||||
}
|
||||
|
||||
});
|
||||
robotAction.start();
|
||||
}
|
||||
}//GEN-LAST:event_startStopActionPerformed
|
||||
|
||||
private void checkButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkButtonActionPerformed
|
||||
if (isRunning) return; // íåëüçÿ ïðîâåðÿòü íàñòðîéêè âî âðåìÿ ðàáîòû
|
||||
int windowX, windowY, boardSize, cellSize;
|
||||
BufferedImage detectImage;
|
||||
RobotUtils robot;
|
||||
try {
|
||||
robot = new RobotUtils();
|
||||
detectImage = robot.getImage(-1, -1, -1, -1);
|
||||
windowX = Integer.valueOf(windowXTextField.getText());
|
||||
windowY = Integer.valueOf(windowYTextField.getText());
|
||||
boardSize = (Integer) boardSizeSpinner.getValue();
|
||||
cellSize = (Integer) cellSizeSpinner.getValue();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
ImageUtils iu = new ImageUtils(detectImage, boardSize, cellSize, windowX, windowY);
|
||||
showImageWindow("Checking", iu.getBoardImage());
|
||||
}//GEN-LAST:event_checkButtonActionPerformed
|
||||
|
||||
private void detectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detectButtonActionPerformed
|
||||
if (isRunning) return; // íåëüçÿ îïðåäåëÿòü íàñòðîéêè âî âðåìÿ ðàáîòû
|
||||
RobotUtils robot;
|
||||
try {
|
||||
robot = new RobotUtils();
|
||||
BufferedImage detectImage = robot.getImage(-1, -1, -1, -1);
|
||||
int boardSize = (Integer) boardSizeSpinner.getValue();
|
||||
ImageUtils iu = new ImageUtils(detectImage, boardSize);
|
||||
Point pt = iu.getBoardParameters();
|
||||
int cellSize = iu.getCellSize();
|
||||
windowXTextField.setText(String.valueOf(pt.x));
|
||||
windowYTextField.setText(String.valueOf(pt.y));
|
||||
cellSizeSpinner.setValue(cellSize);
|
||||
} catch (AWTException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}//GEN-LAST:event_detectButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Ïîêàçàòü ìîäàëüíîå îêíî ñ èçîáðàæåíèåì
|
||||
* @param title çàãîëîâîê îêíà
|
||||
* @param image èçîáðàæåíèå
|
||||
* @throws SecurityException
|
||||
*/
|
||||
private void showImageWindow(String title, BufferedImage image) throws SecurityException {
|
||||
ImageIcon icon = new ImageIcon(image);
|
||||
JLabel backlabel = new JLabel(icon);
|
||||
getLayeredPane().add(backlabel, new Integer(Integer.MIN_VALUE));
|
||||
backlabel.setBounds(0, 0, icon.getIconWidth(), icon.getIconHeight());
|
||||
JDialog dialog = new JDialog(this);
|
||||
dialog.setAlwaysOnTop(true);
|
||||
dialog.setLocationByPlatform(true);
|
||||
dialog.setTitle(title);
|
||||
dialog.setResizable(true);
|
||||
dialog.add(backlabel);
|
||||
dialog.pack();
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
/* Set the Nimbus look and feel */
|
||||
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
|
||||
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
|
||||
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
|
||||
*/
|
||||
try {
|
||||
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
|
||||
if ("Nimbus".equals(info.getName())) {
|
||||
javax.swing.UIManager.setLookAndFeel(info.getClassName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
java.util.logging.Logger.getLogger(RobotFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
java.util.logging.Logger.getLogger(RobotFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
java.util.logging.Logger.getLogger(RobotFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
|
||||
java.util.logging.Logger.getLogger(RobotFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/* Create and display the form */
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new RobotFrame().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JSpinner boardSizeSpinner;
|
||||
private javax.swing.JSpinner cellSizeSpinner;
|
||||
private javax.swing.JButton checkButton;
|
||||
private javax.swing.JButton detectButton;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JLabel jLabel3;
|
||||
private javax.swing.JLabel jLabel5;
|
||||
private javax.swing.JLabel jLabel6;
|
||||
private javax.swing.JLabel jLabel7;
|
||||
private javax.swing.JButton startStop;
|
||||
private javax.swing.JPanel windowPanel;
|
||||
private javax.swing.JTextField windowXTextField;
|
||||
private javax.swing.JTextField windowYTextField;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
78
main/RobotUtils.java
Normal file
78
main/RobotUtils.java
Normal file
@ -0,0 +1,78 @@
|
||||
package main;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Ðàáîòà ñ êëàññîì Robot.
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class RobotUtils {
|
||||
|
||||
private static final int CLICK_DELAY = 300;
|
||||
private Robot robot;
|
||||
|
||||
/**
|
||||
* Êîíñòðóêòîð
|
||||
* @throws AWTException îøèáêà èíèöèàëèçàöèè Robot
|
||||
*/
|
||||
public RobotUtils() throws AWTException {
|
||||
robot = new Robot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Êëèêíóòü â íóæíóþ òî÷êó
|
||||
* @param click òî÷êà ïî êîòîðîé íóæíî êëèêíóòü
|
||||
*/
|
||||
public void clickPoint(Point click) {
|
||||
robot.mouseMove(click.x, click.y);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.delay(CLICK_DELAY);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Àâòîìàòè÷åñêè âîñïðîèçâåñòè çàäàííóþ ïîñëåäîâàòåëüíîñòü íàæàòèé
|
||||
* @param buttons êîîðäèíàòû òî÷åê, êóäà ñëåäóåò íàæèìàòü
|
||||
* @param result ïîñëåäîâàòåëüíîñòü id äëÿ óêàçàíèÿ íà íóæíóþ êíîïêó
|
||||
*/
|
||||
public void autoClick(Point[] buttons, byte[] result) {
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
clickPoint(buttons[result[i]]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Àâòîìàòè÷åñêîå íàïèñàíèå ñîîáùåíèÿ
|
||||
* @param text "ïå÷àòàåìûé" òåêñò
|
||||
*/
|
||||
public void writeMessage(String text) {
|
||||
for (char symbol : text.toCharArray()) {
|
||||
boolean needShiftPress = Character.isUpperCase(symbol) && Character.isLetter(symbol);
|
||||
if(needShiftPress) {
|
||||
robot.keyPress(KeyEvent.VK_SHIFT);
|
||||
}
|
||||
int event = KeyEvent.getExtendedKeyCodeForChar(symbol);
|
||||
try {
|
||||
robot.keyPress(event);
|
||||
} catch (Exception e) {}
|
||||
if(needShiftPress) {
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ïîëó÷åíèå êàðòèíêè ðàçìåðîì [width x height] ñ ýêðàíà ñ ïîçèöèè [x, y]
|
||||
* Åñëè width èëè height ðàâíû -1, òî âîçâðàùàåì âåñü ýêðàí.
|
||||
*/
|
||||
public BufferedImage getImage(int x, int y, int width, int height) {
|
||||
Rectangle area;
|
||||
if ((width == -1) || (height == -1)) {
|
||||
area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
|
||||
} else area = new Rectangle(x, y, width, height);
|
||||
return robot.createScreenCapture(area);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user