package org.crazyit.linkgame.service.impl;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.IOException;
import java.util.Random;
import javax.swing.JLabel;
import org.crazyit.linkgame.commons.GameConfiguration;
import org.crazyit.linkgame.commons.LinkInfo;
import org.crazyit.linkgame.commons.Piece;
import org.crazyit.linkgame.commons.Point;
import org.crazyit.linkgame.service.AbstractBoard;
import org.crazyit.linkgame.service.GameService;
/**
* 游戏逻辑处理类
*
* @author yangenxiong
[email protected]
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class GameServiceImpl implements GameService {
// 定义一个棋盘数组,只提供getter方法
private Piece[][] pieces;
private GameConfiguration config;
private AbstractBoard board;
// 加入分数属性,初始值为0
private long grade = 0;
public GameServiceImpl(GameConfiguration config) {
// 将游戏的配置对象设置本类中
this.config = config;
}
public void start() {
this.grade = 0;
// 创建一个棋盘对象
AbstractBoard board = createBoard();
// 为本对象设置board
this.board = board;
// 获取棋盘数组
this.pieces = board.create(config);
}
// 实现接口的hasPieces方法
public boolean hasPieces(Piece[][] pieces) {
for (int i = 0; i < pieces.length; i++) {
for (int j = 0; j < pieces[i].length; j++) {
if (pieces[i][j] != null) {
return true;
}
}
}
return false;
}
public Piece findPiece(int mouseX, int mouseY) {
// 由于是在本类的(棋盘)board中找Piece对象, 如果board为空, 即棋盘中没有棋子
if (this.board == null) {
return null;
}
// 由于我们在创建Piece对象的时候, 将每个Piece的开始坐标加了
// GameConfiguration中设置的beginImageX/beginImageY值, 因此这里要减去这个值
int relativeX = mouseX - this.config.getBeginImageX();
int relativeY = mouseY - this.config.getBeginImageY();
// 如果鼠标点击的地方比棋盘中第一张图片的开始x坐标和开始y坐标要小, 即没有找到棋子
if (relativeX < 0 || relativeY < 0) {
return null;
}
// 获取relativeX坐标在棋盘数组中的一维值, 第二个参数为每张图片的宽
int indexX = getIndex(relativeX, this.board.getCommonImageWidth());
// 获取relativeY坐标在棋盘数组中的二维值, 第二个参数为每张图片的高
int indexY = getIndex(relativeY, this.board.getCommonImageHeight());
// 这两个索引比数组的最小索引还小, 返回null
if (indexX < 0 || indexY < 0) {
return null;
}
// 这两个索引比数组的最大索引还大(或者等于), 返回null
if (indexX >= this.config.getXSize()
|| indexY >= this.config.getYSize()) {
return null;
}
// 返回本对象中棋盘数组的某个值
return this.pieces[indexX][indexY];
}
// 实现接口的link方法
public LinkInfo link(Piece p1, Piece p2) {
// 两个Piece是同一个, 即在棋盘中选择了同一个Piece, 返回null
if (p1.equals(p2))
return null;
// 如果p1的图片与p2的图片不相同, 则返回null
if (!p1.isSameImage(p2))
return null;
// 如果p2在p1的左边, 则需要重新执行本方法, 两个参数互换
if (p2.getIndexX() < p1.getIndexX())
return link(p2, p1);
// 获取p1的中心点
Point p1Point = getPieceCenter(p1);
// 获取p2的中心点
Point p2Point = getPieceCenter(p2);
// 获取每张图片的宽和高
int pieceWidth = this.board.getCommonImageWidth();
int pieceHeight = this.board.getCommonImageHeight();
// 如果两个Piece在同一行
if (p1.getIndexY() == p2.getIndexY()) {
// 它们在同一行并之间可以连
if (!isXBlock(p1Point, p2Point, pieceWidth)) {
return new LinkInfo(p1Point, p2Point);
}
}
// 如果两个Piece在同一列
if (p1Point.getX() == p2Point.getX()) {
if (!isYBlock(p1Point, p2Point, pieceHeight)) {// 它们之间没有真接障碍, 没有转折点
return new LinkInfo(p1Point, p2Point);
}
}
// 有一个转折点的情况
// 获取两个点的直角相连的点, 即只有一个转折点
Point cornerPoint = getCornerPoint(p1Point, p2Point, pieceWidth,
pieceHeight);
if (cornerPoint != null) {
return new LinkInfo(p1Point, cornerPoint, p2Point);
}
// 该map的key存放第一个转折点, value存放第二个转折点, map的size说明有多少个可以连的方式
Map<Point, Point> turns = getLinkPoints(p1Point, p2Point, pieceWidth,
pieceHeight);
if (turns.size() != 0) {
return getShortcut(p1Point, p2Point, turns, getDistance(p1Point,
p2Point));
}
return null;
}
public long countGrade() {
this.grade += this.config.getPerGrade();
return this.grade;
}
/**
* 获取p1和p2之间最短的连接信息
*
* @param p1
* @param p2
* @param turns
* 放转折点的map
* @param shortDistance
* 两点之间的最短距离
* @return
*/
private LinkInfo getShortcut(Point p1, Point p2, Map<Point, Point> turns,
int shortDistance) {
List<LinkInfo> infos = new ArrayList<LinkInfo>();
// 遍历结果map, 将转折点与选择的点封装成LinkInfo对象, 放到集合中
for (Object info : turns.keySet()) {
Point point1 = (Point) info;
Point point2 = turns.get(point1);
infos.add(new LinkInfo(p1, point1, point2, p2));
}
return getShortcut(infos, shortDistance);
}
/**
* 在infos中获取其四个点最短的那个LinkInfo对象
*
* @param infos
* @return
*/
private LinkInfo getShortcut(List<LinkInfo> infos, int shortDistance) {
int temp1 = 0;
LinkInfo result = null;
for (int i = 0; i < infos.size(); i++) {
LinkInfo info = infos.get(i);
// 计算出几个点的总距离
int distance = countAll(info.getLinkPoints());
// 将循环第一个的差距用temp1保存
if (i == 0) {
temp1 = distance - shortDistance;
result = info;
}
// 如果下一次循环的值比temp1的还小, 则用当前的值作为temp1
if (distance - shortDistance < temp1) {
temp1 = distance - shortDistance;
result = info;
}
}
return result;
}
/**
* 计算points中所有点的距离总和
*
* @param points
* @return
*/
private int countAll(List<Point> points) {
int result = 0;
for (int i = 0; i < points.size(); i++) {
if (i == points.size() - 1) {// 循环到最后一个
break;
}
Point point1 = points.get(i);
Point point2 = points.get(i + 1);
result += getDistance(point1, point2);
}
return result;
}
/**
* 获取两个LinkPoint之间的最短距离
*
* @param p1
* @param p2
* @return
*/
private int getDistance(Point p1, Point p2) {
int xDistance = Math.abs(p1.getX() - p2.getX());
int yDistance = Math.abs(p1.getY() - p2.getY());
return xDistance + yDistance;
}
/**
* 获取两个转折点的情况
*
* @param point1
* @param point2
* @return
*/
private Map<Point, Point> getLinkPoints(Point point1, Point point2,
int pieceWidth, int pieceHeight) {
Map<Point, Point> result = new HashMap<Point, Point>();
// 获取以point1为中心的向上, 向右, 向下的通道
List<Point> p1UpChanel = getUpChanel(point1, point2.getY(), pieceHeight);
List<Point> p1RightChanel = getRightChanel(point1, point2.getX(),
pieceWidth);
List<Point> p1DownChanel = getDownChanel(point1, point2.getY(),
pieceHeight);
// 获取以point2为中心的向下, 向左, 向上的通道
List<Point> p2DownChanel = getDownChanel(point2, point1.getY(),
pieceHeight);
List<Point> p2LeftChanel = getLeftChanel(point2, point1.getX(),
pieceWidth);
List<Point> p2UpChanel = getUpChanel(point2, point1.getY(), pieceHeight);
// 获取棋盘的最大值, 高和宽
int heightMax = (this.config.getYSize() + 1) * pieceHeight
+ this.config.getBeginImageY();
int widthMax = (this.config.getXSize() + 1) * pieceWidth
+ this.config.getBeginImageX();
// 先确定两个点的关系
// point2在point1的左上角或者左下角
if (isLeftUp(point1, point2) || isLeftDown(point1, point2)) {
// 参数换位, 调用本方法
return getLinkPoints(point2, point1, pieceWidth, pieceH