QQ中国象棋(传统版)的棋盘识别程序Java源码(Eclipse工程)目前维护在Github
项目地址:https://github.com/qinjiannet/screen-chess-qq/
程序的入口main方法位于execute包下的Executor类中
自动下棋时默认采用随机行走,开发者可以通过修改ai包下的Thinker类中的getBestMove方法实现更加智能的AI
运行时,需要在QQ游戏大厅中手工开始一局象棋,然后运行Executor
由于程序采用的是截图分析获取棋盘状态的方式,因此运行过程中需要保证游戏窗口不被其他窗口遮挡
部分Java源码摘录如下:
RecognitionHelper.java 用来识别QQ中国象棋的棋盘
package recognition;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import color.ColorHelper;
import entity.Board;
import entity.Coordinate;
import entity.chess.Chess;
import entity.chess.ChessFactory;
//Author:在线疯狂
//Homepage: http://bookshadow.com
public class RecognitionHelper {
public static final int gridSize = 48;
public static final int chessSize = 32; // 42
public static final int orderSize = 42;
public static final char CHESS_NAME[] = { '车', '马', '炮', '砲', '象', '相',
'士', '仕', '将', '帅', '兵', '卒' };
public static final int CHESS_VAL[] = { 96, 110, 101, 81, 112, 124, 55, 70,
97, 122, 88, 82 };
public static final HashMap<Integer, Character> CHESS_NAME_MAP = new HashMap<Integer, Character>();
static {
for (int i = 0; i < CHESS_VAL.length; i++) {
CHESS_NAME_MAP.put(CHESS_VAL[i], CHESS_NAME[i]);
}
}
// Screen Coordinate
public static int[] getStartXY(BufferedImage bi) {
int width = (int) bi.getWidth();
int height = (int) bi.getHeight();
int startX = -1, startY = -1;
for (int i = 0; i < height; i++) {
int cnt = 0;
for (int j = 0; j < width; j++) {
int rgb = bi.getRGB(j, i);
if (ColorHelper.PATTERN_SET.contains(rgb)) {
cnt++;
}
}
if (cnt > 100) {
startX = i;
break;
}
}
for (int i = 0; i < width; i++) {
int cnt = 0;
for (int j = 0; j < height; j++) {
int rgb = bi.getRGB(i, j);
if (ColorHelper.PATTERN_SET.contains(rgb)) {
cnt++;
}
}
if (cnt > 400) {
startY = i - 2;
break;
}
}
return new int[] { startX, startY };
}
public static HashMap<Integer, Integer> getChess(BufferedImage bi) {
HashMap<Integer, Integer> hmap = new HashMap<Integer, Integer>();
int width = bi.getWidth();
int height = bi.getHeight();
for (int ii = 0; ii < width; ii++) {
for (int jj = 0; jj < height; jj++) {
int rgb = bi.getRGB(ii, jj);
Integer val = hmap.get(rgb);
if (val == null) {
val = 0;
}
hmap.put(rgb, val + 1);
}
}
return hmap;
}
public static char getSelfColor(BufferedImage bi) {
int startXY[] = getStartXY(bi);
if (startXY[0] < 0 || startXY[1] < 0)
return 0;
int startLX = startXY[0] + 338;
int startY = 0;
BufferedImage lowerImage = bi.getSubimage(startY, startLX, startXY[1],
orderSize);
return getColor(lowerImage);
}
/**
* getOrder
*
* @param bi
* @return null:error,"sr":self red,"or":opponent red, "sb":self black,
* "ob":opponent black
*/
public static String getOrder(BufferedImage bi) {
int startXY[] = getStartXY(bi);
if (startXY[0] < 0 || startXY[1] < 0)
return null;
int startUX = startXY[0] + 90;
int startLX = startXY[0] + 338;
int startY = 0;
BufferedImage upperImage = bi.getSubimage(startY, startUX, startXY[1],
orderSize);
BufferedImage lowerImage = bi.getSubimage(startY, startLX, startXY[1],
orderSize);
char uc = getColor(upperImage);
char lc = getColor(lowerImage);
String ret = null;
if (uc != Chess.WHITE) {
ret = "" + Board.OPPONENT + uc;
} else if (lc != Chess.WHITE) {
ret = "" + Board.SELF + lc;
}
return ret;
}
/**
* getColor
*
* @param bi
* @return 'w':white,'r':red,'b':black
*/
public static char getColor(BufferedImage bi) {
int blackCnt = 0;
int redCnt = 0;
int width = bi.getWidth();
int height = bi.getHeight();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int rgb = bi.getRGB(i, j);
if (ColorHelper.BLACK == rgb) {
blackCnt++;
} else if (ColorHelper.RED == rgb) {
redCnt++;
}
}
}
if (blackCnt > 80) {
return 'b';
}
if (redCnt > 110) {
return 'r';
}
return 'w';
}
/**
* GetChessStatus By BufferedImage
*
* @param bi
* Screenshot
* @return
*/
public static Board getChessBoard(BufferedImage bi) {
if (bi == null)
return null;
int startXY[] = getStartXY(bi);
if (startXY[0] < 0 || startXY[1] < 0)
return null;
int chessStartX = startXY[0] + 30;
int chessStartY = startXY[1] + 30;
Chess[][] ans = new Chess[10][9];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 9; j++) {
int x = chessStartX + i * RecognitionHelper.gridSize;
int y = chessStartY + j * RecognitionHelper.gridSize;
int sx = x - RecognitionHelper.chessSize / 2;
int sy = y - RecognitionHelper.chessSize / 2;
BufferedImage subImage = bi.getSubimage(sy, sx,
RecognitionHelper.chessSize,
RecognitionHelper.chessSize);
HashMap<Integer, Integer> chessMap = RecognitionHelper
.getChess(subImage);
Character color = null;
Character name = null;
Character redName = null;
Character blackName = null;
Integer redNum = chessMap.get(ColorHelper.RED);
Integer blackNum = chessMap.get(ColorHelper.BLACK);
if (redNum != null) {
redName = RecognitionHelper.CHESS_NAME_MAP.get(redNum);
} else if (chessMap.get(ColorHelper.BLACK) != null) {
blackName = RecognitionHelper.CHESS_NAME_MAP.get(blackNum);
}
Point point = new Point(x, y);
Chess chess = null;
if (redName != null || blackName != null) {
if (redName != null) {
color = '红';
name = redName;
} else {
color = '黑';
name = blackName;
}
char code = Chess.name2Code(name);
chess = ChessFactory.newChess(code);
chess.setLocation(point);
chess.setColor(Chess.color2Alphabet(color));
chess.setCoordinate(new Coordinate(i, j));
chess.setName(color + "" + name);
}
ans[i][j] = chess;
}
}
// Identify upper generals's color
char upColor = Chess.WHITE;
outer: for (int i = 0; i <= 2; i++) {
for (int j = 3; j <= 5; j++) {
if (ans[i][j] != null && ans[i][j].getCode() == Chess.GENERAL) {
upColor = ans[i][j].getColor();
break outer;
}
}
}
return new Board(ans, upColor);
}
}
ScreenshotGetter.java 用来获取屏幕截图
package recognition;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
//Author:在线疯狂
//Homepage: http://bookshadow.com
public class ScreenshotGetter {
public BufferedImage getScreenshot() throws AWTException {
final Robot robot = new Robot();
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) dimension.getWidth();
int height = (int) dimension.getHeight();
BufferedImage screenshot = robot.createScreenCapture(new Rectangle(0,
0, width, height));
return screenshot;
}
}
ColorHelper.java 用来获取RGB格式的颜色代码
package color;
import java.util.HashSet;
//Author:在线疯狂
//Homepage: http://bookshadow.com
public class ColorHelper {
public static final int PATTERN_ARR[] = { -2569056, -2571120, -2571112,
-3099528, -1516360, -2573176, -2044752, -2046816, -2571104,
-1516352, -2044760, -2573168, -3099512, -2042696, -3101576,
-1516344, -1518408, -2573160, -3099520, -2044768, -2042704 };
public static final HashSet<Integer> PATTERN_SET = new HashSet<Integer>();
static {
for (int rgb : PATTERN_ARR) {
PATTERN_SET.add(rgb);
}
}
public static final int RED_RGB[] = { 200, 8, 0 };
public static final int RED = -3667968;
public static final int BLACK_RGB[] = { 56, 56, 56 };
public static final int BLACK = -13092808;
public static int[] getRGB(int rgb) {
int R = (rgb & 0xff0000) >> 16;
int G = (rgb & 0xff00) >> 8;
int B = (rgb & 0xff);
return new int[] { R, G, B };
}
}
本文链接:http://bookshadow.com/weblog/2014/10/25/qq-chess-recognition-ai-java-program/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。