我之前做了个人机对战的五子棋, AI算法很垃圾, 然后各种逻辑很糟糕, 已经很久没有维护了, 今天看了篇文章, 是用了蓝牙和Wifi的五子棋对战, 我觉得很有意思, 毕竟自己没做过蓝牙连接这方面的项目, 然后我就把以前做的五子棋搬了出来.
我在前面就有写过一篇比较详细的文章, 兄弟们可以到前面看一看, Android 蓝牙五子棋[可人机对战] —— 蓝牙通信篇
这个算法呢, 就是一个朋友写的, 使用了博弈树来进行判断对战, 其实原理很简单: 通过计算各个点的权重.
有兴趣的朋友可以下载项目来研究下,这个算法不是很好,计算得比较慢, 一共写了6棵树, 我这里只用了2,3,4, 所以比较快.哪天有空,我也来研究一下ai算法.
public class BleGameActivity extends Activity implements PeopleGameView.onBluetoothListener {
@InjectView(R.id.tv_pgv_win)
TextView mIsWin;
@InjectView(R.id.view_pgv)
PeopleGameView mPeopleGameView;
@InjectView(R.id.btn_pgv_return)
Button mBtnPgvReturn;
@InjectView(R.id.btn_pgv_again)
Button mBtnPgvAgain;
@InjectView(R.id.btn_pgv_msg)
Button mBtnPgvMsg;
private ConnectedThread mConnectedThread;
private BluetoothSocket mSocket;
private ListPopupWindow mWindowCompat;
private List mMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_ble_game);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ButterKnife.inject(this);
init();
}
//初始化
private void init() {
String[] message = getResources().getStringArray(R.array.array_message);
mMessage = Arrays.asList(message);
mPeopleGameView.setTextView(mIsWin);
mPeopleGameView.setCallBack(this);
//获取信息
Intent intent = getIntent();
String adress = intent.getStringExtra("adress");
boolean isStart = intent.getBooleanExtra("isStart", false);
if (adress != null) {
mSocket = SocketManager.getmBleSocketHm(adress);
manageClientSocket(isStart);
mPeopleGameView.setAdress(adress);
mPeopleGameView.setIsStart(isStart);
}
popupWindow();
}
//开启连接线程
public void manageClientSocket(boolean isStart) {
mConnectedThread = new ConnectedThread(mSocket, mPeopleGameView, isStart);
mConnectedThread.start();
}
//发送信息
@Override
public void onCommand(String temp) {
mConnectedThread.write(temp.getBytes());
}
@OnClick({R.id.btn_pgv_return, R.id.btn_pgv_again, R.id.btn_pgv_msg})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_pgv_msg:
mWindowCompat.show();
break;
case R.id.btn_pgv_return:
String command = "return";
mConnectedThread.write(command.getBytes());
mPeopleGameView.returnUp();
break;
case R.id.btn_pgv_again:
String restartCommand = "restart";
mConnectedThread.write(restartCommand.getBytes());
mPeopleGameView.restartGame();
break;
}
}
//弹出快捷回复窗口
private void popupWindow() {
mWindowCompat = new ListPopupWindow(this);
mWindowCompat.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, mMessage));
mWindowCompat.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
mWindowCompat.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
mWindowCompat.setAnchorView(mBtnPgvMsg);
mWindowCompat.setModal(true);
mWindowCompat.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
String msg = "msg;" + mMessage.get(position);
mConnectedThread.write(msg.getBytes());
mWindowCompat.dismiss();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mConnectedThread.cancel();
}
}
PeopleGameView.javapublic class PeopleGameView extends View {
private Paint mPaint;
private int mPanelWidth; //画布宽度
private int mChessFlag = 0; //记录上一次下棋颜色,1为黑色,2为白色,0为刚开始
private static final int CHESS_BLACK = 1;
private static final int CHESS_WHITE = 2;
private static final int MAX_LINE = 15; //最大行数
private static final float SIZE = 3 * 1.0f / 4; //棋子的大小为棋盘格子的3/4
private float mSingleHeight; //格子高度
public boolean isWin = false; //是否已出结果
private boolean isMe = false; //谁先出手
private boolean isStart = false; //谁先开始
private int[][] mChess; //棋盘
private Stack mChessArray; //悔棋的栈
private BleGameActivity mBleGameActivity;
private String mAdress;
private int mUpChessX; //上一个下的棋子x,y
private int mUpChessY;
private TextView mTvWin; //输赢的TextView
public PeopleGameView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
//初始化
private void init() {
isWin = false;
mUpChessX = mUpChessY = -1;
mChess = new int[MAX_LINE][MAX_LINE];
mChessArray = new Stack<>();
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL);
isMe = isStart;
if (isStart) {
mChessFlag = CHESS_WHITE;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = Math.min(widthSize, heightSize);
if (widthMode == MeasureSpec.UNSPECIFIED) {
width = heightSize;
} else if (heightMode == MeasureSpec.UNSPECIFIED) {
width = widthSize;
}
mPanelWidth = width;
mSingleHeight = mPanelWidth * 1.0f / MAX_LINE;
setMeasuredDimension(width, width);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
drawBoard(canvas);
drawPiece(canvas);
}
/**
* 画棋盘
*
* @param canvas
*/
private void drawBoard(Canvas canvas) {
mPaint.setColor(Color.BLACK);
for (int i = 0; i < MAX_LINE; i++) {
canvas.drawLine(mSingleHeight / 2, mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2 + (MAX_LINE - 1) * mSingleHeight, mSingleHeight / 2 + i * mSingleHeight, mPaint);
canvas.drawLine(mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2, mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2 + (MAX_LINE - 1) * mSingleHeight, mPaint);
}
}
/**
* 画棋子
*
* @param canvas
*/
private void drawPiece(Canvas canvas) {
int side = 0;
if ((side = isWin(mChess)) != 0) {
mTvWin.setVisibility(View.VISIBLE);
if (side == CHESS_BLACK) {
mBleGameActivity.onCommand("black_win");
mTvWin.setText("黑棋胜利!");
} else if (side == CHESS_WHITE) {
mBleGameActivity.onCommand("white_win");
mTvWin.setText("白棋胜利!");
}
mChessFlag = 0;
isWin = true;
}
for (int i = 0; i < MAX_LINE; i++) {
for (int j = 0; j < MAX_LINE; j++) {
if (mChess[i][j] == CHESS_BLACK) {
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2 + j * mSingleHeight, mSingleHeight / 2 - 5, mPaint);
}
if (mChess[i][j] == CHESS_WHITE) {
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2 + j * mSingleHeight, mSingleHeight / 2 - 5, mPaint);
}
//画上一个棋子的圆环
if (i == mUpChessX && j == mUpChessY) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
canvas.drawCircle(mSingleHeight / 2 + i * mSingleHeight, mSingleHeight / 2 + j * mSingleHeight, mSingleHeight / 2 - 2, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(0);
}
}
}
}
//下棋子,并发送给对方
private void putChess(int x, int y, int chessFlag) {
mChess[x][y] = chessFlag;
String command = "";
String temp = x + ";" + y + ";" + chessFlag;
mChessArray.push(temp);
command += mAdress + ";" + temp;
mBleGameActivity.onCommand(command + ";" + chessFlag);
}
//接收对方传送信息
public void getCommand(String command) {
if ("msg;".equals(command.substring(0, 4))) {
String finalCommand = command.substring(4);
Toast.makeText(mBleGameActivity, finalCommand, Toast.LENGTH_SHORT).show();
} else if ("white_win".equals(command)) {
mTvWin.setText("白棋胜利!");
} else if ("black_win".equals(command)) {
mTvWin.setText("黑棋胜利!");
} else if ("return".equals(command)) {
Toast.makeText(mBleGameActivity, "对方悔棋!", Toast.LENGTH_SHORT).show();
returnUp();
} else if ("restart".equals(command)) {
Toast.makeText(mBleGameActivity, "对方重玩游戏!", Toast.LENGTH_SHORT).show();
restartGame();
} else {
isMe = false;
String[] data = command.split(";");
int x = Integer.parseInt(data[1]);
int y = Integer.parseInt(data[2]);
int flag = Integer.parseInt(data[3]);
mUpChessX = x;
mUpChessY = y;
mChess[x][y] = flag;
mChessFlag = flag;
String temp = x + ";" + y + ";" + flag;
mChessArray.push(temp);
invalidate();
isMe = true;
}
}
//下棋触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (!isWin) {
int x = (int) event.getX();
int y = (int) event.getY();
if (x < -mSingleHeight / 2 || x > mPanelWidth - mSingleHeight / 2 || y < 0 || y > mPanelWidth - mSingleHeight / 2) {
} else {
int indexX = (int) (x / mSingleHeight);
int indexY = (int) (y / mSingleHeight);
mUpChessX = indexX;
mUpChessY = indexY;
if (mChessFlag == CHESS_WHITE && isMe && mChess[indexX][indexY] == 0) {
putChess(indexX, indexY, CHESS_BLACK);
mChessFlag = CHESS_BLACK;
isMe = false;
invalidate();
} else if (mChessFlag == CHESS_BLACK && isMe && mChess[indexX][indexY] == 0) {
putChess(indexX, indexY, CHESS_WHITE);
mChessFlag = CHESS_WHITE;
isMe = false;
invalidate();
}
}
}
}
return true;
}
//判断是否已有结果
public int isWin(int[][] chess) {
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
int side = chess[i][j];
if (side == 0)
continue;
for (int k = 0; k < 5; k++) {
//check from vertical
if ((i - k >= 0 && i + 4 - k < 15) &&
(chess[i - k][j] == side &&
chess[i + 1 - k][j] == side &&
chess[i + 2 - k][j] == side &&
chess[i + 3 - k][j] == side &&
chess[i + 4 - k][j] == side)) {
return side;
}
//check from horizontal
if ((j - k >= 0 && j + 4 - k < 15) &&
(chess[i][j - k] == side &&
chess[i][j + 1 - k] == side &&
chess[i][j + 2 - k] == side &&
chess[i][j + 3 - k] == side &&
chess[i][j + 4 - k] == side)) {
return side;
}
//check from leftbevel
if ((i - k >= 0 && j - k >= 0 && i + 4 - k < 15 && j + 4 - k < 15) &&
(chess[i - k][j - k] == side &&
chess[i + 1 - k][j + 1 - k] == side &&
chess[i + 2 - k][j + 2 - k] == side &&
chess[i + 3 - k][j + 3 - k] == side &&
chess[i + 4 - k][j + 4 - k] == side)) {
return side;
}
//check from rightbevel
if ((i - k >= 0 && j + k < 15 && i + 4 - k < 15 && j - 4 + k >= 0) &&
(chess[i - k][j + k] == side &&
chess[i + 1 - k][j - 1 + k] == side &&
chess[i + 2 - k][j - 2 + k] == side &&
chess[i + 3 - k][j - 3 + k] == side &&
chess[i + 4 - k][j - 4 + k] == side)) {
return side;
}
}
}
}
return 0;
}
public void setCallBack(BleGameActivity bleGameActivity) {
this.mBleGameActivity = bleGameActivity;
}
public void setIsStart(boolean isStart) {
this.isStart = isStart;
isMe = isStart;
if (isStart) {
mChessFlag = CHESS_WHITE;
}
}
public void setAdress(String adress) {
mAdress = adress;
}
//重新开始
public void restartGame() {
mTvWin.setVisibility(View.INVISIBLE);
init();
invalidate();
}
//悔棋
public void returnUp() {
if (!isWin) {
if (mChessArray.size() == 0) {
} else {
String[] point = mChessArray.pop().split(";");
int x = Integer.parseInt(point[0]);
int y = Integer.parseInt(point[1]);
int flag = Integer.parseInt(point[2]);
mChess[x][y] = 0;
if (mChessArray.size() == 0) {
isMe = isStart;
mChessFlag = CHESS_WHITE;
mUpChessX = -1;
mUpChessY = -1;
} else {
String[] upChess = mChessArray.get(mChessArray.size() - 1).split(";");
mUpChessX = Integer.parseInt(upChess[0]);
mUpChessY = Integer.parseInt(upChess[1]);
if (flag == CHESS_WHITE) {
mChessFlag = CHESS_BLACK;
} else {
mChessFlag = CHESS_WHITE;
}
isMe = !isMe;
}
invalidate();
}
} else {
Toast.makeText(mBleGameActivity, "请重新开始!", Toast.LENGTH_SHORT).show();
}
}
public boolean isMe() {
return isMe;
}
public interface onBluetoothListener {
void onCommand(String temp);
}
public void setTvWin(TextView tvWin) {
mTvWin = tvWin;
}
}