· 编程思想  · 9 min read

五子棋的棋盘Android版

五子棋的棋盘Android版实现,具体上下文可以参考上一篇的五子棋AI实现中的代码

这里是实现一个五子棋的Android棋盘

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

//棋盘
public class Chessboard extends View implements IChessboard{

	//游戏状态常量:
    //已准备好,可开局
    private static final int READY = 1;
    //已开局
    private static final int RUNNING = 2;
    //已结束
    private static final int PLAYER_TWO_LOST = 3;
    private static final int PLAYER_ONE_LOST = 4;

    //当前状态,默认为可开局状态
    private int currentMode = READY;

	//画笔对象
	private final Paint paint = new Paint();

	//代表绿色
	private static final int GREEN = 0;
	private static final int NEW_GREEN = 1;

	//红色
	private static final int RED = 2;
	//黄色
	private static final int NEW_RED = 3;

	//点大小
    private static int pointSize = 20;

    //用于提示输赢的文本控件
	private TextView textView = null;

	//不同颜色的Bigmap数组
	private Bitmap[] pointArray = new Bitmap[4];

	//屏幕右下角的坐标值,即最大坐标值
    private static int maxX;
    private static int maxY;

    //第一点偏离左上角从像数,为了棋盘居中
	private static int yOffset;
	private static int xOffset;

	//两个玩家
	//第一个玩家默认为人类玩家
	private IPlayer player1 = new HumanPlayer();
	//第二个则根据选择人机战还是对战模式来初始化
	private IPlayer player2;
	//预先初始两个第二玩家
	//电脑玩家
	private static IPlayer computer = AiFactory.getInstance(2);
	//人类玩家
	private static final IPlayer human = new HumanPlayer();

	// 所有未下的空白点
	private final List<Point> allFreePoints = new ArrayList<Point>();

    public Chessboard(Context context, AttributeSet attrs) {
        super(context, attrs);
        setFocusable(true);

        //把三个颜色的点准备好,并放入数组
        Resources r = this.getContext().getResources();
        fillPointArrays(GREEN,r.getDrawable(R.drawable.green_point));
        fillPointArrays(NEW_GREEN,r.getDrawable(R.drawable.new_green_point));
        fillPointArrays(RED,r.getDrawable(R.drawable.red_point));
        fillPointArrays(NEW_RED,r.getDrawable(R.drawable.new_red_point));

        //设置画线时用的颜色
        paint.setColor(Color.LTGRAY);
   }


    //初始横线和竖线的数目
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        maxX = (int) Math.floor(w / pointSize);
        maxY = (int) Math.floor(h / pointSize);

