package org.test.wuziqi;
import loon.LSystem;
import loon.LTexture;
import loon.Screen;
import loon.canvas.Canvas;
import loon.canvas.Image;
import loon.canvas.LColor;
import loon.component.LComponent;
import loon.component.LPanel;
import loon.component.LToast;
import loon.event.ClickListener;
import loon.event.SysTouch;
import loon.font.IFont;
import loon.geom.PointI;
import loon.opengl.GLEx;
import loon.utils.MathUtils;
import loon.utils.processes.RealtimeProcess;
import loon.utils.timer.LTimerContext;
public class GobangPanel extends LPanel {
private ComputurTask task = null; // 自动任务
private LToast toast = null; // 提示信息
private final int OFFSET = 40;// 棋盘偏移
private final int CELL_WIDTH = 40;// 棋格宽度
private int computerSide = Chess.BLACK;// 默认机器持黑
private int humanSide = Chess.WHITE;
private int cx = WuziBoard.CENTER, cy = WuziBoard.CENTER;
private boolean isShowOrder = false;// 显示落子顺序
private int[] lastStep;// 上一个落子点
private WuziBoard bd;// 棋盘,重要
private Brain br;// AI,重要
public static final int MANUAL = 0;// 双人模式
public static final int HALF = 1;// 人机模式
public static final int AUTO = 2;// 双机模式
public static final int EVAL = 3;// 估值函数
public static final int TREE = 4;// 估值函数+搜索树
private int mode;// 模式
private int intel;// 智能
private boolean isGameOver = true;
// 显示落子顺序
public void troggleOrder() {
isShowOrder = !isShowOrder;
}
// 悔棋
public void undo() {
PointI p = bd.undo();
if (p != null) {
lastStep[0] = p.x;
lastStep[1] = p.y;
}
}
public GobangPanel() {
super(0, 0, 650, 650);
lastStep = new int[2];
this.setBackground(LColor.orange);
bd = new WuziBoard();
this.customRendering = false;
SetClick(new ClickListener() {
@Override
public void UpClick(LComponent comp, float x, float y) {
// TODO Auto-generated method stub
}
@Override
public void DragClick(LComponent comp, float x, float y) {
}
@Override
public void DownClick(LComponent comp, float x1, float y1) {
if (isGameOver) {
showMessage("请开始新游戏!");
return;
}
int x = MathUtils.round((x1 - OFFSET) * 1.0f / CELL_WIDTH) + 1;
int y = MathUtils.round((y1 - OFFSET) * 1.0f / CELL_WIDTH) + 1;
if (cx >= 1 && cx <= WuziBoard.BOARD_SIZE && cy >= 1
&& cy <= WuziBoard.BOARD_SIZE) {
if (mode == MANUAL) {// 双人
putChess(x, y);
} else if (mode == HALF) {// 人机
if (bd.getPlayer() == humanSide) {
if (putChess(x, y)) {
Log.debug("\n----白棋完毕----");
if (intel == EVAL) {
int[] bestStep = br.findOneBestStep();// 估值函数AI
putChess(bestStep[0], bestStep[1]);
} else if (intel == TREE) {
int[] bestStep = br.findTreeBestStep();// 估值函数+搜索树AI
putChess(bestStep[0], bestStep[1]);
}
Log.debug("\n----黑棋完毕----");
}
}
}
}
}
@Override
public void DoClick(LComponent comp) {
// TODO Auto-generated method stub
}
});
}
@Override
public void createUI(GLEx g, int x1, int y1, LComponent component,
LTexture[] buttonImage) {
// 保存原始画笔
g.saveBrush();
// 画棋盘
drawBoard(g);
// 画天元和星
drawStar(g, WuziBoard.CENTER, WuziBoard.CENTER);
drawStar(g, (WuziBoard.BOARD_SIZE + 1) / 4,
(WuziBoard.BOARD_SIZE + 1) / 4);
drawStar(g, (WuziBoard.BOARD_SIZE + 1) / 4,
(WuziBoard.BOARD_SIZE + 1) * 3 / 4);
drawStar(g, (WuziBoard.BOARD_SIZE + 1) * 3 / 4,
(WuziBoard.BOARD_SIZE + 1) / 4);
drawStar(g, (WuziBoard.BOARD_SIZE + 1) * 3 / 4,
(WuziBoard.BOARD_SIZE + 1) * 3 / 4);
// 画数字和字母
drawNumAndLetter(g);
// 画提示框
drawCell(g, cx, cy, 0);
if (!isGameOver) {
// 画所有棋子
for (int x = 1; x <= WuziBoard.BOARD_SIZE; ++x) {
for (int y = 1; y <= WuziBoard.BOARD_SIZE; ++y) {
drawChess(g, x, y, bd.getData()[x][y].getSide());
}
}
// 画顺序
if (isShowOrder)
drawOrder(g);
else {
if (lastStep[0] > 0 && lastStep[1] > 0) {
g.setColor(LColor.red);
g.fillRect((lastStep[0] - 1) * CELL_WIDTH + OFFSET
- CELL_WIDTH / 10, (lastStep[1] - 1) * CELL_WIDTH
+ OFFSET - CELL_WIDTH / 10, CELL_WIDTH / 5,
CELL_WIDTH / 5);
}
}
}
// 还原画笔
g.restoreBrush();
}
private LTexture boardTexture;
// 画棋盘
private void drawBoard(GLEx g) {
if (boardTexture == null) {
Image img = Image.createImage(width(), height());
Canvas cs = img.getCanvas();
cs.setColor(LColor.black);
cs.setStrokeWidth(2f);
for (int x = 0; x < WuziBoard.BOARD_SIZE; ++x) {
cs.drawLine(x * CELL_WIDTH + OFFSET, OFFSET, x * CELL_WIDTH
+ OFFSET, (WuziBoard.BOARD_SIZE - 1) * CELL_WIDTH
+ OFFSET);
}
for (int y = 0; y < WuziBoard.BOARD_SIZE; ++y) {
cs.drawLine(OFFSET, y * CELL_WIDTH + OFFSET,
(WuziBoard.BOARD_SIZE - 1) * CELL_WIDTH + OFFSET, y
* CELL_WIDTH + OFFSET);
}
boardTexture = img.texture();
img.close();
}
g.draw(boardTexture, 0, 0);
}
// 画天元和星
private void drawStar(GLEx g, int cx, int cy) {
g.fillOval((cx - 1) * CELL_WIDTH + OFFSET - 4, (cy - 1) * CELL_WIDTH
+ OFFSET - 4, 8, 8);
}
// 画数字和字母
private void drawNumAndLetter(GLEx g) {
IFont fm = g.getFont();
float stringWidth, stringAscent;
stringAscent = -fm.getAscent();
for (int i = 1; i <= WuziBoard.BOARD_SIZE; i++) {
String num = String.valueOf(WuziBoard.BOARD_SIZE - i + 1);
stringWidth = fm.stringWidth(num);
g.drawString(String.valueOf(WuziBoard.BOARD_SIZE - i + 1), OFFSET
/ 4 - stringWidth / 2, OFFSET + (CELL_WIDTH * (i - 1))
+ stringAscent / 2);
String letter = String.valueOf((char) (64 + i));
stringWidth = fm.stringWidth(letter);
g.drawString(String.valueOf((char) (64 + i)), OFFSET
+ (CELL_WIDTH * (i - 1)) - stringWidth / 2, OFFSET * 3 / 4
+ OFFSET + CELL_WIDTH * (WuziBoard.BOARD_SIZE - 1)
+ stringAscent / 2);
}
}
// 画棋子
private void drawChess(GLEx g, int cx, int cy, int player) {
if (player == 0)
return;
int size = CELL_WIDTH * 5 / 6;
g.setColor(player == Chess.BLACK ? LColor.black : LColor.white);
g.fillOval((cx - 1) * CELL_WIDTH + OFFSET - size / 2, (cy - 1)
* CELL_WIDTH - size / 2 + OFFSET, size, size);
}
// 画预选框
private void drawCell(GLEx g, int x, int y, int c) {// c 是style
int length = CELL_WIDTH / 4;
int xx = (x - 1) * CELL_WIDTH + OFFSET;
int yy = (y - 1) * CELL_WIDTH + OFFSET;
int x1, y1, x2, y2, x3, y3, x4, y4;
x1 = x4 = xx - CELL_WIDTH / 2;
x2 = x3 = xx + CELL_WIDTH / 2;
y1 = y2 = yy - CELL_WIDTH / 2;
y3 = y4 = yy + CELL_WIDTH / 2;
g.setColor(LColor.red);
g.drawLine(x1, y1, x1 + length, y1);
g.drawLine(x1, y1, x1, y1 + length);
g.drawLine(x2, y2, x2 - length, y2);
g.drawLine(x2, y2, x2, y2 + length);
g.drawLine(x3, y3, x3 - length, y3);
g.drawLine(x3, y3, x3, y3 - length);
g.drawLine(x4, y4, x4 + length, y4);
g.drawLine(x4, y4, x4, y4 - length);
}
// 画落子顺序
private void drawOrder(GLEx g) {
int[][] history = bd.getHistory();
if (history.length > 0) {
g.setColor(LColor.red);
for (int i = 0; i < history.length; i++) {
int x = history[i][0];
int y = history[i][1];
String text = String.valueOf(i + 1);
// 居中
IFont fm = g.getFont();
int stringWidth = fm.stringWidth(text);
float stringAscent = -fm.getAscent();
g.drawString(text, (x - 1) * CELL_WIDTH + OFFSET - stringWidth
/ 2, (y - 1) * CELL_WIDTH + OFFSET + stringAscent / 2);
}
}
}
// 开始游戏
public void startGame(int mode, int intel, int level, int node) {
Screen.removeProcess(task);
// 清除
bd.reset();
isGameOver = true;
this.mode = mode;
this.intel = intel;
bd.reset();
lastStep[0] = lastStep[1] = WuziBoard.CENTER;
br = new Brain(bd, level, node);
bd.start();
isGameOver = false;
showMessage("游戏开始!");
if (mode == AUTO) {// 双机
task = new ComputurTask();
task.setDelay(LSystem.SECOND);
Screen.addProcess(task);
}
}
@Override
public void update(long t) {
if (contains(SysTouch.getX(), SysTouch.getY())) {
int tx = MathUtils.round((SysTouch.getX() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
int ty = MathUtils.round((SysTouch.getY() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
if (tx >= 1 && tx <= WuziBoard.BOARD_SIZE && ty >= 1
&& ty <= WuziBoard.BOARD_SIZE) {
cx = tx;
cy = ty;
}
}
}
private boolean putChess(int x, int y) {
if (bd.putChess(x, y)) {
lastStep[0] = x;// 保存上一步落子点
lastStep[1] = y;
int winSide = bd.isGameOver();// 判断终局
if (winSide > 0) {
if (winSide == humanSide) {
showMessage("白方赢了!");
} else if (winSide == computerSide) {
showMessage("黑方赢了!");
} else {
showMessage("双方平手");
}
// 清除
bd.reset();
isGameOver = true;
return false;
}
return true;
}
return false;
}
public void showMessage(String mes) {
if (toast != null) {
getScreen().remove(toast);
}
getScreen().add(toast = LToast.makeText(mes, LToast.Style.ERROR));
}
// 双机
private class ComputurTask extends RealtimeProcess {
@Override
public void run(LTimerContext time) {
int[] bestStep = br.findTreeBestStep();
if (!putChess(bestStep[0], bestStep[1])) {
this.kill();
}
}
}
}