android开发五子棋人人对战

转载请注明出处:http://blog.csdn.net/sw950729/article/details/51942858
本文出自:马云飞的博客
当初学编程的,都想做一个游戏,俄罗斯方块?贪吃蛇?不不不,今天我所讲的是五子棋双人对战,对比那些来说,应该算比较简单的了。好了,先贴上视频地址http://www.imooc.com/learn/641。
相信很多人都有看过,不过视频中,我发现有些代码是不需要的,而且还存在一些bug,针对视频所存在的bug我都做了调整,经测试,目前无bug。
下面先贴代码:
所需定义的内容:

    //画笔
    private Paint paint;
    //画布的宽度
    private int PanelWidth;
    //最大行数
    private static final int MAX_LINE = 15;
    //设置棋子的大小为棋盘格子的3/4
    private static final float Size = 3 * 1.0f / 4;
    //格子的高度(必须是float)
    private float SingelHeight;
    //黑白棋的素材
    private Bitmap WhiteBitmap;
    private Bitmap BlackBitmap;
    //判断谁先出棋(一般白先手)
    private boolean IsWhite = true;
    //存放黑白棋子坐标
    private ArrayList WhitePoint = new ArrayList<>();
    private ArrayList BlackPoint = new ArrayList<>();

    private boolean IsGameOver = false;

    //五子连珠算赢
    private static final int FIVE_POINT = 5;

对画笔的初始化:

 private void inital() {
        paint = new Paint();
        paint.setColor(0x88000000);
        paint.setAntiAlias(true);//抗锯齿
        paint.setDither(true);//防抖动
        paint.setStyle(Paint.Style.FILL);
        WhiteBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.white);
        BlackBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.black);

    }

对于自定义view有一定基础的小伙伴都知道,自定义一般都要实现2个方法,1:onSizeChanged(视图大小的改变);2:onMeasure(告诉父view,子视图占用多大的空间)
下面上代码,我都有详细注解,就不一个一个解释了:
onMeasure:

  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);
        //AT_MOST:specSize 代表的是最大可获得的空间;
        //EXACTLY:specSize 代表的是精确的尺寸;
        //UNSPECIFIED:对于控件尺寸来说,没有任何参考意义。
        //解决嵌套在ScrollView中时等情况出现的问题
        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
        }

        setMeasuredDimension(width, width);
    }

onSizeChanged:


 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        PanelWidth = w;
        SingelHeight = PanelWidth * 1.0f / MAX_LINE;
    //根据实际的棋盘格子的宽度按照一定的比例缩小棋子
    int onlyWidth = (int) (SingelHeight * Size);
    WhiteBitmap = Bitmap.createScaledBitmap(WhiteBitmap, onlyWidth, onlyWidth, false);
    BlackBitmap = Bitmap.createScaledBitmap(BlackBitmap, onlyWidth, onlyWidth, false);
}

好了,下面我们进图画图操作,需要的操作是,先画棋盘,在画棋子,然后判断游戏结束。

   protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        DrawBoard(canvas);
        DrawPiece(canvas);
        IsGameOver();
    }

绘制棋盘:

 //绘制棋盘
    //因为棋子的中心是在棋盘的点上的,所以上下左右有个边距,一般设为1/2
    private void DrawBoard(Canvas canvas) {
        for (int i = 0; i < MAX_LINE; i++) {
            int startX = (int) SingelHeight / 2;
            int endX = (int) (PanelWidth - SingelHeight / 2);
            int y = (int) ((0.5 + i) * SingelHeight);
            canvas.drawLine(startX, y, endX, y, paint);//画横线
            canvas.drawLine(y, startX, y, endX, paint);//画竖线
        }
    }

绘制棋子:

 private void DrawPiece(Canvas canvas) {
        for (int i = 0, n = WhitePoint.size(); i < n; i++) {
            Point whitePoint = WhitePoint.get(i);
            canvas.drawBitmap(WhiteBitmap,
                    (whitePoint.x + (1 - Size) / 2) * SingelHeight,
                    (whitePoint.y + (1 - Size) / 2) * SingelHeight, null);
        }
        for (int i = 0, n = BlackPoint.size(); i < n; i++) {
            Point blackPoint = BlackPoint.get(i);
            canvas.drawBitmap(BlackBitmap,
                    (blackPoint.x + (1 - Size) / 2) * SingelHeight,
                    (blackPoint.y + (1 - Size) / 2) * SingelHeight, null);
        }
    }

判断游戏是否结束:

 //游戏是否结束
    private void IsGameOver() {
        boolean WhiteWin = checkFiveInLine(WhitePoint);
        boolean BlackWin = checkFiveInLine(BlackPoint);
        boolean NoWin = checkNoWin(WhiteWin, BlackWin);
        if (WhiteWin) {
            IsGameOver = true;
            Dialog("白棋获胜!");
        } else if (BlackWin) {
            IsGameOver = true;
            Dialog("黑棋获胜");
        } else if (NoWin) {
            IsGameOver = true;
            Dialog("针锋相对,和棋了!");
        }
    }