        //设置X、Y座标微调值,目的整个框居中
        xOffset = ((w - (pointSize * maxX)) / 2);
        yOffset = ((h - (pointSize * maxY)) / 2);
        //创建棋盘上的线条
        createLines();
        //初始化棋盘上所有空白点
        createPoints();
    }

    //产生棋盘上所有的线
    private void createLines(){
    	for (int i = 0; i <= maxX; i++) {//竖线
    		lines.add(new Line(xOffset+i*pointSize-pointSize/2, yOffset, xOffset+i*pointSize-pointSize/2, yOffset+maxY*pointSize));
		}
    	for (int i = 0; i <= maxY; i++) {//横线
    		lines.add(new Line(xOffset, yOffset+i*pointSize-pointSize/2, xOffset+maxX*pointSize, yOffset+i*pointSize-pointSize/2));
		}
    }

    //画棋盘
    private List<Line> lines = new ArrayList<Line>();
    private void drawChssboardLines(Canvas canvas){
    	for (Line line : lines) {
    		canvas.drawLine(line.xStart, line.yStart, line.xStop, line.yStop, paint);
		}
    }

    //线类
    class Line{
    	float xStart,yStart,xStop,yStop;
		public Line(float xStart, float yStart, float xStop, float yStop) {
			this.xStart = xStart;
			this.yStart = yStart;
			this.xStop = xStop;
			this.yStop = yStop;
		}
    }

    //画点
    private void drawPoint(Canvas canvas,Point p,int color){
    	canvas.drawBitmap(pointArray[color],p.x*pointSize+xOffset,p.y*pointSize+yOffset,paint);
    }




    //设置运行状态
	public void setMode(int newMode) {
		currentMode = newMode;
		if(currentMode==PLAYER_TWO_LOST){
			//提示玩家2输了
			textView.setText(R.string.player_two_lost);
			currentMode = READY;
		}else if(currentMode==RUNNING){
			textView.setText(null);
		}else if(currentMode==READY){
			textView.setText(R.string.mode_ready);
		}else if(currentMode==PLAYER_ONE_LOST){
			//提示玩家1输了
			textView.setText(R.string.player_one_lost);
			currentMode = READY;
		}
	}


	//设置提示控件
	public void setTextView(TextView textView) {
		this.textView = textView;
	}

	//监听键盘事件
	@Override
    public boolean onKeyDown(int keyCode, KeyEvent msg) {
        if (currentMode == READY && (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_LEFT)) {
        	if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){//向右键,人机对战
        		player2 = computer;
        	}else if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){//向左键,人--人对战
        		player2 = human;
        	}
        	restart();
        	setMode(RUNNING);
        }else if(currentMode==RUNNING && keyCode == KeyEvent.KEYCODE_DPAD_DOWN){//重新开始
        	restart();
        	setMode(READY);
        }else{
        	return false;
        }
        return true;
	}

	public void startPlayerVsComputer(int level) {
		if (currentMode == READY) {
			if (level < 3) {
				computer = AiFactory.getInstance(level);
				player2 = computer;
				restart();
		    	setMode(RUNNING);
			}
			else {
				setMode(READY);
				textView.setText(R.string.geniusWinLabel);
			}
		}

	}

	public void startPlayerVsPlayer() {
		if (currentMode == READY) {
			player2 = human;
		}
		restart();
    	setMode(RUNNING);
	}

	public void restartGame() {
		if (currentMode == RUNNING) {
        	restart();
        	setMode(READY);
		}
	}

	//根据触摸点坐标找到对应点
	private Point newPoint(Float x, Float y){
		Point p = new Point(0, 0);
		for (int i = 0; i < maxX; i++) {
			if ((i * pointSize + xOffset) <= x
					&& x < ((i + 1) * pointSize + xOffset)) {
				p.setX(i);
			}
		}
		for (int i = 0; i < maxY; i++) {
			if ((i * pointSize + yOffset) <= y
					&& y < ((i + 1) * pointSize + yOffset)) {
				p.setY(i);
			}
		}
		return p;
	}

	//重新开始
	private void restart() {
		createPoints();
		player1.setChessboard(this);
		player2.setChessboard(this);
		setPlayer1Run();
		//刷新一下
		refressCanvas();
	}

	//是否已开局
	private boolean hasStart(){
		return currentMode==RUNNING;
	}

	//处理触摸事件
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//还没有开局,或者是按下事件,不处理,只处理开局后的触摸弹起事件
		if(!hasStart() || event.getAction()!=MotionEvent.ACTION_UP){
			return true;
		}
		//是否正在处理一步棋的过程中
		if(onProcessing()){
			return true;
		}

		playerRun(event);

		return true;
	}

	private synchronized void playerRun(MotionEvent event){
		if(isPlayer1Run()){//第一玩家下棋
			player1Run(event);
		}else if(isPlayer2Run()){//第二玩家下棋
			player2Run(event);
		}
	}


	private void player1Run(MotionEvent event){
		Point point = newPoint(event.getX(), event.getY());
		if(allFreePoints.contains(point)){//此棋是否可下
			setOnProcessing();
			player1.run(player2.getMyPoints(),point);
			//playerOnePoints.add(point);
			//刷新一下棋盘
			refressCanvas();
			//判断第一个玩家是否已经下了
			if(!player1.hasWin()){//我还没有赢
				if(player2==computer){//如果第二玩家是电脑
					//10豪秒后才给玩家2下棋
					refreshHandler.computerRunAfter(10);
				}else{
					setPlayer2Run();
				}
			}else{
				//否则,提示游戏结束
				setMode(PLAYER_TWO_LOST);
			}
		}
	}

	private void player2Run(MotionEvent event){
		Point point = newPoint(event.getX(), event.getY());
		if(allFreePoints.contains(point)){//此棋是否可下
			setOnProcessing();
			player2.run(player1.getMyPoints(),point);
//			playerTwoPoints.add(point);
			//刷新一下棋盘
			refressCanvas();
			//判断我是否赢了
			if(!player2.hasWin()){//我还没有赢
				setPlayer1Run();
			}else{
				//否则,提示游戏结束
				setMode(PLAYER_ONE_LOST);
			}
		}
	}


	private RefreshHandler refreshHandler = new RefreshHandler();
	class RefreshHandler extends Handler {

		//这个方法主要在指定的时刻发一个消息
        public void computerRunAfter(long delayMillis) {
        	this.removeMessages(0);
        	//发消息触发handleMessage函数
            sendMessageDelayed(obtainMessage(0), delayMillis);
        }

        //收到消息
        @Override
        public void handleMessage(Message msg) {
        	//电脑走一步棋子
    		player2.run(player1.getMyPoints(),null);
    		//刷新一下
    		refressCanvas();
    		if(!player2.hasWin()){
    			//人下
    			setPlayer1Run();
    		}else{//第二个玩家赢了
    			setMode(PLAYER_ONE_LOST);
    		}
        }
    };

    //是否正在下某一步棋过程中,主是电脑下棋时需要较长的计算时间,这期间一定不可以再响应触摸事件
	private boolean onProcessing() {
		return whoRun == -1;
	}


	//默认第一个玩家先行
	private int whoRun = 1;
	private void setPlayer1Run(){
		whoRun = 1;
	}
	private void setOnProcessing(){
		whoRun = -1;
	}
	//是否轮到人类玩家下子
	private boolean isPlayer1Run(){
		return whoRun==1;
	}

	//是否轮到人类玩家下子
	private boolean isPlayer2Run(){
		return whoRun==2;
	}

	private void setPlayer2Run(){
		whoRun = 2;
	}

	private void refressCanvas(){
		//触发onDraw函数
        Chessboard.this.invalidate();
	}

	private void drawPlayer1Point(Canvas canvas){
		int size = player1.getMyPoints().size()-1;
		if(size<0){
			return ;
		}
		for (int i = 0; i < size; i++) {
			drawPoint(canvas, player1.getMyPoints().get(i), GREEN);
		}
		//最后下的一个点标成黄色
		drawPoint(canvas, player1.getMyPoints().get(size), NEW_GREEN);
	}

	private void drawPlayer2Point(Canvas canvas){
		if(player2==null){
			return ;
		}
		int size = player2.getMyPoints().size()-1;
		if(size<0){
			return ;
		}
		for (int i = 0; i < size; i++) {
			drawPoint(canvas, player2.getMyPoints().get(i), RED);
		}
		//最后下的一个点标成黄色
		drawPoint(canvas, player2.getMyPoints().get(size), NEW_RED);
	}


	//初始化好三种颜色的点
    public void fillPointArrays(int color,Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(pointSize, pointSize, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, pointSize, pointSize);
        drawable.draw(canvas);
        pointArray[color] = bitmap;
    }

    //doRun方法操作的是看不见的内存数据,此方法内容数据以图画的方式表现出来,所以画之前数据一定要先准备好
    @Override
    protected void onDraw(Canvas canvas) {
    	drawChssboardLines(canvas);
    	//画鼠标所在的点
    	drawPlayer1Point(canvas);
    	//画电脑下的棋子
    	drawPlayer2Point(canvas);
    }


	@Override
	public List<Point> getFreePoints() {
		return allFreePoints;
	}

	//初始化空白点集合
	private void createPoints(){
		allFreePoints.clear();
		for (int i = 0; i < maxX; i++) {
			for (int j = 0; j < maxY; j++) {
				allFreePoints.add(new Point(i, j));
			}
		}
	}

	@Override
	public int getMaxX() {
		return maxX;
	}

	@Override
	public int getMaxY() {
		return maxY;
	}
}
Back to Blog

Related Posts

View All Posts »
React Native和Weex技术对比

React Native和Weex技术对比

React Native 和 Weex是比较流行的新一代高体验的跨平台开发框架。这个文档可以仔细分析它们之间的区别,帮助技术人员作出合适的选择。