上周花了一周时间做的课程设计的项目,实现的功能如下:

 基本功能:
(1) 该APP能够通过蓝牙自动搜索周围其他使用了该APP的手机,用户可选择其中某一个APP发起对战的要求,被发起方可以同意或者拒绝;
(2) 双方可以实现五子棋蓝牙对战;
(3) 具备悔棋等功能。 
(4) 实现人机对战。提供难度选择。
(5)提供用户战绩排名系统。

项目已经上传到Github:https://github.com/jiangzhengnan/PumpkinGoBang.git
Github跳转 下面是界面截图和实现原理代码分析。 实现部分分为3点: 1、简单人机算法实现。 2、普通人机算法实现。 3、蓝牙模块客户端服务端实现。
一、运行截图: 主界面:


人人对战界面:


蓝牙搜索功能:


蓝牙对战界面:


简单人机功能:


普通人机功能:


二、实现原理: 1、简单难度电脑算法实现: 因为时间比较赶,所以人机算法这块实现得比较简单,没有去学习使用专业的五子棋人机算法,比如五元组分值比较法或者正规的博弈算法。 简单难度算法就是随机在落子点周围生成一个点:
/** * 简单模式自动下棋的电脑 * * @param x * @param y     玩家下的坐标 * @param Color 玩家下的棋的颜色    黑12 *              

* x&y */private void naocanautomatic(int x, int y, int Color) { int[][] temp = {{x - 1, y - 1}, {x, y - 1}, {x + 1, y - 1}, {x - 1, y}, {x + 1, y}, {x - 1, y + 1}, {x, y + 1}, {x + 1, y + 1}}; ArrayList<int[]> templist = new ArrayList<>(); for (int i = 0; i < temp.length; i++) { if (temp[i][0] >= 0 && temp[i][0] < 13 && temp[i][1] >= 0 && temp[i][1] < 13) { templist.add(temp[i]); } } //判断是否已经下过 panduanshifouyijingxiaguo(templist); int num = (int) (Math.random() * templist.size()); int a = templist.get(num)[0]; int b = templist.get(num)[1]; putChess(a, b, Color);}

这里要保存已经下过的点位,并判断是否已经下过,难点是在于如果下的位置在角落处(或周围已经没有棋子可以自动生成位置了,这时要递归判断并随机生成一个新的位置,直到全图都没有位置了为止终止递归):
/** * 递归判断是否已经下过 * * @param templist */private void panduanshifouyijingxiaguo(ArrayList<int[]> templist) {    for (int i = 0; i < storageHadChess.size(); i++) {        //如有重复,则删掉        for (int j = 0; j < templist.size(); j++) {            if (storageHadChess.get(i)[0] == templist.get(j)[0] && storageHadChess.get(i)[1] == templist.get(j)[1]) {                templist.remove(j);                //递归防止周围没有字落下时直接崩掉                if (templist.size() == 0) {                    templist.add(new int[]{(int) (Math.random() * (GRID_SIZE - 2)), (int) (Math.random() * (GRID_SIZE - 2))});                    //  Log.d("whalea", " " + (int) (Math.random() * (GRID_SIZE - 2)));                    panduanshifouyijingxiaguo(templist);                }            }        }    }}
2、普通难度算法实现: 普通难度的算法实现地比较纠结,在简单人机的基础上(这里可以称之为“随机落子算法”~!),加入了三点判断功能,就是黑白双方一旦有3点相连会自动往这三点的两端随机堵一个点,并继续递归判断下过的位置,这个循环写得比较长,因为没有把重复的代码抽取出来。
/** * 普通模式自动下棋的电脑 * 12 * * @param x * @param y * @param Color */private void normalautomatic(int x, int y, int Color) {    int duishouColor = 0;//对手的颜色    //根据我方颜色推测出对手颜色    if (Color == 1) {        duishouColor = 2;    } else {        duishouColor = 1;    }    //判断我方是否有3个连成一线了    for (int i = 0; i < GRID_SIZE - 1; i++) //i表示列(根据宽度算出来的)        for (int j = 0; j < GRID_SIZE - 1; j++) { //i表示行(根据高度算出来的)            //检测横轴三个相连            if ((((i + 3) < (GRID_SIZE - 1)) &&                    (mGridArray[i][j] == Color) && (mGridArray[i + 1][j] == Color) && (mGridArray[i + 2][j] == Color)) ||                    (((i + 3) < (GRID_SIZE - 1)) &&                            (mGridArray[i][j] == duishouColor) && (mGridArray[i + 1][j] == duishouColor) && (mGridArray[i + 2][j] == duishouColor))) {                //如果有三个点相连了                //先判断是否已经测试过这三个点                boolean aa = false;                for (int p = 0; p < cunchusandianArraylist.size(); p++) {                    String sandiantemp = cunchusandianArraylist.get(p);                    String[] sandiantemps = sandiantemp.split(":");                    //如果这三个点已经存在                    if ((Integer.parseInt(sandiantemps[0]) == i) &&                            (Integer.parseInt(sandiantemps[1]) == j) &&                            (Integer.parseInt(sandiantemps[2]) == (i + 1)) &&                            (Integer.parseInt(sandiantemps[3]) == j) &&                            (Integer.parseInt(sandiantemps[4]) == (i + 2)) &&                            (Integer.parseInt(sandiantemps[5]) == j)) {                        aa = true;                    }                }                if (aa == true) {                } else {                    //在两边端点位置随机下一个                    ifsangedianxianglian(i - 1, j, i + 3, j, Color);                    cunchusandianArraylist.add(i + ":" + j + ":" + (i + 1) + ":" + j + ":" + (i + 2) + ":" + j);                    return;                }            }            //纵轴3个相连            if ((((j + 3) < (GRID_SIZE - 1)) &&                    (mGridArray[i][j] == Color) && (mGridArray[i][j + 1] == Color) && (mGridArray[i][j + 2] == Color)) ||                    (((j + 3) < (GRID_SIZE - 1)) &&                            (mGridArray[i][j] == duishouColor) && (mGridArray[i][j + 1] == duishouColor) && (mGridArray[i][j + 2] == duishouColor))) {                //如果有三个点相连了                //先判断是否已经测试过这三个点                boolean aa = false;                for (int p = 0; p < cunchusandianArraylist.size(); p++) {                    String sandiantemp = cunchusandianArraylist.get(p);                    String[] sandiantemps = sandiantemp.split(":");                    if ((Integer.parseInt(sandiantemps[0]) == i) &&                            (Integer.parseInt(sandiantemps[1]) == j) &&                            (Integer.parseInt(sandiantemps[2]) == i) &&                            (Integer.parseInt(sandiantemps[3]) == (j + 1)) &&                            (Integer.parseInt(sandiantemps[4]) == i) &&                            (Integer.parseInt(sandiantemps[5]) == (j + 2))) {                        aa = true;                    }                }                if (aa == true) {                } else {                    //在两边端点位置随机下一个                    ifsangedianxianglian(i, j - 1, i, j + 3, Color);                    cunchusandianArraylist.add(i + ":" + j + ":" + i + ":" + (j + 1) + ":" + i + ":" + (j + 2));                    return;                }            }            //左上到右下3个相连            if ((((j + 3) < (GRID_SIZE - 1)) && ((i + 3) < (GRID_SIZE - 1)) &&                    (mGridArray[i][j] == Color) && (mGridArray[i + 1][j + 1] == Color) && (mGridArray[i + 2][j + 2] == Color)) ||                    (((j + 3) < (GRID_SIZE - 1)) && ((i + 3) < (GRID_SIZE - 1)) &&                            (mGridArray[i][j] == duishouColor) && (mGridArray[i + 1][j + 1] == duishouColor) && (mGridArray[i + 2][j + 2] == duishouColor))) {                //如果有三个点相连了                //先判断是否已经测试过这三个点                boolean aa = false;                for (int p = 0; p < cunchusandianArraylist.size(); p++) {                    String sandiantemp = cunchusandianArraylist.get(p);                    String[] sandiantemps = sandiantemp.split(":");                    if ((Integer.parseInt(sandiantemps[0]) == i) &&                            (Integer.parseInt(sandiantemps[1]) == j) &&                            (Integer.parseInt(sandiantemps[2]) == (i + 1)) &&                            (Integer.parseInt(sandiantemps[3]) == (j + 1)) &&                            (Integer.parseInt(sandiantemps[4]) == (i + 2)) &&                            (Integer.parseInt(sandiantemps[5]) == (j + 2))) {                        aa = true;                    }                }                if (aa == true) {                } else {                    ifsangedianxianglian(i - 1, j - 1, i + 3, j + 3, Color);                    cunchusandianArraylist.add(i + ":" + j + ":" + (i + 1) + ":" + (j + 1) + ":" + (i + 2) + ":" + (j + 2));                    return;                }            }            //右上到左下3个相连            if ((((i - 3) >= 0) && ((j + 3) < (GRID_SIZE - 1)) &&                    (mGridArray[i][j] == Color) && (mGridArray[i - 1][j + 1] == Color) && (mGridArray[i - 2][j + 2] == Color)) ||                    (((i - 3) >= 0) && ((j + 3) < (GRID_SIZE - 1)) &&                            (mGridArray[i][j] == duishouColor) && (mGridArray[i - 1][j + 1] == duishouColor) && (mGridArray[i - 2][j + 2] == duishouColor))) {                //如果有三个点相连了                //先判断是否已经测试过这三个点                boolean aa = false;                for (int p = 0; p < cunchusandianArraylist.size(); p++) {                    String sandiantemp = cunchusandianArraylist.get(p);                    String[] sandiantemps = sandiantemp.split(":");                    if ((Integer.parseInt(sandiantemps[0]) == i) &&                            (Integer.parseInt(sandiantemps[1]) == j) &&                            (Integer.parseInt(sandiantemps[2]) == (i - 1)) &&                            (Integer.parseInt(sandiantemps[3]) == (j + 1)) &&                            (Integer.parseInt(sandiantemps[4]) == (i - 2)) &&                            (Integer.parseInt(sandiantemps[5]) == (j + 2))) {                        aa = true;                    }                }                if (aa == true) {                } else {                    ifsangedianxianglian(i + 1, j - 1, i - 3, j + 3, Color);                    cunchusandianArraylist.add(i + ":" + j + ":" + (i - 1) + ":" + j + 1 + ":" + (i - 2) + ":" + (j + 2));                    return;                }            }        }    int[][] temp = {{x - 1, y - 1}, {x, y - 1}, {x + 1, y - 1}, {x - 1, y}, {x + 1, y}, {x - 1, y + 1}, {x, y + 1}, {x + 1, y + 1}};    ArrayList<int[]> templist = new ArrayList<>();    for (int k = 0; k < temp.length; k++) {        if (temp[k][0] >= 0 && temp[k][0] < 13 && temp[k][1] >= 0 && temp[k][1] < 13) {            templist.add(temp[k]);        }        //判断是否已经下过        panduanshifouyijingxiaguo(templist);        int num = (int) (Math.random() * templist.size());        int a = templist.get(num)[0];        int b = templist.get(num)[1];        putChess(a, b, Color);        return;    }}

3、蓝牙连接实现代码: 整个项目是客户端与服务端一体的,所以蓝牙部分大概可以分为三个模块: 扫描模块: 实首先打开一个广播扫描周围设备:
//接收广播/** * 接受广播,并显示尚未配对的可用的周围所有蓝牙设备 */private class BluetoothReceiver extends BroadcastReceiver {    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        //如果是正在扫描状态        if (BluetoothDevice.ACTION_FOUND.equals(action)) {            //只要BluetoothReceiver接收到来自于系统的广播,这个广播是什么呢,是我找到了一个远程蓝牙设备            //Intent代表刚刚发现远程蓝牙设备适配器的对象,可以从收到的Intent对象取出一些信息            BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);            // 如果该设备已经被配对,则跳过            //  if (bluetoothDevice.getBondState() != BluetoothDevice.BOND_BONDED) {            if (!devices.contains(bluetoothDevice)) {                //设备数组获得新的设备信息并更新adapter                deviceNameAndDresss.add(new Device(bluetoothDevice.getName(), bluetoothDevice.getAddress(),bluetoothDevice.getBondState()));                //添加新的设备到设备Arraylist                devices.add(bluetoothDevice);                deviceshowAdapter.notifyDataSetChanged();            }        }    }}
也可以调用BlueToothAapter的startDiscovery()方法主动进行扫描:
//扫描周围的蓝牙设备按钮监听器private class SaoMiaoButtonListener implements View.OnClickListener {    @Override    public void onClick(View v) {        ObjectAnimator animator = ObjectAnimator.ofFloat(v,"rotation",0,359);        animator.setRepeatCount(12);        animator.setDuration(1000);        animator.start();        isQuering = true;        Toast.makeText(BlueToothFindOthersAty.this, "开始扫描", Toast.LENGTH_SHORT).show();        //清空列表        deviceNameAndDresss.clear();        //获得已配对的蓝牙设备        Set pairedDevices = bluetoothAdapter.getBondedDevices();        if (pairedDevices.size() > 0) {            for (BluetoothDevice device : pairedDevices) {                if (!devices.contains(device)) {                    deviceNameAndDresss.add(new Device(device.getName(), device.getAddress(),device.getBondState()));                    devices.add(device);                }            }        }        deviceshowAdapter.setDevices(deviceNameAndDresss);        deviceshowAdapter.notifyDataSetChanged();        //开始扫描周围的可见的蓝牙设备        bluetoothAdapter.startDiscovery();    }}
服务端等待连接模块: 这里服务端比较简单,通过accpet方法监听连接就可以了。
//开启子线程等待连接new Thread(new Runnable() {    @Override    public void run() {        try {            //开启服务端            //等待客户端接入            while (true) {                bluetoothServerSocket = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(benjiname, Config.UUID);                fuwuSocket = bluetoothServerSocket.accept();                if (fuwuSocket.isConnected()) {                    runOnUiThread(new Runnable() {                        @Override                        public void run() {                            Toast.makeText(BlueToothFindOthersAty.this, "接收挑战请求,建立连接成功!", Toast.LENGTH_SHORT);                            //执行socket方法                             BlueToothGameAty blueToothGameAty = new BlueToothGameAty();                            blueToothGameAty.blueToothGameAty.manageConnectedSocket(fuwuSocket, false);                     //       blueToothGameAty.blueToothGameAty.chushihua(blueToothGameAty);                        }                    });                    //跳转到蓝牙游戏activity                    Intent i = new Intent(BlueToothFindOthersAty.this,BlueToothGameAty.class);                    startActivity(i);                    //初始化线程来传输数据                    // manageConnectedSocket(fuwuSocket);                    //得到连接之后关闭ServerSocket                    // bluetoothServerSocket.close();                    //打断线程                    //   Thread.interrupted();                }            }        } catch (IOException e) {            e.printStackTrace();            Log.d("whalea", "没读到的原因!:" + e.getMessage());        }    }}).start();
客户端主动连接模块: 客户端socket使用connet()方法主动连接。
/** * 建立连接的方法 * * @param position  位置 * @param isfaqiren */private void buildConnect(int position, boolean isfaqiren) {    //自己主动去连接    BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceNameAndDresss.get(position).getDeviceAddress());    Boolean result = false;    try {        //先进行配对        //如果没有配对        Log.d("whalea", "开始配对");        if (device.getBondState() == BluetoothDevice.BOND_NONE) {            Method createBondMethod = null;            createBondMethod = BluetoothDevice.class                    .getMethod("createBond");            Log.d("whalea", "开始配对");            result = (Boolean) createBondMethod.invoke(device);        }        //如果已经配对好了        else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {            //获得客户端Socket            kehuduanSocket = device.createRfcommSocketToServiceRecord(Config.UUID);            final AlertDialog aDialog = new AlertDialog.Builder(BlueToothFindOthersAty.this).                    setTitle("发起对战").                    setMessage("确认挑战玩家:" + deviceNameAndDresss.get(position).getDeviceName() + "吗?")                    .setNegativeButton("确定", new DialogInterface.OnClickListener() {                        @Override                        public void onClick(DialogInterface dialog, int which) {                            new Thread(new Runnable() {                                @Override                                public void run() {                                    //先停止扫描,以防止之后的连接被阻塞                                    bluetoothAdapter.cancelDiscovery();                                    try {                                        //开始连接,发送连接请求                                        kehuduanSocket.connect();                                        if (!bluetoothAdapter.isEnabled()) {                                            bluetoothAdapter.enable();                                        }                                        if (kehuduanSocket.isConnected()) {                                            runOnUiThread(new Runnable() {                                                @Override                                                public void run() {                                                    Toast.makeText(BlueToothFindOthersAty.this, "连接成功!!", Toast.LENGTH_SHORT).show();                                                    //执行socket方法                                                     BlueToothGameAty blueToothGameAty = new BlueToothGameAty();                                                    blueToothGameAty.blueToothGameAty.manageConnectedSocket(kehuduanSocket, true);                                                 //   blueToothGameAty.blueToothGameAty.chushihua(blueToothGameAty);                                                }                                            });                                            //跳转到蓝牙游戏activity                                            Intent i = new Intent(BlueToothFindOthersAty.this,BlueToothGameAty.class);                                            startActivity(i);                                        }                                    } catch (final IOException e) {                                        runOnUiThread(new Runnable() {                                            @Override                                            public void run() {                                                Toast.makeText(BlueToothFindOthersAty.this, "连接失败!!" + e.getMessage(), Toast.LENGTH_SHORT).show();                                            }                                        });                                             /*   try {                                                    kehuduanSocket.close();                                                } catch (IOException e1) {                                                }                                                return;*/                                    }                                    // manageConnectedSocket(kehuduanSocket);                                    //之后关闭socket,清除内部资源                                      /*      try {                                                kehuduanSocket.close();                                            } catch (IOException e) {                                                e.printStackTrace();                                            }*/                                }                            }).start();                        }                    })                    .setPositiveButton("取消", null).show();        }    } catch (Exception e) {        e.printStackTrace();    }}

其他初始化的代码都在项目里面就不赘述了,可以自己下载来看。

*********************************************************我是分割线n(*≧▽≦*)n******************************************************** 本来有很多课程设计项目可供选择的= =不过最后还是选了比较有挑战性的这个。 之前一直没接触过蓝牙开发,网上的demo或者例子又都很难理解(可能是没有科学上网的原因)。 最终还是靠着官网的API才慢慢写出了一开始的连接demo,然后一步步测试传输数据。 哎,你们呐,还是要多看API!



更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Android(安卓)Studio真机无线调试(2020最新亲测有用)
  3. Android(安卓)项目实践(一)——开发流程
  4. 使用Qt开发Android应用程序(Qt on Android),连接安卓手机真机调试时
  5. Android(安卓)Socket连接(模拟心跳包,断线重连,发送数据等)
  6. Android(安卓)蓝牙4.0(BLE)开发实现对蓝牙的写入数据和读取数据
  7. Android爪机连接蓝牙设备并进行通信的小例子
  8. Android设备获取扫码枪扫描的内容与可能遇到的问题解决
  9. android Ble4.0蓝牙开发之搜索慢、startLeScan()过时,6.0以上不需

随机推荐

  1. android 进程与线程 - 开发文档翻译 - 进
  2. 说说 Android(安卓)的常见 UI 控件
  3. (一)Android事件分发机制 - View篇
  4. Android中的Parcel机制 实现Bundle传递对
  5. Android系列之浅谈Android(安卓)3D旋转
  6. android - 为安全而设计 - 1 - 开发文档
  7. Cordova与Android之一 Activity跳转
  8. Flash Android(安卓)ANE打包之基本流程
  9. Android软件安全与逆向分析
  10. Android中 GridLayout 【网格布局】 全面