游戏结果,为了开始新的一局(以及悔棋):

  public boolean GetGameResult() {
        return IsGameOver;
    }

    public int GetPieceSize() {
        if (WhitePoint.size() == 0 && BlackPoint.size() == 0) {
            return 0;
        }
        return 1;
    }

    private boolean checkNoWin(boolean whiteWin, boolean blackWin) {
        if (whiteWin || blackWin) {
            return false;
        }
        int max = MAX_LINE * MAX_LINE;
        //如果白棋和黑棋的总数等于棋盘格子数,说明和棋
        if (WhitePoint.size() + BlackPoint.size() == max) {
            return true;
        }
        return false;
    }

    //重新开始
    public void restart() {
        WhitePoint.clear();
        BlackPoint.clear();
        IsGameOver = false;
        IsWhite=true;
        invalidate();
    }

    //悔棋
    public void regret() {
        if (BlackPoint.size() > 0 || WhitePoint.size() > 0) {
            if (IsWhite) {
                BlackPoint.remove(BlackPoint.size() - 1);
                IsWhite = !IsWhite;
            } else {
                WhitePoint.remove(WhitePoint.size() - 1);
                IsWhite = !IsWhite;
            }
            invalidate();
        }
    }

弹出的dialog,这里你们可以自由改变:


    private void Dialog(String string) {
        new AlertDialog.Builder(getContext())
                .setTitle(string)
                .setPositiveButton("重来",
                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog,
                                                int which) {
                                restart();
                            }
                        })
                .setNeutralButton("查看棋盘!", new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                })
                .setNegativeButton("退出",
                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog,
                                                int which) {
                                MainActivity.getMainActivity().finish();
                            }
                        }).show();
    }

判断五子是否相连:

 private boolean checkFiveInLine(List point) {
        for (Point p : point) {
            int x = p.x;
            int y = p.y;

            boolean checkHorizontal = checkHorizontalFiveInLine(x, y, point);
            boolean checkVertical = checkVerticalFiveInLine(x, y, point);
            boolean checkLeftDiagonal = checkLeftFiveInLine(x, y, point);
            boolean checkRightDiagonal = checkRightFiveInLine(x, y, point);
            if (checkHorizontal || checkVertical || checkLeftDiagonal || checkRightDiagonal) {
                return true;
            }
        }

        return false;
    }

这里我只贴一个,其他一样的,就是改变x,y的坐标而已:

//横向五子连珠
    private boolean checkHorizontalFiveInLine(int x, int y, List point) {
        int count = 1;
        for (int i = 1; i < FIVE_POINT; i++) {
            if (point.contains(new Point(x - i, y))) {
                count++;
            } else {
                break;
            }
        }
        if (count == FIVE_POINT) {
            return true;
        }
        return false;
    }

这里,你们应该发现,我和视频中的判断是不一样的,比他少了判断右边的,这样只是判断次数多了一点,如果右边也判断的话,在人机对战中,我可以说,你们会疯掉。。。
好了,接下来是点击事件,然后开始下子:


    public boolean onTouchEvent(MotionEvent event) {
        if (IsGameOver) {
            return false;
        }
        if (event.getAction() == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            Point p = getValidPoint(x, y);
            if (WhitePoint.contains(p) || BlackPoint.contains(p)) {
                return false;
            }

            if (IsWhite) {
                WhitePoint.add(p);
            } else {
                BlackPoint.add(p);
            }
            invalidate();
            IsWhite = !IsWhite;
            return true;
        }
        return true;
    }

棋子的落点位置:

  private Point getValidPoint(int x, int y) {
        return new Point((int) (x / SingelHeight), (int) (y / SingelHeight));
    }

这样一个简单的五子棋功能就实现了,有人会说为什么不保存数据?其实我们不需要保存数据,我们只要让视图全屏就ok了。
代码如下:

<resources>
    <style name="AppTheme" parent="android:Theme.Translucent.NoTitleBar.Fullscreen">
    style>

resources>

这里我没有考虑到禁手的问题,感觉如果考虑到禁手的话,算法比较复杂,人机对战,上周我花了一周的时间也差不多解决了,打草稿就花了差不多10多张纸~~~功能没什么问题了,有空还在找bug。后期我会贴上人机对战的算法以及app。不过代码就不贴了。因为我写的比较复杂。而且如果没思路的话,把代码给你,你也要看好半天才能理解。
好了,今天就说到这边把,我的android交流群:232748032。欢迎新手,大神的加入。

你可能感兴趣的:(android进阶)