├── 源码 ├── 博弈单元 │ ├── drop_point.txt │ ├── lab3 │ │ ├── test │ │ │ ├── drop_point.txt │ │ │ ├── my_solvent.h5 │ │ │ ├── picture │ │ │ │ ├── 1.jpg │ │ │ │ ├── 2.jpg │ │ │ │ ├── 3.jpg │ │ │ │ ├── 4.jpg │ │ │ │ └── 5.jpg │ │ │ ├── __pycache__ │ │ │ │ ├── move.cpython-37.pyc │ │ │ │ ├── Camera.cpython-37.pyc │ │ │ │ ├── DrawUI.cpython-37.pyc │ │ │ │ ├── MyModel.cpython-37.pyc │ │ │ │ ├── capture.cpython-37.pyc │ │ │ │ ├── Checkboard.cpython-37.pyc │ │ │ │ └── AI_alpha_beta.cpython-37.pyc │ │ │ ├── MyModel.py │ │ │ ├── Checkboard.py │ │ │ ├── mygame.py │ │ │ ├── Camera.py │ │ │ ├── move.py │ │ │ ├── mygame_UI.py │ │ │ ├── recognize.py │ │ │ ├── DrawUI.py │ │ │ ├── capture.py │ │ │ └── AI_alpha_beta.py │ │ └── train │ │ │ ├── test.py │ │ │ ├── my_solvent.h5 │ │ │ ├── __pycache__ │ │ │ ├── GA.cpython-37.pyc │ │ │ ├── DrawUI.cpython-37.pyc │ │ │ ├── MyModel.cpython-37.pyc │ │ │ ├── Checkboard.cpython-37.pyc │ │ │ ├── AI_alpha_beta.cpython-37.pyc │ │ │ ├── two_AI_chess.cpython-37.pyc │ │ │ └── two_AI_chess_UI.cpython-37.pyc │ │ │ ├── MyModel.py │ │ │ ├── Checkboard.py │ │ │ ├── GA.py │ │ │ ├── two_AI_chess.py │ │ │ ├── two_AI_chess_UI.py │ │ │ ├── DrawUI.py │ │ │ └── AI_alpha_beta.py │ ├── my_solvent.h5 │ ├── MyModel.py │ ├── test.py │ ├── Checkboard.py │ ├── mygame.py │ ├── Camera.py │ ├── mygame_UI.py │ ├── recognize.py │ ├── DrawUI.py │ ├── capture.py │ └── AI_alpha_beta.py ├── 控制单元 │ ├── my_model.pth │ ├── transmit.py │ ├── sever.py │ ├── position.txt │ ├── train.txt │ ├── ANN.py │ ├── move.py │ └── README.md └── 视觉单元 │ ├── picture │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ └── 5.jpg │ ├── Camera.py │ └── capture.py ├── README.md └── LICENSE /源码/博弈单元/drop_point.txt: -------------------------------------------------------------------------------- 1 | 3 3 -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/drop_point.txt: -------------------------------------------------------------------------------- 1 | 3 2 -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/test.py: -------------------------------------------------------------------------------- 1 | print("{:d}".format(0x7fffffff)) -------------------------------------------------------------------------------- /源码/控制单元/my_model.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/控制单元/my_model.pth -------------------------------------------------------------------------------- /源码/博弈单元/my_solvent.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/my_solvent.h5 -------------------------------------------------------------------------------- /源码/视觉单元/picture/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/视觉单元/picture/1.jpg -------------------------------------------------------------------------------- /源码/视觉单元/picture/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/视觉单元/picture/2.jpg -------------------------------------------------------------------------------- /源码/视觉单元/picture/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/视觉单元/picture/3.jpg -------------------------------------------------------------------------------- /源码/视觉单元/picture/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/视觉单元/picture/4.jpg -------------------------------------------------------------------------------- /源码/视觉单元/picture/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/视觉单元/picture/5.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/my_solvent.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/my_solvent.h5 -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/picture/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/picture/1.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/picture/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/picture/2.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/picture/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/picture/3.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/picture/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/picture/4.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/picture/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/picture/5.jpg -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/my_solvent.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/my_solvent.h5 -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/move.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/move.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/GA.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/GA.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/Camera.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/Camera.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/DrawUI.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/DrawUI.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/MyModel.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/MyModel.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/capture.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/capture.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/DrawUI.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/DrawUI.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/Checkboard.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/Checkboard.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/MyModel.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/MyModel.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/Checkboard.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/Checkboard.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/__pycache__/AI_alpha_beta.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/test/__pycache__/AI_alpha_beta.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/AI_alpha_beta.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/AI_alpha_beta.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/two_AI_chess.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/two_AI_chess.cpython-37.pyc -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/__pycache__/two_AI_chess_UI.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Robin-WZQ/Gobang-Chess/HEAD/源码/博弈单元/lab3/train/__pycache__/two_AI_chess_UI.cpython-37.pyc -------------------------------------------------------------------------------- /源码/控制单元/transmit.py: -------------------------------------------------------------------------------- 1 | import socket 2 | new_socket = socket.socket() #创建socket对象 3 | ip = "192.168.149.1" # 树莓派地址 4 | port = 22 # 设置默认端口 5 | new_socket.connect((ip,port)) 6 | i=0 7 | while 1: 8 | x = input() 9 | y= input() 10 | z = input() 11 | t = x+","+y+","+z 12 | new_socket.send(t.encode()) 13 | i+=1 14 | if i==4: 15 | back_str = new_socket.recv(1024).decode() #结束数据 16 | break 17 | new_socket.close() #关闭客户端 18 | print("客户端结束运行") -------------------------------------------------------------------------------- /源码/博弈单元/MyModel.py: -------------------------------------------------------------------------------- 1 | # 用于加载模型和拟合评估值 2 | from keras.models import load_model 3 | import numpy as np 4 | from AI_alpha_beta import Line_Points 5 | 6 | class Model: 7 | def __init__(self): 8 | # 选择想要加载的模型 9 | self.model = load_model('my_solvent.h5', compile=False) 10 | 11 | # 输入当前局面,输出评估函数 12 | def get_score_ANN(self, board): 13 | x_input = np.zeros((1, Line_Points ** 2), dtype=int) 14 | for j in range(Line_Points): 15 | for i in range(Line_Points): 16 | x_input[0, j * Line_Points + i] = board[j][i] 17 | score = self.model.predict(x_input) 18 | return score -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/MyModel.py: -------------------------------------------------------------------------------- 1 | # 用于加载模型和拟合评估值 2 | from keras.models import load_model 3 | import numpy as np 4 | from AI_alpha_beta import Line_Points 5 | 6 | class Model: 7 | def __init__(self): 8 | # 选择想要加载的模型 9 | self.model = load_model('my_solvent.h5', compile=False) 10 | 11 | # 输入当前局面,输出评估函数 12 | def get_score_ANN(self, board): 13 | x_input = np.zeros((1, Line_Points ** 2), dtype=int) 14 | for j in range(Line_Points): 15 | for i in range(Line_Points): 16 | x_input[0, j * Line_Points + i] = board[j][i] 17 | score = self.model.predict(x_input) 18 | return score -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于树莓派机械臂的五子棋博弈系统 2 | 3 | This is a project based on machine learning and deep learning method for playing Gobang by controlling mechanical arm. More details have been shown in \源码\控制\README.md 4 | 5 | 专业大作业,在天锐、云皓和我的共同努力下,项目得以完成。本人负责机械臂的算法部署、串口通信和舵机控制三个部分,在\源码\控制单元中得见,详解请见\源码\控制\README.md 6 | 7 | 机械臂购买链接:[幻尔 树莓派4b 机械臂ArmPi AI视觉识别机械手臂 Python可编程机器人 WIFI远程控制 标准版(成品) Pi 4B/2G 现货【图片 价格 品牌 报价】-京东 (jd.com)](https://item.jd.com/10020757990850.html#none) 8 | 9 | ### 系统概要设计 10 | ![屏幕截图 2021-07-26 215507](https://user-images.githubusercontent.com/60317828/127077602-43ea4c68-2e19-40f8-9330-94e93ca1041d.png) 11 | 12 | ### 系统流程图 13 | ![屏幕截图 2021-07-26 215530](https://user-images.githubusercontent.com/60317828/127077624-e797436f-ec0b-4d2b-a37e-c77ffc860e32.png) 14 | 15 | -------------------------------------------------------------------------------- /源码/控制单元/sever.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | def main(): 4 | ''' 5 | socket communication between Windows and Linux 6 | ''' 7 | #服务端 8 | new_socket = socket.socket() # 创建 socket 对象 9 | ip = "192.168.149.1" # 获取本地主机名 10 | port = 22 # 设置端口 11 | new_socket.bind((ip, port)) # 绑定端口 12 | new_socket.listen(20) # 等待客户端连接并设置最大连接数 13 | while True: 14 | init_position() 15 | new_cil, addr = new_socket.accept() # 建立客户端连接。 16 | print('新进来的客户端的地址:', addr) 17 | t = new_cil.recv(1024).decode() 18 | t = t.split(',') 19 | put_chess(int(t[0]),int(t[1])) 20 | if(int(t[2]==0)): 21 | new_cil.close() # 关闭连接 22 | 23 | main() 24 | -------------------------------------------------------------------------------- /源码/控制单元/position.txt: -------------------------------------------------------------------------------- 1 | -10 10 2 | -7.5 10 3 | -5 10 4 | -2.5 10 5 | 0 10 6 | 2.5 10 7 | 5 10 8 | 7.5 10 9 | 10 10 10 | -10 12.5 11 | -7.5 12.5 12 | -5 12.5 13 | -2.5 12.5 14 | 0 12.5 15 | 2.5 12.5 16 | 5 12.5 17 | 7.5 12.5 18 | 10 12.5 19 | -10 15 20 | -7.5 15 21 | -5 15 22 | -2.5 15 23 | 0 15 24 | 2.5 15 25 | 5 15 26 | 7.5 15 27 | 10 15 28 | -10 17.5 29 | -7.5 17.5 30 | -5 17.5 31 | -2.5 17.5 32 | 0 17.5 33 | 2.5 17.5 34 | 5 17.5 35 | 7.5 17.5 36 | 10 17.5 37 | -10 20 38 | -7.5 20 39 | -5 20 40 | -2.5 20 41 | 0 20 42 | 2.5 20 43 | 5 20 44 | 7.5 20 45 | 10 20 46 | -10 22.5 47 | -7.5 22.5 48 | -5 22.5 49 | -2.5 22.5 50 | 0 22.5 51 | 2.5 22.5 52 | 5 22.5 53 | 7.5 22.5 54 | 10 22.5 55 | -10 25 56 | -7.5 25 57 | -5 25 58 | -2.5 25 59 | 0 25 60 | 2.5 25 61 | 5 25 62 | 7.5 25 63 | 10 25 64 | -10 27.5 65 | -7.5 27.5 66 | -5 27.5 67 | -2.5 27.5 68 | 0 27.5 69 | 2.5 27.5 70 | 5 27.5 71 | 7.5 27.5 72 | 10 27.5 73 | -10 30 74 | -7.5 30 75 | -5 30 76 | -2.5 30 77 | 0 30 78 | 2.5 30 79 | 5 30 80 | 7.5 30 81 | 10 30 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Robin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/MyModel.py: -------------------------------------------------------------------------------- 1 | # 用于加载模型和拟合评估值 2 | import keras 3 | import numpy as np 4 | from keras.layers import Dense 5 | from AI_alpha_beta import Line_Points 6 | 7 | n = [Line_Points * Line_Points, 16, 32, 64, 24, 8, 1] # 每层神经元的个数 8 | 9 | class Model: 10 | def __init__(self): 11 | md = keras.Sequential() 12 | md.add(Dense(n[1], activation='relu', input_dim=n[0])) 13 | md.add(Dense(n[2], activation='relu')) 14 | md.add(Dense(n[3], activation='relu')) 15 | md.add(Dense(n[4], activation='relu')) 16 | md.add(Dense(n[5], activation='relu')) 17 | md.add(Dense(n[6], activation=None)) 18 | # 选择想要加载的模型 19 | self.model = md 20 | 21 | def my_set_weights(self, x): 22 | ls = [] 23 | sum = 0 24 | for i in range(6): 25 | ls.append(np.array(x[sum: sum + n[i] * n[i + 1]]).reshape(n[i], n[i + 1])) 26 | sum += n[i] * n[i + 1] 27 | ls.append(np.array(x[sum: sum + n[i + 1]])) 28 | sum += n[i + 1] 29 | self.model.set_weights(ls) 30 | 31 | # 输入当前局面,输出评估函数 32 | def get_score_ANN(self, board): 33 | x_input = np.zeros((1, Line_Points ** 2), dtype=int) 34 | for j in range(Line_Points): 35 | for i in range(Line_Points): 36 | x_input[0, j * Line_Points + i] = board[j][i] 37 | score = self.model.predict(x_input) 38 | return score 39 | -------------------------------------------------------------------------------- /源码/博弈单元/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # coding=utf8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import Camera 8 | import threading 9 | from LABConfig import * 10 | from ArmIK.Transform import * 11 | from ArmIK.ArmMoveIK import * 12 | import HiwonderSDK.Board as Board 13 | from CameraCalibration.CalibrationConfig import * 14 | 15 | def init_position(): 16 | Board.setBusServoPulse(5,700,1000) 17 | time.sleep(1) 18 | 19 | Board.setBusServoPulse(4, 800, 400) 20 | time.sleep(0.5) 21 | 22 | Board.setBusServoPulse(6, 850, 400) 23 | time.sleep(0.5) 24 | 25 | Board.setBusServoPulse(3, 300, 300) 26 | time.sleep(0.5) 27 | 28 | Board.setBusServoPulse(2, 500, 300) 29 | time.sleep(0.5) 30 | 31 | Board.setBusServoPulse(1, 200, 300) 32 | time.sleep(0.5) # 延时时间和运行时间相同 33 | 34 | Board.setBusServoPulse(1, 600, 1000) 35 | time.sleep(2) # 延时时间和运行时间相同 36 | 37 | def put_chess(x,y): 38 | AK.setPitchRangeMoving((x, y, 0.9), -90, -90, 0, 1000) 39 | time.sleep(2) 40 | Board.setBusServoPulse(1, 800, 500) 41 | time.sleep(1) 42 | 43 | def read_position(): 44 | f = open("drop_point.txt", "r") 45 | x,y = f.read().split() 46 | f.close() 47 | return x,y 48 | 49 | #x,y = read_position() 50 | #print(x,y) 51 | 52 | AK = ArmIK() 53 | ''' 54 | init_position() 55 | ''' 56 | while 1: 57 | x,y = input().split() 58 | put_chess(eval(x),eval(y)) 59 | -------------------------------------------------------------------------------- /源码/控制单元/train.txt: -------------------------------------------------------------------------------- 1 | 65 699 389 688 2 | 76 753 427 654 3 | 84 795 460 611 4 | 87 819 481 558 5 | 88 826 489 500 6 | 87 819 481 442 7 | 84 795 460 389 8 | 76 753 427 346 9 | 65 699 389 312 10 | 67 660 365 661 11 | 63 688 383 629 12 | 62 712 399 591 13 | 70 740 420 547 14 | 73 749 426 500 15 | 70 740 420 453 16 | 62 712 399 409 17 | 63 688 383 371 18 | 67 660 365 339 19 | 75 625 342 640 20 | 68 646 357 611 21 | 67 666 370 577 22 | 67 681 380 539 23 | 61 676 378 500 24 | 67 681 380 461 25 | 67 666 370 423 26 | 68 646 357 389 27 | 75 625 342 360 28 | 74 570 308 624 29 | 66 585 320 597 30 | 64 604 332 566 31 | 66 620 342 534 32 | 71 633 350 500 33 | 66 620 342 466 34 | 64 604 332 434 35 | 66 585 320 403 36 | 74 570 308 376 37 | 115 578 305 611 38 | 97 576 308 586 39 | 89 584 316 558 40 | 66 556 303 530 41 | 76 578 315 500 42 | 66 556 303 470 43 | 89 584 316 442 44 | 97 576 308 414 45 | 115 578 305 389 46 | 117 512 262 600 47 | 132 568 294 577 48 | 119 566 297 552 49 | 117 575 304 526 50 | 96 543 288 500 51 | 117 575 304 474 52 | 119 566 297 448 53 | 132 568 294 423 54 | 117 512 262 400 55 | 196 576 279 591 56 | 165 550 273 570 57 | 145 536 270 547 58 | 143 545 277 524 59 | 154 567 288 500 60 | 143 545 277 476 61 | 145 536 270 453 62 | 165 550 273 430 63 | 196 576 279 409 64 | 222 536 243 583 65 | 223 567 264 564 66 | 204 555 263 543 67 | 200 559 267 522 68 | 208 576 277 500 69 | 200 559 267 478 70 | 204 555 263 457 71 | 223 567 264 436 72 | 222 536 243 417 73 | 293 557 231 577 74 | 262 536 229 558 75 | 239 519 226 539 76 | 238 530 234 520 77 | 251 556 247 500 78 | 238 530 234 480 79 | 239 519 226 461 80 | 262 536 229 442 81 | 293 557 231 423 82 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/Checkboard.py: -------------------------------------------------------------------------------- 1 | # 检查棋盘 2 | 3 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 4 | 5 | class Checkerboard: 6 | def __init__(self, line_points): 7 | self._line_points = line_points 8 | self._checkerboard = [[0] * line_points for _ in range(line_points)] 9 | 10 | def _get_checkerboard(self): 11 | return self._checkerboard 12 | 13 | checkerboard = property(_get_checkerboard) 14 | 15 | # 判断是否可落子 16 | def can_drop(self, point): 17 | return self._checkerboard[point.Y][point.X] == 0 18 | 19 | def drop(self, chessman, point): 20 | """ 21 | 落子 22 | :param chessman:当前落子的棋手 23 | :param point:落子位置 24 | :return:若该子落下之后即可获胜,则返回获胜方,否则返回 None 25 | """ 26 | # print(f'{chessman.Name} ({point.X}, {point.Y})') 27 | self._checkerboard[point.Y][point.X] = chessman.Value 28 | 29 | if self._win(point): 30 | # print(f'{chessman.Name}获胜') 31 | return chessman 32 | 33 | # 判断是否赢了 34 | def _win(self, point): 35 | cur_value = self._checkerboard[point.Y][point.X] 36 | for os in offset: 37 | if self._get_count_on_direction(point, cur_value, os[0], os[1]): 38 | return True 39 | 40 | # 判断在八个方向上是否已经有五颗棋子 41 | def _get_count_on_direction(self, point, value, x_offset, y_offset): 42 | count = 1 43 | # 先判断四个方向 44 | for step in range(1, 5): 45 | x = point.X + step * x_offset 46 | y = point.Y + step * y_offset 47 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 48 | count += 1 49 | else: 50 | break 51 | # 取反判断另外四个方向 52 | for step in range(1, 5): 53 | x = point.X - step * x_offset 54 | y = point.Y - step * y_offset 55 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 56 | count += 1 57 | else: 58 | break 59 | 60 | return count >= 5 -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/Checkboard.py: -------------------------------------------------------------------------------- 1 | # 检查棋盘 2 | 3 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 4 | 5 | class Checkerboard: 6 | def __init__(self, line_points): 7 | self._line_points = line_points 8 | self._checkerboard = [[0] * line_points for _ in range(line_points)] 9 | 10 | def _get_checkerboard(self): 11 | return self._checkerboard 12 | 13 | checkerboard = property(_get_checkerboard) 14 | 15 | # 判断是否可落子 16 | def can_drop(self, point): 17 | return self._checkerboard[point.Y][point.X] == 0 18 | 19 | def drop(self, chessman, point): 20 | """ 21 | 落子 22 | :param chessman:当前落子的棋手 23 | :param point:落子位置 24 | :return:若该子落下之后即可获胜,则返回获胜方,否则返回 None 25 | """ 26 | print(f'{chessman.Name} ({point.X}, {point.Y})') 27 | self._checkerboard[point.Y][point.X] = chessman.Value 28 | 29 | if self._win(point): 30 | print(f'{chessman.Name}获胜') 31 | return chessman 32 | # else: 33 | # print('请继续') 34 | 35 | 36 | 37 | # 判断是否赢了 38 | def _win(self, point): 39 | cur_value = self._checkerboard[point.Y][point.X] 40 | for os in offset: 41 | if self._get_count_on_direction(point, cur_value, os[0], os[1]): 42 | return True 43 | 44 | # 判断在八个方向上是否已经有五颗棋子 45 | def _get_count_on_direction(self, point, value, x_offset, y_offset): 46 | count = 1 47 | for step in range(1, 5): 48 | x = point.X + step * x_offset 49 | y = point.Y + step * y_offset 50 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 51 | count += 1 52 | else: 53 | break 54 | for step in range(1, 5): 55 | x = point.X - step * x_offset 56 | y = point.Y - step * y_offset 57 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 58 | count += 1 59 | else: 60 | break 61 | 62 | return count >= 5 63 | -------------------------------------------------------------------------------- /源码/控制单元/ANN.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | from torch.nn import init 4 | import numpy as np 5 | import torchvision 6 | import torchvision.transforms as transforms 7 | from torchvision import datasets 8 | 9 | 10 | class network(nn.Module): 11 | def __init__(self): 12 | super(network, self).__init__() 13 | self.layer = nn.Sequential( 14 | nn.Linear(2, 100), 15 | nn.ReLU(), 16 | nn.Linear(100,64), 17 | nn.ReLU(), 18 | nn.Linear(64, 4)) 19 | 20 | def forward(self, x): 21 | x = x.view(x.size()[0], -1) 22 | x = self.layer(x) 23 | return x 24 | 25 | net = network() 26 | 27 | for name, param in net.named_parameters(): 28 | if 'weight' in name: 29 | init.normal_(param, mean=0, std=0.01) 30 | if 'bias' in name: 31 | init.constant_(param, val=0) 32 | 33 | # 损失函数使用交叉熵 34 | criterion = nn.MSELoss() 35 | # 优化函数使用 SGD 36 | optimizer = torch.optim.Adam(net.parameters(), lr=0.04) 37 | '''for epoch in range(24): 38 | train_l_sum =0 39 | f = open("position.txt",mode='r') 40 | a = f.readlines() 41 | g = open("train.txt",mode='r') 42 | b = g.readlines() 43 | for i in range(len(a)): 44 | p = a[i].strip('\n').split() 45 | x = float(p[0]) 46 | y = float(p[1]) 47 | input = torch.tensor([[x,y]]).float() 48 | output = net(input) 49 | q = b[i].strip("\n").split() 50 | num1 = float(q[0]) 51 | num2 = float(q[1]) 52 | num3 = float(q[2]) 53 | num4 = float(q[3]) 54 | ground_truth = torch.tensor([[num1,num2,num3,num4]]).float() 55 | l = criterion(output,ground_truth) 56 | optimizer.zero_grad() 57 | l.backward() # 计算梯度 58 | optimizer.step() # 随机梯度下降算法, 更新参数 59 | train_l_sum += l.item() 60 | print(epoch,train_l_sum/81) 61 | f.close() 62 | g.close() 63 | 64 | torch.save(net.state_dict(), "my_model.pth") 65 | model = network() 66 | model.load_state_dict(torch.load("my_model.pth")) 67 | model.eval() 68 | 69 | print(model(torch.tensor([[0,20]]).float()))''' 70 | -------------------------------------------------------------------------------- /源码/博弈单元/Checkboard.py: -------------------------------------------------------------------------------- 1 | # 检查棋盘 2 | 3 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 4 | 5 | class Checkerboard: 6 | def __init__(self, line_points): 7 | self._line_points = line_points 8 | self._checkerboard = [[0] * line_points for _ in range(line_points)] 9 | 10 | def _get_checkerboard(self): 11 | return self._checkerboard 12 | 13 | checkerboard = property(_get_checkerboard) 14 | 15 | # 判断是否可落子 16 | def can_drop(self, point): 17 | return self._checkerboard[point.Y][point.X] == 0 18 | 19 | def drop(self, chessman, point): 20 | """ 21 | 落子 22 | :param chessman:当前落子的棋手 23 | :param point:落子位置 24 | :return:若该子落下之后即可获胜,则返回获胜方,否则返回 None 25 | """ 26 | print(f'{chessman.Name} ({point.X}, {point.Y})') 27 | self._checkerboard[point.Y][point.X] = chessman.Value 28 | 29 | if self._win(point): 30 | print(f'{chessman.Name}获胜') 31 | return chessman 32 | # else: 33 | # print('请继续') 34 | 35 | 36 | 37 | # 判断是否赢了 38 | def _win(self, point): 39 | cur_value = self._checkerboard[point.Y][point.X] 40 | for os in offset: 41 | if self._get_count_on_direction(point, cur_value, os[0], os[1]): 42 | return True 43 | 44 | # 判断在八个方向上是否已经有五颗棋子 45 | def _get_count_on_direction(self, point, value, x_offset, y_offset): 46 | count = 1 47 | # 先判断四个方向 48 | for step in range(1, 5): 49 | x = point.X + step * x_offset 50 | y = point.Y + step * y_offset 51 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 52 | count += 1 53 | else: 54 | break 55 | # 取反判断另外四个方向 56 | for step in range(1, 5): 57 | x = point.X - step * x_offset 58 | y = point.Y - step * y_offset 59 | if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value: 60 | count += 1 61 | else: 62 | break 63 | 64 | return count >= 5 65 | -------------------------------------------------------------------------------- /源码/博弈单元/mygame.py: -------------------------------------------------------------------------------- 1 | """人工智能五子棋""" 2 | from AI_alpha_beta import * 3 | from Checkboard import * 4 | from DrawUI import * 5 | #from MyModel import * 6 | from capture import * 7 | from move import * 8 | 9 | Chessman = namedtuple('Chessman', 'Name Value Color') 10 | Point = namedtuple('Point', 'X Y') 11 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 12 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 13 | 14 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 15 | 16 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 17 | imgText = font.render(text, True, fcolor) 18 | screen.blit(imgText, (x, y)) 19 | 20 | 21 | def main(): 22 | 23 | checkerboard = Checkerboard(Line_Points) 24 | cur_runner = BLACK_CHESSMAN 25 | winner = None 26 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 27 | 28 | # 加载网络模型 29 | #AI_model = Model() 30 | black_win_count = 0 31 | white_win_count = 0 32 | init_position() 33 | 34 | while True: 35 | # 控制下棋进程 36 | 37 | a = list(capture()) 38 | click_point = Point(a[0], a[1]) 39 | 40 | winner = checkerboard.drop(cur_runner, click_point) 41 | if winner is None: 42 | cur_runner = _get_next(cur_runner) 43 | computer.get_opponent_drop(click_point) 44 | # AI生成白棋,findBestChess返回坐标 45 | AI_point, score = computer.findBestChess(WHITE_CHESSMAN.Value) # 2 46 | 47 | put_chess(-2*AI_point.X+10+1.25,2.5*AI_point.Y+10) #math 48 | #put_chess2(AI_point.X,AI_point.Y) #deeplearning 49 | init_position() 50 | #f = open("drop_point.txt", "w") 51 | #f.write(str(AI_point.X) + " " + str(AI_point.Y)) 52 | #f.close() 53 | 54 | # 判断是否赢得比赛 55 | winner = checkerboard.drop(cur_runner, AI_point) 56 | if winner is not None: 57 | exit(0) 58 | cur_runner = _get_next(cur_runner) 59 | else: 60 | exit(0) 61 | 62 | 63 | def _get_next(cur_runner): 64 | if cur_runner == BLACK_CHESSMAN: 65 | return WHITE_CHESSMAN 66 | else: 67 | return BLACK_CHESSMAN 68 | 69 | if __name__ == '__main__': 70 | main() -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/mygame.py: -------------------------------------------------------------------------------- 1 | """人工智能五子棋""" 2 | from AI_alpha_beta import * 3 | from Checkboard import * 4 | from DrawUI import * 5 | from MyModel import * 6 | from capture import * 7 | from move import * 8 | 9 | Chessman = namedtuple('Chessman', 'Name Value Color') 10 | Point = namedtuple('Point', 'X Y') 11 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 12 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 13 | 14 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 15 | 16 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 17 | imgText = font.render(text, True, fcolor) 18 | screen.blit(imgText, (x, y)) 19 | 20 | 21 | def main(): 22 | 23 | checkerboard = Checkerboard(Line_Points) 24 | cur_runner = BLACK_CHESSMAN 25 | winner = None 26 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 27 | 28 | # 加载网络模型 29 | AI_model = Model() 30 | black_win_count = 0 31 | white_win_count = 0 32 | init_position() 33 | 34 | while True: 35 | # 控制下棋进程 36 | 37 | a = list(capture()) 38 | click_point = Point(a[0], a[1]) 39 | 40 | winner = checkerboard.drop(cur_runner, click_point) 41 | if winner is None: 42 | cur_runner = _get_next(cur_runner) 43 | computer.get_opponent_drop(click_point) 44 | # AI生成白棋,findBestChess返回坐标 45 | AI_point, score = computer.findBestChess(WHITE_CHESSMAN.Value, AI_model) # 2 46 | 47 | put_chess(-2*AI_point.X+10,2.5*AI_point.Y+10) #math 48 | #put_chess2(AI_point.X,AI_point.Y) #deeplearning 49 | init_position() 50 | #f = open("drop_point.txt", "w") 51 | #f.write(str(AI_point.X) + " " + str(AI_point.Y)) 52 | #f.close() 53 | 54 | # 判断是否赢得比赛 55 | winner = checkerboard.drop(cur_runner, AI_point) 56 | if winner is not None: 57 | exit(0) 58 | cur_runner = _get_next(cur_runner) 59 | else: 60 | exit(0) 61 | 62 | 63 | def _get_next(cur_runner): 64 | if cur_runner == BLACK_CHESSMAN: 65 | return WHITE_CHESSMAN 66 | else: 67 | return BLACK_CHESSMAN 68 | 69 | if __name__ == '__main__': 70 | main() -------------------------------------------------------------------------------- /源码/博弈单元/Camera.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding:utf-8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import threading 8 | import numpy as np 9 | from CameraCalibration.CalibrationConfig import * 10 | 11 | if sys.version_info.major == 2: 12 | print('Please run this program with python3!') 13 | sys.exit(0) 14 | 15 | class Camera: 16 | def __init__(self, resolution=(640, 480)): 17 | self.cap = None 18 | self.width = resolution[0] 19 | self.height = resolution[1] 20 | self.frame = None 21 | self.opened = False 22 | #加载参数 23 | self.param_data = np.load(calibration_param_path + '.npz') 24 | 25 | #获取参数 26 | self.mtx = self.param_data['mtx_array'] 27 | self.dist = self.param_data['dist_array'] 28 | self.newcameramtx, roi = cv2.getOptimalNewCameraMatrix(self.mtx, self.dist, (self.width, self.height), 0, (self.width, self.height)) 29 | self.mapx, self.mapy = cv2.initUndistortRectifyMap(self.mtx, self.dist, None, self.newcameramtx, (self.width,self.height), 5) 30 | 31 | self.th = threading.Thread(target=self.camera_task, args=(), daemon=True) 32 | self.th.start() 33 | 34 | def camera_open(self): 35 | try: 36 | self.cap = cv2.VideoCapture(-1) 37 | self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V')) 38 | self.cap.set(cv2.CAP_PROP_FPS, 30) 39 | self.cap.set(cv2.CAP_PROP_SATURATION, 40) 40 | self.opened = True 41 | except Exception as e: 42 | print('打开摄像头失败:', e) 43 | 44 | def camera_close(self): 45 | try: 46 | self.opened = False 47 | time.sleep(0.2) 48 | if self.cap is not None: 49 | self.cap.release() 50 | time.sleep(0.05) 51 | self.cap = None 52 | except Exception as e: 53 | print('关闭摄像头失败:', e) 54 | 55 | def camera_task(self): 56 | while True: 57 | try: 58 | if self.opened and self.cap.isOpened(): 59 | ret, frame_tmp = self.cap.read() 60 | if ret: 61 | frame_resize = cv2.resize(frame_tmp, (self.width, self.height), interpolation=cv2.INTER_NEAREST) 62 | self.frame = cv2.remap(frame_resize, self.mapx, self.mapy, cv2.INTER_LINEAR) 63 | else: 64 | print(1) 65 | self.frame = None 66 | cap = cv2.VideoCapture(-1) 67 | ret, _ = cap.read() 68 | if ret: 69 | self.cap = cap 70 | elif self.opened: 71 | print(2) 72 | cap = cv2.VideoCapture(-1) 73 | ret, _ = cap.read() 74 | if ret: 75 | self.cap = cap 76 | else: 77 | time.sleep(0.01) 78 | except Exception as e: 79 | print('获取摄像头画面出错:', e) 80 | time.sleep(0.01) 81 | 82 | if __name__ == '__main__': 83 | my_camera = Camera() 84 | my_camera.camera_open() 85 | while True: 86 | img = my_camera.frame 87 | if img is not None: 88 | cv2.imshow('img', img) 89 | key = cv2.waitKey(1) 90 | if key == 27: 91 | break 92 | my_camera.camera_close() 93 | cv2.destroyAllWindows() 94 | -------------------------------------------------------------------------------- /源码/视觉单元/Camera.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding:utf-8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import threading 8 | import numpy as np 9 | from CameraCalibration.CalibrationConfig import * 10 | 11 | if sys.version_info.major == 2: 12 | print('Please run this program with python3!') 13 | sys.exit(0) 14 | 15 | class Camera: 16 | def __init__(self, resolution=(640, 480)): 17 | self.cap = None 18 | self.width = resolution[0] 19 | self.height = resolution[1] 20 | self.frame = None 21 | self.opened = False 22 | #加载参数 23 | self.param_data = np.load(calibration_param_path + '.npz') 24 | 25 | #获取参数 26 | self.mtx = self.param_data['mtx_array'] 27 | self.dist = self.param_data['dist_array'] 28 | self.newcameramtx, roi = cv2.getOptimalNewCameraMatrix(self.mtx, self.dist, (self.width, self.height), 0, (self.width, self.height)) 29 | self.mapx, self.mapy = cv2.initUndistortRectifyMap(self.mtx, self.dist, None, self.newcameramtx, (self.width,self.height), 5) 30 | 31 | self.th = threading.Thread(target=self.camera_task, args=(), daemon=True) 32 | self.th.start() 33 | 34 | def camera_open(self): 35 | try: 36 | self.cap = cv2.VideoCapture(-1) 37 | self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V')) 38 | self.cap.set(cv2.CAP_PROP_FPS, 30) 39 | self.cap.set(cv2.CAP_PROP_SATURATION, 40) 40 | self.opened = True 41 | except Exception as e: 42 | print('打开摄像头失败:', e) 43 | 44 | def camera_close(self): 45 | try: 46 | self.opened = False 47 | time.sleep(0.2) 48 | if self.cap is not None: 49 | self.cap.release() 50 | time.sleep(0.05) 51 | self.cap = None 52 | except Exception as e: 53 | print('关闭摄像头失败:', e) 54 | 55 | def camera_task(self): 56 | while True: 57 | try: 58 | if self.opened and self.cap.isOpened(): 59 | ret, frame_tmp = self.cap.read() 60 | if ret: 61 | frame_resize = cv2.resize(frame_tmp, (self.width, self.height), interpolation=cv2.INTER_NEAREST) 62 | self.frame = cv2.remap(frame_resize, self.mapx, self.mapy, cv2.INTER_LINEAR) 63 | else: 64 | print(1) 65 | self.frame = None 66 | cap = cv2.VideoCapture(-1) 67 | ret, _ = cap.read() 68 | if ret: 69 | self.cap = cap 70 | elif self.opened: 71 | print(2) 72 | cap = cv2.VideoCapture(-1) 73 | ret, _ = cap.read() 74 | if ret: 75 | self.cap = cap 76 | else: 77 | time.sleep(0.01) 78 | except Exception as e: 79 | print('获取摄像头画面出错:', e) 80 | time.sleep(0.01) 81 | 82 | if __name__ == '__main__': 83 | my_camera = Camera() 84 | my_camera.camera_open() 85 | while True: 86 | img = my_camera.frame 87 | if img is not None: 88 | cv2.imshow('img', img) 89 | key = cv2.waitKey(1) 90 | if key == 27: 91 | break 92 | my_camera.camera_close() 93 | cv2.destroyAllWindows() 94 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/Camera.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding:utf-8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import threading 8 | import numpy as np 9 | from CameraCalibration.CalibrationConfig import * 10 | 11 | if sys.version_info.major == 2: 12 | print('Please run this program with python3!') 13 | sys.exit(0) 14 | 15 | class Camera: 16 | def __init__(self, resolution=(640, 480)): 17 | self.cap = None 18 | self.width = resolution[0] 19 | self.height = resolution[1] 20 | self.frame = None 21 | self.opened = False 22 | #加载参数 23 | self.param_data = np.load(calibration_param_path + '.npz') 24 | 25 | #获取参数 26 | self.mtx = self.param_data['mtx_array'] 27 | self.dist = self.param_data['dist_array'] 28 | self.newcameramtx, roi = cv2.getOptimalNewCameraMatrix(self.mtx, self.dist, (self.width, self.height), 0, (self.width, self.height)) 29 | self.mapx, self.mapy = cv2.initUndistortRectifyMap(self.mtx, self.dist, None, self.newcameramtx, (self.width,self.height), 5) 30 | 31 | self.th = threading.Thread(target=self.camera_task, args=(), daemon=True) 32 | self.th.start() 33 | 34 | def camera_open(self): 35 | try: 36 | self.cap = cv2.VideoCapture(-1) 37 | self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V')) 38 | self.cap.set(cv2.CAP_PROP_FPS, 30) 39 | self.cap.set(cv2.CAP_PROP_SATURATION, 40) 40 | self.opened = True 41 | except Exception as e: 42 | print('打开摄像头失败:', e) 43 | 44 | def camera_close(self): 45 | try: 46 | self.opened = False 47 | time.sleep(0.2) 48 | if self.cap is not None: 49 | self.cap.release() 50 | time.sleep(0.05) 51 | self.cap = None 52 | except Exception as e: 53 | print('关闭摄像头失败:', e) 54 | 55 | def camera_task(self): 56 | while True: 57 | try: 58 | if self.opened and self.cap.isOpened(): 59 | ret, frame_tmp = self.cap.read() 60 | if ret: 61 | frame_resize = cv2.resize(frame_tmp, (self.width, self.height), interpolation=cv2.INTER_NEAREST) 62 | self.frame = cv2.remap(frame_resize, self.mapx, self.mapy, cv2.INTER_LINEAR) 63 | else: 64 | print(1) 65 | self.frame = None 66 | cap = cv2.VideoCapture(-1) 67 | ret, _ = cap.read() 68 | if ret: 69 | self.cap = cap 70 | elif self.opened: 71 | print(2) 72 | cap = cv2.VideoCapture(-1) 73 | ret, _ = cap.read() 74 | if ret: 75 | self.cap = cap 76 | else: 77 | time.sleep(0.01) 78 | except Exception as e: 79 | print('获取摄像头画面出错:', e) 80 | time.sleep(0.01) 81 | 82 | if __name__ == '__main__': 83 | my_camera = Camera() 84 | my_camera.camera_open() 85 | while True: 86 | img = my_camera.frame 87 | if img is not None: 88 | cv2.imshow('img', img) 89 | key = cv2.waitKey(1) 90 | if key == 27: 91 | break 92 | my_camera.camera_close() 93 | cv2.destroyAllWindows() 94 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/GA.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 通过进化算法训练评估函数(评估函数用神经网络表示) 3 | ''' 4 | import numpy as np 5 | import random 6 | from two_AI_chess import * 7 | # from two_AI_chess_UI import * 8 | 9 | population_scale = 5 # 种群的规模 10 | max_times = 50 # 最大进化代数 11 | set_p = 0.001 # 突变概率 12 | 13 | def reproduction(x, y): 14 | # 采用两点交叉的算法产生子代 15 | breakpoint1 = random.randint(0, len(x)) 16 | breakpoint2 = random.randint(0, len(x)) 17 | if breakpoint2 < breakpoint1: 18 | temp = breakpoint1 19 | breakpoint1 = breakpoint2 20 | breakpoint2 = temp 21 | child = np.array(list(x)) 22 | for i in range(breakpoint1, breakpoint2 + 1): 23 | child[i] = y[i] 24 | return child 25 | 26 | 27 | my_model = Model() 28 | # 输出模型参数量,以便解的构建 29 | # print(my_model.model.summary()) 30 | # print(my_model.model.count_params()) 31 | 32 | # 获得初始解 33 | population = [] 34 | p_evaluate = [] 35 | for i in range(population_scale): 36 | population.append(np.random.normal(size=my_model.model.count_params())) 37 | p_evaluate.append([i, 0]) 38 | 39 | # 评估解的质量 40 | # m = 0 41 | for i in range(population_scale - 1): 42 | for j in range(i + 1, population_scale): 43 | # print("run: {}".format(m)) 44 | # m += 1 45 | winner = two_AI_chess(population[i], population[j]) 46 | if winner == 1: 47 | p_evaluate[i][1] += 1 48 | p_evaluate[j][1] -= 1 49 | if winner == -1: 50 | p_evaluate[i][1] -= 1 51 | p_evaluate[j][1] += 1 52 | print("初始解已处理完毕") 53 | 54 | # 进化部分 55 | t = 0 56 | while t < max_times: 57 | # 输出当前信息 58 | print("当前为第{:6}代".format(t)) 59 | 60 | # 挑选亲代 61 | p_evaluate.sort(key=lambda xx: xx[1], reverse=True) 62 | parents_index = [] 63 | parents_num = population_scale // 2 64 | for i in range(parents_num): 65 | parents_index.append(p_evaluate[i][0]) 66 | 67 | # 基因交叉 68 | children = [] 69 | for i in range(population_scale): 70 | x = random.randint(0, parents_num - 1) 71 | y = random.randint(0, parents_num - 1) 72 | 73 | while x == y: 74 | y = random.randint(0, parents_num - 1) 75 | children.append(reproduction(population[parents_index[x]], 76 | population[parents_index[y]])) 77 | 78 | # 基因突变 79 | for i in range(population_scale): 80 | for j in range(my_model.model.count_params()): 81 | if random.random() < set_p: 82 | children[i][j] += np.random.normal(0, 0.3) 83 | 84 | # 评估解的质量 85 | sum_scale = population_scale * 2 86 | s_evaluate = [] 87 | s_population = np.concatenate((population, children), axis=0) 88 | for i in range(sum_scale): 89 | s_evaluate.append([i, 0]) 90 | for i in range(sum_scale - 1): 91 | for j in range(i + 1, sum_scale): 92 | # 两个AI下棋得出胜者 93 | winner = two_AI_chess(s_population[i], s_population[j]) 94 | if winner == 1: 95 | s_evaluate[i][1] += 1 96 | s_evaluate[j][1] -= 1 97 | if winner == -1: 98 | s_evaluate[i][1] -= 1 99 | s_evaluate[j][1] += 1 100 | 101 | # 选择下一代 102 | s_evaluate.sort(key=lambda x_: x_[1], reverse=True) 103 | print(s_evaluate) 104 | population = [] 105 | for i in range(population_scale): 106 | population.append(s_population[s_evaluate[i][0]]) 107 | t += 1 108 | 109 | # 挑选排名第一的解并输出 110 | my_model.my_set_weights(population[0]) 111 | my_model.model.save('my_solvent.h5') -------------------------------------------------------------------------------- /源码/控制单元/move.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # coding=utf8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import Camera 8 | import threading 9 | from LABConfig import * 10 | from ArmIK.Transform import * 11 | from ArmIK.ArmMoveIK import * 12 | import HiwonderSDK.Board as Board 13 | from CameraCalibration.CalibrationConfig import * 14 | import torch 15 | 16 | 17 | def init_position(): 18 | Board.setBusServoPulse(5,700,1000) 19 | time.sleep(1) 20 | 21 | Board.setBusServoPulse(4, 800, 400) 22 | time.sleep(0.5) 23 | 24 | Board.setBusServoPulse(6, 850, 400) 25 | time.sleep(0.5) 26 | 27 | Board.setBusServoPulse(3, 300, 300) 28 | time.sleep(0.5) 29 | 30 | Board.setBusServoPulse(2, 500, 300) 31 | time.sleep(0.5) 32 | 33 | Board.setBusServoPulse(1, 200, 300) 34 | time.sleep(0.5) # 延时时间和运行时间相同 35 | 36 | Board.setBusServoPulse(1, 700, 1000) 37 | time.sleep(2) # 延时时间和运行时间相同 38 | 39 | def put_chess(x,y): 40 | result = AK.setPitchRangeMoving((x, y, 0.05*y+1.5), -90, -90, 0, 2000) 41 | time.sleep(3) 42 | #print(result[0]['servo5']) 43 | Board.setBusServoPulse(2, 400, 500) 44 | time.sleep(1) 45 | '''Board.setBusServoPulse(5, result[0]['servo5']-(30-y), 500) 46 | time.sleep(0.5)''' 47 | Board.setBusServoPulse(4, result[0]['servo4']+20, 500) 48 | time.sleep(0.5) 49 | Board.setBusServoPulse(3, result[0]['servo3']+20, 500) 50 | time.sleep(0.5) 51 | '''Board.setBusServoPulse(5, result[0]['servo5']+20, 500) 52 | time.sleep(0.5) 53 | Board.setBusServoPulse(4, result[0]['servo4']+20, 500) 54 | time.sleep(0.5)''' 55 | Board.setBusServoPulse(1, 300, 2000) 56 | time.sleep(3) 57 | Board.setBusServoPulse(5, 800, 2000) 58 | #write_data(result[0]['servo3'],result[0]['servo4'],result[0]['servo5'],result[0]['servo6']) 59 | time.sleep(3) 60 | return result[0] 61 | 62 | def read_position(): 63 | f = open("drop_point.txt", "r") 64 | x,y = f.read().split() 65 | f.close() 66 | return x,y 67 | 68 | def read_data(): 69 | ''' 70 | 读入数据 71 | ''' 72 | position = open("/home/pi/ArmPi/play_the_chess/position.txt",mode='r') 73 | p = position.readlines() 74 | for i in range(len(p)): 75 | k=p[i].strip('\n').split() 76 | re = put_chess(float(k[0]),float(k[1])) 77 | write_data(re['servo3'],re['servo4'],re['servo5'],re['servo6']) 78 | position.close() 79 | return 0 80 | 81 | def write_data(x1,x2,x3,x4): 82 | ''' 83 | 构造训练集 84 | ''' 85 | f = open("/home/pi/ArmPi/play_the_chess/train.txt",mode='a') 86 | f.write(str(x1)+' ') 87 | f.write(str(x2)+' ') 88 | f.write(str(x3)+' ') 89 | f.write(str(x4)+'\n') 90 | f.close 91 | return 0 92 | 93 | def put_chess2(x,y): 94 | #load the pre-trained model 95 | model = network() 96 | model.load_state_dict(torch.load("my_model.pth")) 97 | model.eval() 98 | p = model(torch.tensor([[x,y]]).float()) 99 | #run the arm 100 | Board.setBusServoPulse(3, int(p[0][0].trunc()), 500) 101 | time.sleep(1) 102 | Board.setBusServoPulse(4, int(p[0][1].trunc()), 500) 103 | time.sleep(1) 104 | Board.setBusServoPulse(5, int(p[0][2].trunc()), 500) 105 | time.sleep(1) 106 | Board.setBusServoPulse(6, int(p[0][3].trunc()), 500) 107 | time.sleep(3) 108 | #fine tuning 109 | Board.setBusServoPulse(2, 400, 500) 110 | time.sleep(1) 111 | Board.setBusServoPulse(4, int(p[0][1].trunc())+20, 500) 112 | time.sleep(0.5) 113 | Board.setBusServoPulse(3, int(p[0][0].trunc())+20, 500) 114 | time.sleep(0.5) 115 | Board.setBusServoPulse(1, 300, 2000) 116 | time.sleep(3) 117 | Board.setBusServoPulse(5, 800, 2000) 118 | time.sleep(3) 119 | 120 | #x,y = read_position() 121 | #print(x,y) 122 | 123 | AK = ArmIK() 124 | #read_data() 125 | 126 | #init_position() 127 | 128 | #put_chess(0,20) 129 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/move.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # coding=utf8 3 | import sys 4 | sys.path.append('/home/pi/ArmPi/') 5 | import cv2 6 | import time 7 | import Camera 8 | import threading 9 | from LABConfig import * 10 | from ArmIK.Transform import * 11 | from ArmIK.ArmMoveIK import * 12 | import HiwonderSDK.Board as Board 13 | from CameraCalibration.CalibrationConfig import * 14 | import torch 15 | 16 | 17 | def init_position(): 18 | Board.setBusServoPulse(5,700,1000) 19 | time.sleep(1) 20 | 21 | Board.setBusServoPulse(4, 800, 400) 22 | time.sleep(0.5) 23 | 24 | Board.setBusServoPulse(6, 850, 400) 25 | time.sleep(0.5) 26 | 27 | Board.setBusServoPulse(3, 300, 300) 28 | time.sleep(0.5) 29 | 30 | Board.setBusServoPulse(2, 500, 300) 31 | time.sleep(0.5) 32 | 33 | Board.setBusServoPulse(1, 200, 300) 34 | time.sleep(0.5) # 延时时间和运行时间相同 35 | 36 | Board.setBusServoPulse(1, 700, 1000) 37 | time.sleep(2) # 延时时间和运行时间相同 38 | 39 | def put_chess(x,y): 40 | result = AK.setPitchRangeMoving((x, y, 0.05*y+1.5), -90, -90, 0, 2000) 41 | time.sleep(3) 42 | #print(result[0]['servo5']) 43 | Board.setBusServoPulse(2, 400, 500) 44 | time.sleep(1) 45 | '''Board.setBusServoPulse(5, result[0]['servo5']-(30-y), 500) 46 | time.sleep(0.5)''' 47 | Board.setBusServoPulse(4, result[0]['servo4']+20, 500) 48 | time.sleep(0.5) 49 | Board.setBusServoPulse(3, result[0]['servo3']+20, 500) 50 | time.sleep(0.5) 51 | '''Board.setBusServoPulse(5, result[0]['servo5']+20, 500) 52 | time.sleep(0.5) 53 | Board.setBusServoPulse(4, result[0]['servo4']+20, 500) 54 | time.sleep(0.5)''' 55 | Board.setBusServoPulse(1, 300, 2000) 56 | time.sleep(3) 57 | Board.setBusServoPulse(5, 800, 2000) 58 | #write_data(result[0]['servo3'],result[0]['servo4'],result[0]['servo5'],result[0]['servo6']) 59 | time.sleep(3) 60 | return result[0] 61 | 62 | def read_position(): 63 | f = open("drop_point.txt", "r") 64 | x,y = f.read().split() 65 | f.close() 66 | return x,y 67 | 68 | def read_data(): 69 | ''' 70 | 读入数据 71 | ''' 72 | position = open("/home/pi/ArmPi/play_the_chess/position.txt",mode='r') 73 | p = position.readlines() 74 | for i in range(len(p)): 75 | k=p[i].strip('\n').split() 76 | re = put_chess(float(k[0]),float(k[1])) 77 | write_data(re['servo3'],re['servo4'],re['servo5'],re['servo6']) 78 | position.close() 79 | return 0 80 | 81 | def write_data(x1,x2,x3,x4): 82 | ''' 83 | 构造训练集 84 | ''' 85 | f = open("/home/pi/ArmPi/play_the_chess/train.txt",mode='a') 86 | f.write(str(x1)+' ') 87 | f.write(str(x2)+' ') 88 | f.write(str(x3)+' ') 89 | f.write(str(x4)+'\n') 90 | f.close 91 | return 0 92 | 93 | def put_chess2(x,y): 94 | #load the pre-trained model 95 | model = network() 96 | model.load_state_dict(torch.load("my_model.pth")) 97 | model.eval() 98 | p = model(torch.tensor([[x,y]]).float()) 99 | #run the arm 100 | Board.setBusServoPulse(3, int(p[0][0].trunc()), 500) 101 | time.sleep(1) 102 | Board.setBusServoPulse(4, int(p[0][1].trunc()), 500) 103 | time.sleep(1) 104 | Board.setBusServoPulse(5, int(p[0][2].trunc()), 500) 105 | time.sleep(1) 106 | Board.setBusServoPulse(6, int(p[0][3].trunc()), 500) 107 | time.sleep(3) 108 | #fine tuning 109 | Board.setBusServoPulse(2, 400, 500) 110 | time.sleep(1) 111 | Board.setBusServoPulse(4, int(p[0][1].trunc())+20, 500) 112 | time.sleep(0.5) 113 | Board.setBusServoPulse(3, int(p[0][0].trunc())+20, 500) 114 | time.sleep(0.5) 115 | Board.setBusServoPulse(1, 300, 2000) 116 | time.sleep(3) 117 | Board.setBusServoPulse(5, 800, 2000) 118 | time.sleep(3) 119 | 120 | #x,y = read_position() 121 | #print(x,y) 122 | 123 | AK = ArmIK() 124 | #read_data() 125 | 126 | #init_position() 127 | 128 | # put_chess(0,20) 129 | #put_chess(10,20) -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/two_AI_chess.py: -------------------------------------------------------------------------------- 1 | """两个人工智能黑白棋互相博弈,得到对不同评价函数的评价值""" 2 | 3 | import random 4 | from AI_alpha_beta import * 5 | from Checkboard import * 6 | from MyModel import Model 7 | 8 | Chessman = namedtuple('Chessman', 'Name Value Color') 9 | Point = namedtuple('Point', 'X Y') 10 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 11 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 12 | 13 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 14 | 15 | CURRENT_BLACK_POINT = Point(-1, -1) 16 | CURRENT_WHITE_POINT = Point(-1, -1) 17 | 18 | def _get_next(cur_runner): 19 | if cur_runner == BLACK_CHESSMAN: 20 | return WHITE_CHESSMAN 21 | else: 22 | return BLACK_CHESSMAN 23 | 24 | #让AI对局n次 25 | GAME_MAX_COUNT = 1 26 | 27 | def two_AI_chess(x, y): 28 | 29 | x_model = Model() 30 | y_model = Model() 31 | 32 | x_model.my_set_weights(x) 33 | y_model.my_set_weights(y) 34 | 35 | checkerboard = Checkerboard(Line_Points) 36 | cur_runner = BLACK_CHESSMAN 37 | winner = None 38 | 39 | black_win_count = 0 40 | white_win_count = 0 41 | 42 | computer_white = ChessAI(Line_Points, WHITE_CHESSMAN) 43 | computer_black = ChessAI(Line_Points, BLACK_CHESSMAN) 44 | 45 | step = 1 46 | 47 | while True: 48 | 49 | if step == 1: 50 | x = random.randint(0, Line_Points - 1) 51 | y = random.randint(0, Line_Points - 1) 52 | black_point = Point(x, y) 53 | computer_black.board[x][y] = WHITE_CHESSMAN.Value 54 | winner = checkerboard.drop(cur_runner, black_point) 55 | CURRENT_BLACK_POINT = black_point 56 | cur_runner = _get_next(cur_runner) 57 | # 合理地初始化黑白棋的当前点,防止出现错误 58 | computer_black.temp_point = black_point 59 | computer_white.temp_point = black_point 60 | step = 0 61 | 62 | if winner is None: 63 | computer_white.get_opponent_drop(CURRENT_BLACK_POINT) 64 | white_point, score_white = computer_white.findBestChess(WHITE_CHESSMAN.Value, y_model) # 2 65 | 66 | CURRENT_WHITE_POINT = white_point 67 | # 判断是否赢得比赛 68 | winner = checkerboard.drop(cur_runner, white_point) 69 | if white_point == (-1, -1): 70 | winner = _get_next(cur_runner) 71 | if winner is not None: 72 | # print("白棋赢了!") 73 | white_win_count += 1 74 | else: 75 | cur_runner = _get_next(cur_runner) 76 | 77 | computer_black.get_opponent_drop(CURRENT_WHITE_POINT) 78 | black_point, score_black = computer_black.findBestChess(BLACK_CHESSMAN.Value, x_model) # 1 79 | 80 | # 判断是否赢得比赛 81 | CURRENT_BLACK_POINT = black_point 82 | winner = checkerboard.drop(cur_runner, black_point) 83 | if black_point == (-1, -1): 84 | winner = _get_next(cur_runner) 85 | if winner is not None: 86 | # print("黑棋赢了!") 87 | black_win_count += 1 88 | 89 | cur_runner = _get_next(cur_runner) 90 | # 有赢家,初始化下一局 91 | if winner is not None: 92 | if black_win_count + white_win_count == GAME_MAX_COUNT: 93 | # 1: black wins; 0: no winner; -1: white wins 94 | if black_win_count > white_win_count: 95 | print("黑棋赢了!") 96 | return 1 97 | elif black_win_count == white_win_count: 98 | return 0 99 | else: 100 | print("白棋赢了!") 101 | return -1 102 | winner = None 103 | cur_runner = BLACK_CHESSMAN 104 | checkerboard = Checkerboard(Line_Points) 105 | step = 1 106 | computer_white = ChessAI(Line_Points, WHITE_CHESSMAN) 107 | computer_black = ChessAI(Line_Points, BLACK_CHESSMAN) -------------------------------------------------------------------------------- /源码/博弈单元/mygame_UI.py: -------------------------------------------------------------------------------- 1 | """人工智能五子棋""" 2 | import sys 3 | from pygame.locals import * 4 | import pygame.gfxdraw 5 | from AI_alpha_beta import * 6 | from Checkboard import * 7 | from DrawUI import * 8 | from MyModel import * 9 | 10 | Chessman = namedtuple('Chessman', 'Name Value Color') 11 | Point = namedtuple('Point', 'X Y') 12 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 13 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 14 | 15 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 16 | 17 | 18 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 19 | imgText = font.render(text, True, fcolor) 20 | screen.blit(imgText, (x, y)) 21 | 22 | 23 | def main(): 24 | pygame.init() 25 | screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 26 | pygame.display.set_caption('五子棋') 27 | 28 | font1 = pygame.font.SysFont('SimHei', 32) 29 | font2 = pygame.font.SysFont('SimHei', 72) 30 | fwidth, fheight = font2.size('黑方获胜') 31 | 32 | checkerboard = Checkerboard(Line_Points) 33 | cur_runner = BLACK_CHESSMAN 34 | winner = None 35 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 36 | 37 | while True: 38 | for event in pygame.event.get(): 39 | if event.type == QUIT: 40 | print("玩家退出游戏") 41 | sys.exit() 42 | elif event.type == KEYDOWN: 43 | if event.key == K_RETURN: 44 | # 一局结束的时候,按回车,会执行下面语句,重新初始化 45 | if winner is not None: 46 | winner = None 47 | cur_runner = BLACK_CHESSMAN 48 | checkerboard = Checkerboard(Line_Points) 49 | # 把电脑设定为AI类,算法封装在AI 50 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 51 | 52 | elif event.type == MOUSEBUTTONDOWN: 53 | # print("-------------") 54 | if winner is None: 55 | pressed_array = pygame.mouse.get_pressed() 56 | if pressed_array[0]: 57 | mouse_pos = pygame.mouse.get_pos() 58 | # 根据鼠标点击返回游戏区坐标 59 | click_point = DrawUI._get_clickpoint(mouse_pos) 60 | # 点击区域有效 61 | if click_point is not None: 62 | # 如果该位置能够落子 63 | if checkerboard.can_drop(click_point): 64 | winner = checkerboard.drop(cur_runner, click_point) 65 | if winner is None: 66 | cur_runner = _get_next(cur_runner) 67 | computer.get_opponent_drop(click_point) 68 | # AI生成白棋,findBestChess返回坐标 69 | AI_point, score = computer.findBestChess(WHITE_CHESSMAN.Value) # 2 70 | 71 | # 判断是否赢得比赛 72 | winner = checkerboard.drop(cur_runner, AI_point) 73 | if winner is not None: 74 | white_win_count += 1 75 | cur_runner = _get_next(cur_runner) 76 | else: 77 | black_win_count += 1 78 | else: 79 | print('该位置已经被占') 80 | else: 81 | print('超出棋盘区域') 82 | 83 | # 画棋盘 84 | DrawUI._draw_checkerboard(screen) 85 | 86 | # 画棋盘上已有的棋子 87 | for i, row in enumerate(checkerboard.checkerboard): 88 | for j, cell in enumerate(row): 89 | if cell == BLACK_CHESSMAN.Value: 90 | DrawUI._draw_chessman(screen, Point(j, i), BLACK_CHESSMAN.Color) 91 | elif cell == WHITE_CHESSMAN.Value: 92 | DrawUI._draw_chessman(screen, Point(j, i), WHITE_CHESSMAN.Color) 93 | 94 | # 在右侧打印出战况 95 | DrawUI._draw_left_info(screen, font1, cur_runner, black_win_count, white_win_count, DrawUI) 96 | 97 | # 判断最终的冠军 98 | if winner: 99 | print_text(screen, font2, (SCREEN_WIDTH - fwidth) // 2, (SCREEN_HEIGHT - fheight) // 2, winner.Name + '获胜', 100 | RED_COLOR) 101 | 102 | pygame.display.flip() 103 | 104 | 105 | def _get_next(cur_runner): 106 | if cur_runner == BLACK_CHESSMAN: 107 | return WHITE_CHESSMAN 108 | else: 109 | return BLACK_CHESSMAN 110 | 111 | 112 | if __name__ == '__main__': 113 | main() 114 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/mygame_UI.py: -------------------------------------------------------------------------------- 1 | """人工智能五子棋""" 2 | import sys 3 | from pygame.locals import * 4 | import pygame.gfxdraw 5 | from AI_alpha_beta import * 6 | from Checkboard import * 7 | from DrawUI import * 8 | from MyModel import * 9 | 10 | Chessman = namedtuple('Chessman', 'Name Value Color') 11 | Point = namedtuple('Point', 'X Y') 12 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 13 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 14 | 15 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 16 | 17 | 18 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 19 | imgText = font.render(text, True, fcolor) 20 | screen.blit(imgText, (x, y)) 21 | 22 | 23 | def main(): 24 | pygame.init() 25 | screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 26 | pygame.display.set_caption('五子棋') 27 | 28 | font1 = pygame.font.SysFont('SimHei', 32) 29 | font2 = pygame.font.SysFont('SimHei', 72) 30 | fwidth, fheight = font2.size('黑方获胜') 31 | 32 | checkerboard = Checkerboard(Line_Points) 33 | cur_runner = BLACK_CHESSMAN 34 | winner = None 35 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 36 | 37 | # 加载网络模型 38 | AI_model = Model() 39 | black_win_count = 0 40 | white_win_count = 0 41 | 42 | while True: 43 | for event in pygame.event.get(): 44 | if event.type == QUIT: 45 | print("玩家退出游戏") 46 | sys.exit() 47 | elif event.type == KEYDOWN: 48 | if event.key == K_RETURN: 49 | # 一局结束的时候,按回车,会执行下面语句,重新初始化 50 | if winner is not None: 51 | winner = None 52 | cur_runner = BLACK_CHESSMAN 53 | checkerboard = Checkerboard(Line_Points) 54 | # 把电脑设定为AI类,算法封装在AI 55 | computer = ChessAI(Line_Points, WHITE_CHESSMAN) 56 | 57 | elif event.type == MOUSEBUTTONDOWN: 58 | # print("-------------") 59 | if winner is None: 60 | pressed_array = pygame.mouse.get_pressed() 61 | if pressed_array[0]: 62 | mouse_pos = pygame.mouse.get_pos() 63 | # 根据鼠标点击返回游戏区坐标 64 | click_point = DrawUI._get_clickpoint(mouse_pos) 65 | # 点击区域有效 66 | if click_point is not None: 67 | # 如果该位置能够落子 68 | if checkerboard.can_drop(click_point): 69 | winner = checkerboard.drop(cur_runner, click_point) 70 | if winner is None: 71 | cur_runner = _get_next(cur_runner) 72 | computer.get_opponent_drop(click_point) 73 | # AI生成白棋,findBestChess返回坐标 74 | AI_point, score = computer.findBestChess(WHITE_CHESSMAN.Value, AI_model) # 2 75 | 76 | # 判断是否赢得比赛 77 | winner = checkerboard.drop(cur_runner, AI_point) 78 | if winner is not None: 79 | white_win_count += 1 80 | cur_runner = _get_next(cur_runner) 81 | else: 82 | black_win_count += 1 83 | else: 84 | print('该位置已经被占') 85 | else: 86 | print('超出棋盘区域') 87 | 88 | # 画棋盘 89 | DrawUI._draw_checkerboard(screen) 90 | 91 | # 画棋盘上已有的棋子 92 | for i, row in enumerate(checkerboard.checkerboard): 93 | for j, cell in enumerate(row): 94 | if cell == BLACK_CHESSMAN.Value: 95 | DrawUI._draw_chessman(screen, Point(j, i), BLACK_CHESSMAN.Color) 96 | elif cell == WHITE_CHESSMAN.Value: 97 | DrawUI._draw_chessman(screen, Point(j, i), WHITE_CHESSMAN.Color) 98 | 99 | # 在右侧打印出战况 100 | DrawUI._draw_left_info(screen, font1, cur_runner, black_win_count, white_win_count, DrawUI) 101 | 102 | # 判断最终的冠军 103 | if winner: 104 | print_text(screen, font2, (SCREEN_WIDTH - fwidth) // 2, (SCREEN_HEIGHT - fheight) // 2, winner.Name + '获胜', 105 | RED_COLOR) 106 | 107 | pygame.display.flip() 108 | 109 | 110 | def _get_next(cur_runner): 111 | if cur_runner == BLACK_CHESSMAN: 112 | return WHITE_CHESSMAN 113 | else: 114 | return BLACK_CHESSMAN 115 | 116 | 117 | if __name__ == '__main__': 118 | main() 119 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/two_AI_chess_UI.py: -------------------------------------------------------------------------------- 1 | """两个人工智能黑白棋互相博弈,得到对不同评价函数的评价值""" 2 | 3 | import random 4 | from AI_alpha_beta import * 5 | from Checkboard import * 6 | from MyModel import Model 7 | 8 | import pygame.gfxdraw 9 | from DrawUI import * 10 | 11 | Chessman = namedtuple('Chessman', 'Name Value Color') 12 | Point = namedtuple('Point', 'X Y') 13 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 14 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 15 | 16 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 17 | 18 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 19 | imgText = font.render(text, True, fcolor) 20 | screen.blit(imgText, (x, y)) 21 | 22 | CURRENT_BLACK_POINT = Point(-1, -1) 23 | CURRENT_WHITE_POINT = Point(-1, -1) 24 | 25 | def _get_next(cur_runner): 26 | if cur_runner == BLACK_CHESSMAN: 27 | return WHITE_CHESSMAN 28 | else: 29 | return BLACK_CHESSMAN 30 | 31 | #让AI对局n次 32 | GAME_MAX_COUNT = 3 33 | 34 | def two_AI_chess_UI(x, y): 35 | 36 | x_model = Model() 37 | y_model = Model() 38 | 39 | x_model.my_set_weights(x) 40 | y_model.my_set_weights(y) 41 | 42 | pygame.init() 43 | screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 44 | pygame.display.set_caption('五子棋') 45 | 46 | font1 = pygame.font.SysFont('SimHei', 32) 47 | font2 = pygame.font.SysFont('SimHei', 72) 48 | fwidth, fheight = font2.size('黑方获胜') 49 | 50 | checkerboard = Checkerboard(Line_Points) 51 | cur_runner = BLACK_CHESSMAN 52 | winner = None 53 | 54 | black_win_count = 0 55 | white_win_count = 0 56 | 57 | computer_white = ChessAI(Line_Points, WHITE_CHESSMAN) 58 | computer_black = ChessAI(Line_Points, BLACK_CHESSMAN) 59 | 60 | step = 1 61 | 62 | while True: 63 | 64 | if step == 1: 65 | x = random.randint(0, Line_Points - 1) 66 | y = random.randint(0, Line_Points - 1) 67 | black_point = Point(x, y) 68 | computer_black.board[x][y] = WHITE_CHESSMAN.Value 69 | winner = checkerboard.drop(cur_runner, black_point) 70 | CURRENT_BLACK_POINT = black_point 71 | cur_runner = _get_next(cur_runner) 72 | # 合理地初始化黑白棋的当前点,防止出现错误 73 | computer_black.temp_point = black_point 74 | computer_white.temp_point = black_point 75 | step = 0 76 | 77 | if winner is None: 78 | computer_white.get_opponent_drop(CURRENT_BLACK_POINT) 79 | white_point, score_white = computer_white.findBestChess(WHITE_CHESSMAN.Value, y_model) # 2 80 | 81 | CURRENT_WHITE_POINT = white_point 82 | # 判断是否赢得比赛 83 | winner = checkerboard.drop(cur_runner, white_point) 84 | if white_point == (-1, -1): 85 | winner = _get_next(cur_runner) 86 | if winner is not None: 87 | print("白棋赢了!") 88 | white_win_count += 1 89 | else: 90 | cur_runner = _get_next(cur_runner) 91 | 92 | computer_black.get_opponent_drop(CURRENT_WHITE_POINT) 93 | black_point, score_black = computer_black.findBestChess(BLACK_CHESSMAN.Value, x_model) # 1 94 | 95 | # 判断是否赢得比赛 96 | CURRENT_BLACK_POINT = black_point 97 | winner = checkerboard.drop(cur_runner, black_point) 98 | if black_point == (-1, -1): 99 | winner = _get_next(cur_runner) 100 | if winner is not None: 101 | print("黑棋赢了!") 102 | black_win_count += 1 103 | 104 | cur_runner = _get_next(cur_runner) 105 | # 有赢家,初始化下一局 106 | if winner is not None: 107 | if black_win_count + white_win_count == GAME_MAX_COUNT: 108 | # 1: black wins; 0: no winner; -1: white wins 109 | if black_win_count > white_win_count: 110 | # print("黑棋赢了!") 111 | return 1 112 | elif black_win_count == white_win_count: 113 | return 0 114 | else: 115 | # print("白棋赢了!") 116 | return -1 117 | winner = None 118 | cur_runner = BLACK_CHESSMAN 119 | checkerboard = Checkerboard(Line_Points) 120 | step = 1 121 | computer_white = ChessAI(Line_Points, WHITE_CHESSMAN) 122 | computer_black = ChessAI(Line_Points, BLACK_CHESSMAN) 123 | 124 | # 在右侧打印出战况 125 | DrawUI._draw_left_info(screen, font1, cur_runner, black_win_count, white_win_count, DrawUI) 126 | 127 | # 判断最终的冠军 128 | if winner: 129 | print_text(screen, font2, (SCREEN_WIDTH - fwidth)//2, (SCREEN_HEIGHT - fheight)//2, winner.Name + '获胜', RED_COLOR) 130 | 131 | pygame.display.flip() -------------------------------------------------------------------------------- /源码/博弈单元/recognize.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # from skimage.measure import compare_ssim 3 | from skimage.metrics import structural_similarity 4 | import argparse 5 | import imutils 6 | import cv2 7 | 8 | 9 | def capture(): 10 | image_path = "/home/pi/ArmPi/play_the_chess/recongnize/picture" 11 | 12 | # image = cv2.imread(image_path+'1.jpg') 13 | # cv2.imshow('test',image) 14 | def cut(image_to_cut): 15 | sp = image_to_cut.shape # 获取图像形状:返回【行数值,列数值】列表 16 | sz1 = sp[0] # 图像的高度(行 范围) 17 | sz2 = sp[1] 18 | a = int(sz1 / 2 - 150) # x start 19 | b = int(sz1 / 2 + 165) # x end 20 | c = int(sz2 / 2 - 150) # y start 21 | d = int(sz2 / 2 + 155) # y end 22 | resized_image = image_to_cut[a:b, c:d] # 裁剪图像 23 | cv2.imshow('resized', resized_image) 24 | return resized_image 25 | 26 | # 这里的长之差得315,宽之差305,有所畸变,非正方形 27 | # 不过无伤大雅——后续可直接用w和h作为长宽除法的单位 28 | 29 | def compare_between(first, second): 30 | # load the two input images 31 | imageA = cv2.imread(image_path + first) 32 | imageB = cv2.imread(image_path + second) 33 | resized_orig = cut(imageA) 34 | resized_mod = cut(imageB) 35 | # 36 | # resized_orig = cv2.resize(imageA, (500, 500)) 37 | # resized_mod = cv2.resize(imageB, (500, 500)) 38 | 39 | # 去噪声增加图像质量 40 | resultA = cv2.GaussianBlur(resized_orig, (5, 5), 1, 1) 41 | resultB = cv2.GaussianBlur(resized_mod, (5, 5), 1, 1) 42 | 43 | # convert the images to grayscale 44 | grayA = cv2.cvtColor(resultA, cv2.COLOR_BGR2GRAY) 45 | grayB = cv2.cvtColor(resultB, cv2.COLOR_BGR2GRAY) 46 | # compute the Structural Similarity Index (SSIM) between the two 47 | # images, ensuring that the difference image is returned 48 | (score, diff) = structural_similarity(grayA, grayB, full=True) 49 | diff = (diff * 255).astype("uint8") 50 | # print("SSIM: {}".format(score)) 51 | 52 | # threshold the difference image, followed by finding contours to 53 | # obtain the regions of the two input images that differ 54 | thresh = cv2.threshold(diff, 0, 255, 55 | cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 56 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 57 | cv2.CHAIN_APPROX_SIMPLE) 58 | cnts = imutils.grab_contours(cnts) 59 | 60 | # loop over the contours 61 | for c in cnts: 62 | # compute the bounding box of the contour and then draw the 63 | # bounding box on both input images to represent where the two 64 | # images differ 65 | 66 | (x, y, w, h) = cv2.boundingRect(c) 67 | if w * h > 500: 68 | cv2.rectangle(resultA, (x, y), (x + w, y + h), (0, 0, 255), 2) 69 | cv2.rectangle(resultB, (x, y), (x + w, y + h), (0, 0, 255), 2) 70 | print( 71 | "l_t bound({},{});r_b bound({},{});center:({},{})".format(x, y, (x + w), (y + h), 72 | (x + w / 2), 73 | (y + h / 2))) 74 | # print("move:({},{})".format(int((x + w )/63),int((y+h )/61))) 75 | print("move:({},{})".format(int((x + w) / w), int((y + h) / h))) 76 | # break 77 | # print(y) 78 | 79 | # show the output images 80 | cv2.imshow("Original", resultA) 81 | cv2.imshow("Modified", resultB) 82 | # cv2.imshow("Diff", diff) 83 | # cv2.imshow("Thresh", thresh) 84 | # cv2.waitKey(0) 85 | return int((x + w) / w), int((y + h) / h) 86 | 87 | # import cv2 88 | cap = cv2.VideoCapture(1, cv2.CAP_DSHOW) 89 | flag = cap.isOpened() 90 | 91 | print ("camera:",flag) 92 | 93 | index = 1 94 | # 表示第几张图片 95 | compared = 0 96 | # 是否和之前的图片比较过 97 | while flag: 98 | 99 | ret, frame = cap.read() 100 | cv2.imshow("Camera_window", frame) 101 | k = cv2.waitKey(1) & 0xFF 102 | if k == ord('s'): # 按下s键,进入下面的保存图片操作 103 | cv2.imwrite("D:/rainwork/Gobang/lab1/picture/" + str(index) + ".jpg", frame) 104 | print("save" + str(index) + ".jpg successfuly!") 105 | print("-------------------------") 106 | index += 1 107 | compared = 0 108 | elif k == ord('q'): # 按下q键,程序退出 109 | break 110 | if (not compared) and index > 2: 111 | # print(str(index) + '.jpg') 112 | move = [compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg')] 113 | compared = 1 114 | 115 | # 调用compare比较两个图片的区别 116 | cap.release() # 释放摄像头 117 | cv2.destroyAllWindows() # 释放并销毁窗口 118 | #print("#") 119 | return move 120 | 121 | print (capture()) -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/recognize.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # from skimage.measure import compare_ssim 3 | from skimage.metrics import structural_similarity 4 | import argparse 5 | import imutils 6 | import cv2 7 | 8 | 9 | def capture(): 10 | image_path = "/home/pi/ArmPi/play_the_chess/recongnize/picture" 11 | 12 | # image = cv2.imread(image_path+'1.jpg') 13 | # cv2.imshow('test',image) 14 | def cut(image_to_cut): 15 | sp = image_to_cut.shape # 获取图像形状:返回【行数值,列数值】列表 16 | sz1 = sp[0] # 图像的高度(行 范围) 17 | sz2 = sp[1] 18 | a = int(sz1 / 2 - 150) # x start 19 | b = int(sz1 / 2 + 165) # x end 20 | c = int(sz2 / 2 - 150) # y start 21 | d = int(sz2 / 2 + 155) # y end 22 | resized_image = image_to_cut[a:b, c:d] # 裁剪图像 23 | cv2.imshow('resized', resized_image) 24 | return resized_image 25 | 26 | # 这里的长之差得315,宽之差305,有所畸变,非正方形 27 | # 不过无伤大雅——后续可直接用w和h作为长宽除法的单位 28 | 29 | def compare_between(first, second): 30 | # load the two input images 31 | imageA = cv2.imread(image_path + first) 32 | imageB = cv2.imread(image_path + second) 33 | resized_orig = cut(imageA) 34 | resized_mod = cut(imageB) 35 | # 36 | # resized_orig = cv2.resize(imageA, (500, 500)) 37 | # resized_mod = cv2.resize(imageB, (500, 500)) 38 | 39 | # 去噪声增加图像质量 40 | resultA = cv2.GaussianBlur(resized_orig, (5, 5), 1, 1) 41 | resultB = cv2.GaussianBlur(resized_mod, (5, 5), 1, 1) 42 | 43 | # convert the images to grayscale 44 | grayA = cv2.cvtColor(resultA, cv2.COLOR_BGR2GRAY) 45 | grayB = cv2.cvtColor(resultB, cv2.COLOR_BGR2GRAY) 46 | # compute the Structural Similarity Index (SSIM) between the two 47 | # images, ensuring that the difference image is returned 48 | (score, diff) = structural_similarity(grayA, grayB, full=True) 49 | diff = (diff * 255).astype("uint8") 50 | # print("SSIM: {}".format(score)) 51 | 52 | # threshold the difference image, followed by finding contours to 53 | # obtain the regions of the two input images that differ 54 | thresh = cv2.threshold(diff, 0, 255, 55 | cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 56 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 57 | cv2.CHAIN_APPROX_SIMPLE) 58 | cnts = imutils.grab_contours(cnts) 59 | 60 | # loop over the contours 61 | for c in cnts: 62 | # compute the bounding box of the contour and then draw the 63 | # bounding box on both input images to represent where the two 64 | # images differ 65 | 66 | (x, y, w, h) = cv2.boundingRect(c) 67 | if w * h > 500: 68 | cv2.rectangle(resultA, (x, y), (x + w, y + h), (0, 0, 255), 2) 69 | cv2.rectangle(resultB, (x, y), (x + w, y + h), (0, 0, 255), 2) 70 | print( 71 | "l_t bound({},{});r_b bound({},{});center:({},{})".format(x, y, (x + w), (y + h), 72 | (x + w / 2), 73 | (y + h / 2))) 74 | # print("move:({},{})".format(int((x + w )/63),int((y+h )/61))) 75 | print("move:({},{})".format(int((x + w) / w), int((y + h) / h))) 76 | # break 77 | # print(y) 78 | 79 | # show the output images 80 | cv2.imshow("Original", resultA) 81 | cv2.imshow("Modified", resultB) 82 | # cv2.imshow("Diff", diff) 83 | # cv2.imshow("Thresh", thresh) 84 | # cv2.waitKey(0) 85 | return int((x + w) / w), int((y + h) / h) 86 | 87 | # import cv2 88 | cap = cv2.VideoCapture(1, cv2.CAP_DSHOW) 89 | flag = cap.isOpened() 90 | 91 | print ("camera:",flag) 92 | 93 | index = 1 94 | # 表示第几张图片 95 | compared = 0 96 | # 是否和之前的图片比较过 97 | while flag: 98 | 99 | ret, frame = cap.read() 100 | cv2.imshow("Camera_window", frame) 101 | k = cv2.waitKey(1) & 0xFF 102 | if k == ord('s'): # 按下s键,进入下面的保存图片操作 103 | cv2.imwrite("D:/rainwork/Gobang/lab1/picture/" + str(index) + ".jpg", frame) 104 | print("save" + str(index) + ".jpg successfuly!") 105 | print("-------------------------") 106 | index += 1 107 | compared = 0 108 | elif k == ord('q'): # 按下q键,程序退出 109 | break 110 | if (not compared) and index > 2: 111 | # print(str(index) + '.jpg') 112 | move = [compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg')] 113 | compared = 1 114 | 115 | # 调用compare比较两个图片的区别 116 | cap.release() # 释放摄像头 117 | cv2.destroyAllWindows() # 释放并销毁窗口 118 | #print("#") 119 | return move 120 | 121 | print (capture()) -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/DrawUI.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from collections import namedtuple 3 | 4 | SIZE = 30 # 棋盘每个点时间的间隔 5 | Line_Points = 19 # 棋盘每行/每列点数 6 | Outer_Width = 20 # 棋盘外宽度 7 | Border_Width = 4 # 边框宽度 8 | Inside_Width = 4 # 边框跟实际的棋盘之间的间隔 9 | Border_Length = SIZE * (Line_Points - 1) + Inside_Width * 2 + Border_Width # 边框线的长度 10 | Start_X = Start_Y = Outer_Width + int(Border_Width / 2) + Inside_Width # 网格线起点(左上角)坐标 11 | SCREEN_HEIGHT = SIZE * (Line_Points - 1) + Outer_Width * 2 + Border_Width + Inside_Width * 2 # 游戏屏幕的高 12 | SCREEN_WIDTH = SCREEN_HEIGHT + 200 # 游戏屏幕的宽 13 | 14 | Stone_Radius = SIZE // 2 - 3 # 棋子半径 15 | Stone_Radius2 = SIZE // 2 + 3 16 | Checkerboard_Color = (0xFA, 0xEB, 0xD7) # 棋盘颜色 17 | BLACK_COLOR = (0, 0, 0) 18 | WHITE_COLOR = (255, 255, 255) 19 | RED_COLOR = (200, 30, 30) 20 | BLUE_COLOR = (30, 30, 200) 21 | 22 | RIGHT_INFO_POS_X = SCREEN_HEIGHT + Stone_Radius2 * 2 + 10 23 | Point = namedtuple('Point', 'X Y') 24 | Chessman = namedtuple('Chessman', 'Name Value Color') 25 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 26 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 27 | 28 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 29 | imgText = font.render(text, True, fcolor) 30 | screen.blit(imgText, (x, y)) 31 | 32 | # 画棋盘 33 | class DrawUI: 34 | def _draw_checkerboard(screen): 35 | # 填充棋盘背景色 36 | screen.fill(Checkerboard_Color) 37 | # 画棋盘网格线外的边框 38 | pygame.draw.rect(screen, BLACK_COLOR, (Outer_Width, Outer_Width, Border_Length, Border_Length), Border_Width) 39 | # 画网格线 40 | for i in range(Line_Points): 41 | pygame.draw.line(screen, BLACK_COLOR, 42 | (Start_Y, Start_Y + SIZE * i), 43 | (Start_Y + SIZE * (Line_Points - 1), Start_Y + SIZE * i), 44 | 1) 45 | for j in range(Line_Points): 46 | pygame.draw.line(screen, BLACK_COLOR, 47 | (Start_X + SIZE * j, Start_X), 48 | (Start_X + SIZE * j, Start_X + SIZE * (Line_Points - 1)), 49 | 1) 50 | # 画星位和天元 51 | for i in (3, 9, 15): 52 | for j in (3, 9, 15): 53 | if i == j == 9: 54 | radius = 5 55 | else: 56 | radius = 3 57 | # pygame.draw.circle(screen, BLACK, (Start_X + SIZE * i, Start_Y + SIZE * j), radius) 58 | pygame.gfxdraw.aacircle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 59 | pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 60 | 61 | 62 | # 画棋子 63 | def _draw_chessman(screen, point, stone_color): 64 | # pygame.draw.circle(screen, stone_color, (Start_X + SIZE * point.X, Start_Y + SIZE * point.Y), Stone_Radius) 65 | pygame.gfxdraw.aacircle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 66 | pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 67 | 68 | def _draw_chessman_pos(screen, pos, stone_color): 69 | pygame.gfxdraw.aacircle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 70 | pygame.gfxdraw.filled_circle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 71 | 72 | # 画左侧信息显示 73 | def _draw_left_info(screen, font, cur_runner, black_win_count, white_win_count,self): 74 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2), BLACK_CHESSMAN.Color) 75 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2 * 4), WHITE_CHESSMAN.Color) 76 | 77 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + 3, '玩家', BLUE_COLOR) 78 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + Stone_Radius2 * 3 + 3, '电脑', BLUE_COLOR) 79 | 80 | print_text(screen, font, SCREEN_HEIGHT, SCREEN_HEIGHT - Stone_Radius2 * 8, '战况:', BLUE_COLOR) 81 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - int(Stone_Radius2 * 4.5)), BLACK_CHESSMAN.Color) 82 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - Stone_Radius2 * 2), WHITE_CHESSMAN.Color) 83 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - int(Stone_Radius2 * 5.5) + 3, f'{black_win_count} 胜', BLUE_COLOR) 84 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - Stone_Radius2 * 3 + 3, f'{white_win_count} 胜', BLUE_COLOR) 85 | 86 | 87 | 88 | # 根据鼠标点击位置,返回游戏区坐标 89 | def _get_clickpoint(click_pos): 90 | pos_x = click_pos[0] - Start_X 91 | pos_y = click_pos[1] - Start_Y 92 | if pos_x < -Inside_Width or pos_y < -Inside_Width: 93 | return None 94 | x = pos_x // SIZE 95 | y = pos_y // SIZE 96 | if pos_x % SIZE > Stone_Radius: 97 | x += 1 98 | if pos_y % SIZE > Stone_Radius: 99 | y += 1 100 | if x >= Line_Points or y >= Line_Points: 101 | return None 102 | 103 | return Point(x, y) 104 | -------------------------------------------------------------------------------- /源码/博弈单元/DrawUI.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from collections import namedtuple 3 | 4 | SIZE = 30 # 棋盘每个点时间的间隔 5 | Line_Points = 9 # 棋盘每行/每列点数 6 | Outer_Width = 20 # 棋盘外宽度 7 | Border_Width = 4 # 边框宽度 8 | Inside_Width = 4 # 边框跟实际的棋盘之间的间隔 9 | Border_Length = SIZE * (Line_Points - 1) + Inside_Width * 2 + Border_Width # 边框线的长度 10 | Start_X = Start_Y = Outer_Width + int(Border_Width / 2) + Inside_Width # 网格线起点(左上角)坐标 11 | SCREEN_HEIGHT = SIZE * (Line_Points - 1) + Outer_Width * 2 + Border_Width + Inside_Width * 2 # 游戏屏幕的高 12 | SCREEN_WIDTH = SCREEN_HEIGHT + 200 # 游戏屏幕的宽 13 | 14 | Stone_Radius = SIZE // 2 - 3 # 棋子半径 15 | Stone_Radius2 = SIZE // 2 + 3 16 | Checkerboard_Color = (0xFA, 0xEB, 0xD7) # 棋盘颜色 17 | BLACK_COLOR = (0, 0, 0) 18 | WHITE_COLOR = (255, 255, 255) 19 | RED_COLOR = (200, 30, 30) 20 | BLUE_COLOR = (30, 30, 200) 21 | 22 | RIGHT_INFO_POS_X = SCREEN_HEIGHT + Stone_Radius2 * 2 + 10 23 | Point = namedtuple('Point', 'X Y') 24 | Chessman = namedtuple('Chessman', 'Name Value Color') 25 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 26 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 27 | 28 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 29 | imgText = font.render(text, True, fcolor) 30 | screen.blit(imgText, (x, y)) 31 | 32 | # 画棋盘 33 | class DrawUI: 34 | def _draw_checkerboard(screen): 35 | # 填充棋盘背景色 36 | screen.fill(Checkerboard_Color) 37 | # 画棋盘网格线外的边框 38 | pygame.draw.rect(screen, BLACK_COLOR, (Outer_Width, Outer_Width, Border_Length, Border_Length), Border_Width) 39 | # 画网格线 40 | for i in range(Line_Points): 41 | pygame.draw.line(screen, BLACK_COLOR, 42 | (Start_Y, Start_Y + SIZE * i), 43 | (Start_Y + SIZE * (Line_Points - 1), Start_Y + SIZE * i), 44 | 1) 45 | for j in range(Line_Points): 46 | pygame.draw.line(screen, BLACK_COLOR, 47 | (Start_X + SIZE * j, Start_X), 48 | (Start_X + SIZE * j, Start_X + SIZE * (Line_Points - 1)), 49 | 1) 50 | # # 画星位和天元 51 | # for i in (3, 9, 15): 52 | # for j in (3, 9, 15): 53 | # if i == j == 9: 54 | # radius = 5 55 | # else: 56 | # radius = 3 57 | # # pygame.draw.circle(screen, BLACK, (Start_X + SIZE * i, Start_Y + SIZE * j), radius) 58 | # pygame.gfxdraw.aacircle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 59 | # pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 60 | 61 | 62 | # 画棋子 63 | def _draw_chessman(screen, point, stone_color): 64 | # pygame.draw.circle(screen, stone_color, (Start_X + SIZE * point.X, Start_Y + SIZE * point.Y), Stone_Radius) 65 | pygame.gfxdraw.aacircle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 66 | pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 67 | 68 | def _draw_chessman_pos(screen, pos, stone_color): 69 | pygame.gfxdraw.aacircle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 70 | pygame.gfxdraw.filled_circle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 71 | 72 | # 画左侧信息显示 73 | def _draw_left_info(screen, font, cur_runner, black_win_count, white_win_count,self): 74 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2), BLACK_CHESSMAN.Color) 75 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2 * 4), WHITE_CHESSMAN.Color) 76 | 77 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + 3, '玩家', BLUE_COLOR) 78 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + Stone_Radius2 * 3 + 3, '电脑', BLUE_COLOR) 79 | 80 | print_text(screen, font, SCREEN_HEIGHT, SCREEN_HEIGHT - Stone_Radius2 * 8, '战况:', BLUE_COLOR) 81 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - int(Stone_Radius2 * 4.5)), BLACK_CHESSMAN.Color) 82 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - Stone_Radius2 * 2), WHITE_CHESSMAN.Color) 83 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - int(Stone_Radius2 * 5.5) + 3, f'{black_win_count} 胜', BLUE_COLOR) 84 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - Stone_Radius2 * 3 + 3, f'{white_win_count} 胜', BLUE_COLOR) 85 | 86 | 87 | 88 | # 根据鼠标点击位置,返回游戏区坐标 89 | def _get_clickpoint(click_pos): 90 | pos_x = click_pos[0] - Start_X 91 | pos_y = click_pos[1] - Start_Y 92 | if pos_x < -Inside_Width or pos_y < -Inside_Width: 93 | return None 94 | x = pos_x // SIZE 95 | y = pos_y // SIZE 96 | if pos_x % SIZE > Stone_Radius: 97 | x += 1 98 | if pos_y % SIZE > Stone_Radius: 99 | y += 1 100 | if x >= Line_Points or y >= Line_Points: 101 | return None 102 | 103 | return Point(x, y) 104 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/DrawUI.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from collections import namedtuple 3 | 4 | SIZE = 30 # 棋盘每个点时间的间隔 5 | Line_Points = 9 # 棋盘每行/每列点数 6 | Outer_Width = 20 # 棋盘外宽度 7 | Border_Width = 4 # 边框宽度 8 | Inside_Width = 4 # 边框跟实际的棋盘之间的间隔 9 | Border_Length = SIZE * (Line_Points - 1) + Inside_Width * 2 + Border_Width # 边框线的长度 10 | Start_X = Start_Y = Outer_Width + int(Border_Width / 2) + Inside_Width # 网格线起点(左上角)坐标 11 | SCREEN_HEIGHT = SIZE * (Line_Points - 1) + Outer_Width * 2 + Border_Width + Inside_Width * 2 # 游戏屏幕的高 12 | SCREEN_WIDTH = SCREEN_HEIGHT + 200 # 游戏屏幕的宽 13 | 14 | Stone_Radius = SIZE // 2 - 3 # 棋子半径 15 | Stone_Radius2 = SIZE // 2 + 3 16 | Checkerboard_Color = (0xFA, 0xEB, 0xD7) # 棋盘颜色 17 | BLACK_COLOR = (0, 0, 0) 18 | WHITE_COLOR = (255, 255, 255) 19 | RED_COLOR = (200, 30, 30) 20 | BLUE_COLOR = (30, 30, 200) 21 | 22 | RIGHT_INFO_POS_X = SCREEN_HEIGHT + Stone_Radius2 * 2 + 10 23 | Point = namedtuple('Point', 'X Y') 24 | Chessman = namedtuple('Chessman', 'Name Value Color') 25 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 26 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 27 | 28 | def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 29 | imgText = font.render(text, True, fcolor) 30 | screen.blit(imgText, (x, y)) 31 | 32 | # 画棋盘 33 | class DrawUI: 34 | def _draw_checkerboard(screen): 35 | # 填充棋盘背景色 36 | screen.fill(Checkerboard_Color) 37 | # 画棋盘网格线外的边框 38 | pygame.draw.rect(screen, BLACK_COLOR, (Outer_Width, Outer_Width, Border_Length, Border_Length), Border_Width) 39 | # 画网格线 40 | for i in range(Line_Points): 41 | pygame.draw.line(screen, BLACK_COLOR, 42 | (Start_Y, Start_Y + SIZE * i), 43 | (Start_Y + SIZE * (Line_Points - 1), Start_Y + SIZE * i), 44 | 1) 45 | for j in range(Line_Points): 46 | pygame.draw.line(screen, BLACK_COLOR, 47 | (Start_X + SIZE * j, Start_X), 48 | (Start_X + SIZE * j, Start_X + SIZE * (Line_Points - 1)), 49 | 1) 50 | # # 画星位和天元 51 | # for i in (3, 9, 15): 52 | # for j in (3, 9, 15): 53 | # if i == j == 9: 54 | # radius = 5 55 | # else: 56 | # radius = 3 57 | # # pygame.draw.circle(screen, BLACK, (Start_X + SIZE * i, Start_Y + SIZE * j), radius) 58 | # pygame.gfxdraw.aacircle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 59 | # pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR) 60 | 61 | 62 | # 画棋子 63 | def _draw_chessman(screen, point, stone_color): 64 | # pygame.draw.circle(screen, stone_color, (Start_X + SIZE * point.X, Start_Y + SIZE * point.Y), Stone_Radius) 65 | pygame.gfxdraw.aacircle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 66 | pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color) 67 | 68 | def _draw_chessman_pos(screen, pos, stone_color): 69 | pygame.gfxdraw.aacircle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 70 | pygame.gfxdraw.filled_circle(screen, pos[0], pos[1], Stone_Radius2, stone_color) 71 | 72 | # 画左侧信息显示 73 | def _draw_left_info(screen, font, cur_runner, black_win_count, white_win_count,self): 74 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2), BLACK_CHESSMAN.Color) 75 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2 * 4), WHITE_CHESSMAN.Color) 76 | 77 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + 3, '玩家', BLUE_COLOR) 78 | print_text(screen, font, RIGHT_INFO_POS_X, Start_X + Stone_Radius2 * 3 + 3, '电脑', BLUE_COLOR) 79 | 80 | print_text(screen, font, SCREEN_HEIGHT, SCREEN_HEIGHT - Stone_Radius2 * 8, '战况:', BLUE_COLOR) 81 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - int(Stone_Radius2 * 4.5)), BLACK_CHESSMAN.Color) 82 | self._draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - Stone_Radius2 * 2), WHITE_CHESSMAN.Color) 83 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - int(Stone_Radius2 * 5.5) + 3, f'{black_win_count} 胜', BLUE_COLOR) 84 | print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - Stone_Radius2 * 3 + 3, f'{white_win_count} 胜', BLUE_COLOR) 85 | 86 | 87 | 88 | # 根据鼠标点击位置,返回游戏区坐标 89 | def _get_clickpoint(click_pos): 90 | pos_x = click_pos[0] - Start_X 91 | pos_y = click_pos[1] - Start_Y 92 | if pos_x < -Inside_Width or pos_y < -Inside_Width: 93 | return None 94 | x = pos_x // SIZE 95 | y = pos_y // SIZE 96 | if pos_x % SIZE > Stone_Radius: 97 | x += 1 98 | if pos_y % SIZE > Stone_Radius: 99 | y += 1 100 | if x >= Line_Points or y >= Line_Points: 101 | return None 102 | 103 | return Point(x, y) 104 | -------------------------------------------------------------------------------- /源码/博弈单元/capture.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # from skimage.measure import compare_ssim 3 | from skimage.metrics import structural_similarity 4 | import argparse 5 | import imutils 6 | import cv2 7 | import Camera 8 | 9 | 10 | def capture(): 11 | image_path = "/home/pi/ArmPi/play_the_chess/recongnize/picture/" 12 | 13 | # image = cv2.imread(image_path+'1.jpg') 14 | # cv2.imshow('test',image) 15 | def cut(image_to_cut): 16 | sp = image_to_cut.shape # 获取图像形状:返回【行数值,列数值】列表 17 | sz1 = sp[0] # 图像的高度(行 范围) 18 | sz2 = sp[1] 19 | #sz1=image_to_cut.height 20 | #sz2=image_to_cut.width 21 | a = int(sz1 / 2 - 150) # x start 22 | b = int(sz1 / 2 + 165) # x end 23 | c = int(sz2 / 2 - 150) # y start 24 | d = int(sz2 / 2 + 155) # y end 25 | resized_image = image_to_cut[a:b,c:d] # 裁剪图像 26 | cv2.imshow('resized', resized_image) 27 | return resized_image 28 | 29 | # 这里的长之差得315,宽之差305,有所畸变,非正方形 30 | # 不过无伤大雅——后续可直接用w和h作为长宽除法的单位 31 | 32 | def compare_between(first, second): 33 | # load the two input images 34 | imageA = cv2.imread(image_path + first) 35 | imageB = cv2.imread(image_path + second) 36 | resized_orig = cut(imageA) 37 | resized_mod = cut(imageB) 38 | # 39 | # resized_orig = cv2.resize(imageA, (500, 500)) 40 | # resized_mod = cv2.resize(imageB, (500, 500)) 41 | 42 | # 去噪声增加图像质量 43 | resultA = cv2.GaussianBlur(resized_orig, (5, 5), 1, 1) 44 | resultB = cv2.GaussianBlur(resized_mod, (5, 5), 1, 1) 45 | 46 | # convert the images to grayscale 47 | grayA = cv2.cvtColor(resultA, cv2.COLOR_BGR2GRAY) 48 | grayB = cv2.cvtColor(resultB, cv2.COLOR_BGR2GRAY) 49 | # compute the Structural Similarity Index (SSIM) between the two 50 | # images, ensuring that the difference image is returned 51 | (score, diff) = structural_similarity(grayA, grayB, full=True) 52 | diff = (diff * 255).astype("uint8") 53 | # print("SSIM: {}".format(score)) 54 | 55 | # threshold the difference image, followed by finding contours to 56 | # obtain the regions of the two input images that differ 57 | thresh = cv2.threshold(diff, 0, 255, 58 | cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 59 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 60 | cv2.CHAIN_APPROX_SIMPLE) 61 | cnts = imutils.grab_contours(cnts) 62 | 63 | # loop over the contours 64 | for c in cnts: 65 | # compute the bounding box of the contour and then draw the 66 | # bounding box on both input images to represent where the two 67 | # images differ 68 | 69 | (x, y, w, h) = cv2.boundingRect(c) 70 | if w * h > 500 and w*h<1600: 71 | cv2.rectangle(resultA, (x, y), (x + w, y + h), (0, 0, 255), 2) 72 | cv2.rectangle(resultB, (x, y), (x + w, y + h), (0, 0, 255), 2) 73 | print( 74 | "l_t bound({},{});r_b bound({},{});center:({},{})".format(x, y, (x + w), (y + h), 75 | (x + w / 2), 76 | (y + h / 2))) 77 | # print("move:({},{})".format(int((x + w )/63),int((y+h )/61))) 78 | #print("move:({},{})".format(round((x + w) / w), round((y + h) / h))) 79 | # break 80 | # print(y) 81 | 82 | # show the output images 83 | cv2.imshow("Original", resultA) 84 | cv2.imshow("Modified", resultB) 85 | # cv2.imshow("Diff", diff) 86 | # cv2.imshow("Thresh", thresh) 87 | # cv2.waitKey(0) 88 | return round((x + w) / w), round((y + h) / h) 89 | 90 | # import cv2 91 | # cap = cv2.VideoCapture(1, cv2.CAP_DSHOW) 92 | # flag = cap.isOpened() 93 | index = 1 94 | # 表示第几张图片 95 | compared = 0 96 | # 是否和之前的图片比较过 97 | 98 | my_camera = Camera.Camera() 99 | my_camera.camera_open() 100 | while True: 101 | img = my_camera.frame 102 | if img is not None: 103 | frame = img.copy() 104 | # Frame = run(frame) 105 | cv2.imshow('Frame', frame) 106 | k = cv2.waitKey(1) 107 | if k == ord('s'): # 按下s键,进入下面的保存图片操作 108 | cv2.imwrite(image_path + str(index) + ".jpg", frame) 109 | print("save" + str(index) + ".jpg successfuly!") 110 | print("-------------------------") 111 | index += 1 112 | compared = 0 113 | elif k == ord('q'): # 按下q键,程序退出 114 | break 115 | if (not compared) and index > 2: 116 | # print(str(index) + '.jpg') 117 | move = compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg') 118 | compared = 1 119 | my_camera.camera_close() 120 | cv2.destroyAllWindows() 121 | return move 122 | 123 | # while flag: 124 | # 125 | # ret, frame = cap.read() 126 | # cv2.imshow("Camera_window", frame) 127 | # k = cv2.waitKey(1) & 0xFF 128 | # if k == ord('s'): # 按下s键,进入下面的保存图片操作 129 | # cv2.imwrite("D:/rainwork/Gobang/lab1/picture/" + str(index) + ".jpg", frame) 130 | # print("save" + str(index) + ".jpg successfuly!") 131 | # print("-------------------------") 132 | # index += 1 133 | # compared = 0 134 | # elif k == ord('q'): # 按下q键,程序退出 135 | # break 136 | # if (not compared) and index > 2: 137 | # # print(str(index) + '.jpg') 138 | # move = [compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg')] 139 | # compared = 1 140 | # 141 | # # 调用compare比较两个图片的区别 142 | # cap.release() # 释放摄像头 143 | # cv2.destroyAllWindows() # 释放并销毁窗口 144 | 145 | 146 | 147 | #print("move",capture()) -------------------------------------------------------------------------------- /源码/视觉单元/capture.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # from skimage.measure import compare_ssim 3 | from skimage.metrics import structural_similarity 4 | import argparse 5 | import imutils 6 | import cv2 7 | import Camera 8 | 9 | 10 | def capture(): 11 | image_path = "/home/pi/ArmPi/play_the_chess/lab3/test/picture/" 12 | 13 | # image = cv2.imread(image_path+'1.jpg') 14 | # cv2.imshow('test',image) 15 | def cut(image_to_cut): 16 | sp = image_to_cut.shape # 获取图像形状:返回【行数值,列数值】列表 17 | sz1 = sp[0] # 图像的高度(行 范围) 18 | sz2 = sp[1] 19 | #sz1=image_to_cut.height 20 | #sz2=image_to_cut.width 21 | a = int(sz1 / 2 - 150) # x start 22 | b = int(sz1 / 2 + 165) # x end 23 | c = int(sz2 / 2 - 150) # y start 24 | d = int(sz2 / 2 + 155) # y end 25 | resized_image = image_to_cut[a:b,c:d] # 裁剪图像 26 | cv2.imshow('resized', resized_image) 27 | return resized_image 28 | 29 | # 这里的长之差得315,宽之差305,有所畸变,非正方形 30 | # 不过无伤大雅——后续可直接用w和h作为长宽除法的单位 31 | 32 | def compare_between(first, second): 33 | # load the two input images 34 | imageA = cv2.imread(image_path + first) 35 | imageB = cv2.imread(image_path + second) 36 | resized_orig = cut(imageA) 37 | resized_mod = cut(imageB) 38 | # 39 | # resized_orig = cv2.resize(imageA, (500, 500)) 40 | # resized_mod = cv2.resize(imageB, (500, 500)) 41 | 42 | # 去噪声增加图像质量 43 | resultA = cv2.GaussianBlur(resized_orig, (5, 5), 1, 1) 44 | resultB = cv2.GaussianBlur(resized_mod, (5, 5), 1, 1) 45 | 46 | # convert the images to grayscale 47 | grayA = cv2.cvtColor(resultA, cv2.COLOR_BGR2GRAY) 48 | grayB = cv2.cvtColor(resultB, cv2.COLOR_BGR2GRAY) 49 | # compute the Structural Similarity Index (SSIM) between the two 50 | # images, ensuring that the difference image is returned 51 | (score, diff) = structural_similarity(grayA, grayB, full=True) 52 | diff = (diff * 255).astype("uint8") 53 | # print("SSIM: {}".format(score)) 54 | 55 | # threshold the difference image, followed by finding contours to 56 | # obtain the regions of the two input images that differ 57 | thresh = cv2.threshold(diff, 0, 255, 58 | cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 59 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 60 | cv2.CHAIN_APPROX_SIMPLE) 61 | cnts = imutils.grab_contours(cnts) 62 | 63 | # loop over the contours 64 | for c in cnts: 65 | # compute the bounding box of the contour and then draw the 66 | # bounding box on both input images to represent where the two 67 | # images differ 68 | 69 | (x, y, w, h) = cv2.boundingRect(c) 70 | if w * h > 500 and w*h<1600: 71 | cv2.rectangle(resultA, (x, y), (x + w, y + h), (0, 0, 255), 2) 72 | cv2.rectangle(resultB, (x, y), (x + w, y + h), (0, 0, 255), 2) 73 | print( 74 | "l_t bound({},{});r_b bound({},{});center:({},{})".format(x, y, (x + w), (y + h), 75 | (x + w / 2), 76 | (y + h / 2))) 77 | # print("move:({},{})".format(int((x + w )/63),int((y+h )/61))) 78 | #print("move:({},{})".format(round((x + w) / w), round((y + h) / h))) 79 | # break 80 | # print(y) 81 | 82 | # show the output images 83 | cv2.imshow("Original", resultA) 84 | cv2.imshow("Modified", resultB) 85 | # cv2.imshow("Diff", diff) 86 | # cv2.imshow("Thresh", thresh) 87 | # cv2.waitKey(0) 88 | return round((x + w) / w), round((y + h) / h) 89 | 90 | # import cv2 91 | # cap = cv2.VideoCapture(1, cv2.CAP_DSHOW) 92 | # flag = cap.isOpened() 93 | index = 1 94 | # 表示第几张图片 95 | compared = 0 96 | # 是否和之前的图片比较过 97 | 98 | my_camera = Camera.Camera() 99 | my_camera.camera_open() 100 | while True: 101 | img = my_camera.frame 102 | if img is not None: 103 | frame = img.copy() 104 | # Frame = run(frame) 105 | cv2.imshow('Frame', frame) 106 | k = cv2.waitKey(1) 107 | if k == ord('s'): # 按下s键,进入下面的保存图片操作 108 | cv2.imwrite(image_path + str(index) + ".jpg", frame) 109 | print("save" + str(index) + ".jpg successfuly!") 110 | print("-------------------------") 111 | index += 1 112 | compared = 0 113 | elif k == ord('q'): # 按下q键,程序退出 114 | break 115 | if (not compared) and index > 2: 116 | # print(str(index) + '.jpg') 117 | move = compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg') 118 | compared = 1 119 | my_camera.camera_close() 120 | cv2.destroyAllWindows() 121 | return move 122 | 123 | # while flag: 124 | # 125 | # ret, frame = cap.read() 126 | # cv2.imshow("Camera_window", frame) 127 | # k = cv2.waitKey(1) & 0xFF 128 | # if k == ord('s'): # 按下s键,进入下面的保存图片操作 129 | # cv2.imwrite("D:/rainwork/Gobang/lab1/picture/" + str(index) + ".jpg", frame) 130 | # print("save" + str(index) + ".jpg successfuly!") 131 | # print("-------------------------") 132 | # index += 1 133 | # compared = 0 134 | # elif k == ord('q'): # 按下q键,程序退出 135 | # break 136 | # if (not compared) and index > 2: 137 | # # print(str(index) + '.jpg') 138 | # move = [compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg')] 139 | # compared = 1 140 | # 141 | # # 调用compare比较两个图片的区别 142 | # cap.release() # 释放摄像头 143 | # cv2.destroyAllWindows() # 释放并销毁窗口 144 | 145 | 146 | 147 | print("move",capture()) -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/capture.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # from skimage.measure import compare_ssim 3 | from skimage.metrics import structural_similarity 4 | import argparse 5 | import imutils 6 | import cv2 7 | import Camera 8 | 9 | 10 | def capture(): 11 | image_path = "/home/pi/ArmPi/play_the_chess/recongnize/picture/" 12 | 13 | # image = cv2.imread(image_path+'1.jpg') 14 | # cv2.imshow('test',image) 15 | def cut(image_to_cut): 16 | sp = image_to_cut.shape # 获取图像形状:返回【行数值,列数值】列表 17 | sz1 = sp[0] # 图像的高度(行 范围) 18 | sz2 = sp[1] 19 | #sz1=image_to_cut.height 20 | #sz2=image_to_cut.width 21 | a = int(sz1 / 2 - 150) # x start 22 | b = int(sz1 / 2 + 165) # x end 23 | c = int(sz2 / 2 - 150) # y start 24 | d = int(sz2 / 2 + 155) # y end 25 | resized_image = image_to_cut[a:b,c:d] # 裁剪图像 26 | cv2.imshow('resized', resized_image) 27 | return resized_image 28 | 29 | # 这里的长之差得315,宽之差305,有所畸变,非正方形 30 | # 不过无伤大雅——后续可直接用w和h作为长宽除法的单位 31 | 32 | def compare_between(first, second): 33 | # load the two input images 34 | imageA = cv2.imread(image_path + first) 35 | imageB = cv2.imread(image_path + second) 36 | resized_orig = cut(imageA) 37 | resized_mod = cut(imageB) 38 | # 39 | # resized_orig = cv2.resize(imageA, (500, 500)) 40 | # resized_mod = cv2.resize(imageB, (500, 500)) 41 | 42 | # 去噪声增加图像质量 43 | resultA = cv2.GaussianBlur(resized_orig, (5, 5), 1, 1) 44 | resultB = cv2.GaussianBlur(resized_mod, (5, 5), 1, 1) 45 | 46 | # convert the images to grayscale 47 | grayA = cv2.cvtColor(resultA, cv2.COLOR_BGR2GRAY) 48 | grayB = cv2.cvtColor(resultB, cv2.COLOR_BGR2GRAY) 49 | # compute the Structural Similarity Index (SSIM) between the two 50 | # images, ensuring that the difference image is returned 51 | (score, diff) = structural_similarity(grayA, grayB, full=True) 52 | diff = (diff * 255).astype("uint8") 53 | # print("SSIM: {}".format(score)) 54 | 55 | # threshold the difference image, followed by finding contours to 56 | # obtain the regions of the two input images that differ 57 | thresh = cv2.threshold(diff, 0, 255, 58 | cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 59 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 60 | cv2.CHAIN_APPROX_SIMPLE) 61 | cnts = imutils.grab_contours(cnts) 62 | 63 | # loop over the contours 64 | for c in cnts: 65 | # compute the bounding box of the contour and then draw the 66 | # bounding box on both input images to represent where the two 67 | # images differ 68 | 69 | (x, y, w, h) = cv2.boundingRect(c) 70 | if w * h > 500 and w*h<1600: 71 | cv2.rectangle(resultA, (x, y), (x + w, y + h), (0, 0, 255), 2) 72 | cv2.rectangle(resultB, (x, y), (x + w, y + h), (0, 0, 255), 2) 73 | print( 74 | "l_t bound({},{});r_b bound({},{});center:({},{})".format(x, y, (x + w), (y + h), 75 | (x + w / 2), 76 | (y + h / 2))) 77 | # print("move:({},{})".format(int((x + w )/63),int((y+h )/61))) 78 | #print("move:({},{})".format(round((x + w) / w), round((y + h) / h))) 79 | # break 80 | # print(y) 81 | 82 | # show the output images 83 | cv2.imshow("Original", resultA) 84 | cv2.imshow("Modified", resultB) 85 | # cv2.imshow("Diff", diff) 86 | # cv2.imshow("Thresh", thresh) 87 | # cv2.waitKey(0) 88 | return round((x + w) / w), round((y + h) / h) 89 | 90 | # import cv2 91 | # cap = cv2.VideoCapture(1, cv2.CAP_DSHOW) 92 | # flag = cap.isOpened() 93 | index = 1 94 | # 表示第几张图片 95 | compared = 0 96 | # 是否和之前的图片比较过 97 | 98 | my_camera = Camera.Camera() 99 | my_camera.camera_open() 100 | while True: 101 | img = my_camera.frame 102 | if img is not None: 103 | frame = img.copy() 104 | # Frame = run(frame) 105 | cv2.imshow('Frame', frame) 106 | k = cv2.waitKey(1) 107 | if k == ord('s'): # 按下s键,进入下面的保存图片操作 108 | cv2.imwrite(image_path + str(index) + ".jpg", frame) 109 | print("save" + str(index) + ".jpg successfuly!") 110 | print("-------------------------") 111 | index += 1 112 | compared = 0 113 | elif k == ord('q'): # 按下q键,程序退出 114 | break 115 | if (not compared) and index > 2: 116 | # print(str(index) + '.jpg') 117 | move = compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg') 118 | compared = 1 119 | my_camera.camera_close() 120 | cv2.destroyAllWindows() 121 | return move 122 | 123 | # while flag: 124 | # 125 | # ret, frame = cap.read() 126 | # cv2.imshow("Camera_window", frame) 127 | # k = cv2.waitKey(1) & 0xFF 128 | # if k == ord('s'): # 按下s键,进入下面的保存图片操作 129 | # cv2.imwrite("D:/rainwork/Gobang/lab1/picture/" + str(index) + ".jpg", frame) 130 | # print("save" + str(index) + ".jpg successfuly!") 131 | # print("-------------------------") 132 | # index += 1 133 | # compared = 0 134 | # elif k == ord('q'): # 按下q键,程序退出 135 | # break 136 | # if (not compared) and index > 2: 137 | # # print(str(index) + '.jpg') 138 | # move = [compare_between(str(index - 1) + '.jpg', str(index - 2) + '.jpg')] 139 | # compared = 1 140 | # 141 | # # 调用compare比较两个图片的区别 142 | # cap.release() # 释放摄像头 143 | # cv2.destroyAllWindows() # 释放并销毁窗口 144 | 145 | 146 | 147 | #print("move",capture()) -------------------------------------------------------------------------------- /源码/博弈单元/lab3/test/AI_alpha_beta.py: -------------------------------------------------------------------------------- 1 | '''alpha-beta剪枝''' 2 | 3 | # AI搜索的深度 4 | AI_SEARCH_DEPTH = 2 # 定义AI搜索的深度,深度2是最佳的 5 | from enum import IntEnum 6 | import time 7 | from collections import namedtuple 8 | 9 | Line_Points = 9 # 每行的点数 10 | 11 | class CHESS_TYPE(IntEnum): 12 | NONE = 0, 13 | SLEEP_TWO = 1, 14 | LIVE_TWO = 2, 15 | SLEEP_THREE = 3 16 | LIVE_THREE = 4, 17 | CHONG_FOUR = 5, 18 | LIVE_FOUR = 6, 19 | LIVE_FIVE = 7, 20 | 21 | 22 | CHESS_TYPE_NUM = 8 23 | 24 | FIVE = CHESS_TYPE.LIVE_FIVE.value 25 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 26 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 27 | 28 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 29 | Chessman = namedtuple('Chessman', 'Name Value Color') 30 | Point = namedtuple('Point', 'X Y') 31 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 32 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 33 | 34 | CHESS_TYPE_NUM = 8 35 | 36 | FIVE = CHESS_TYPE.LIVE_FIVE.value 37 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 38 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 39 | 40 | SCORE_MAX = 0x7fffffff 41 | SCORE_MIN = -1 * SCORE_MAX 42 | 43 | 44 | # SCORE_FIVE = 10000 45 | 46 | 47 | class ChessAI(): 48 | def __init__(self, line_points, chessman): 49 | self.len = line_points # 10 50 | self._my = chessman 51 | # 水平、竖直、左右斜方向 52 | self.record = [[[0, 0, 0, 0] for x in range(line_points)] for y in range(line_points)] 53 | self.count = [[0 for x in range(CHESS_TYPE_NUM)] for i in range(2)] 54 | self.pos_score = [[(9 - max(abs(x - 9), abs(y - 9))) for x in range(line_points)] for y in range(line_points)] 55 | self._opponent = BLACK_CHESSMAN if chessman == WHITE_CHESSMAN else WHITE_CHESSMAN 56 | # 单纯循环整个棋盘 57 | self.board = [[0] * line_points for _ in range(line_points)] 58 | 59 | def reset(self): 60 | for y in range(self.len): 61 | for x in range(self.len): 62 | for i in range(4): 63 | self.record[y][x][i] = 0 64 | 65 | for i in range(len(self.count)): 66 | for j in range(len(self.count[0])): 67 | self.count[i][j] = 0 68 | 69 | # 获得对手的棋,也就是电脑玩家鼠标点击的地方 70 | def get_opponent_drop(self, point): 71 | self.board[point.Y][point.X] = self._opponent.Value # 1 72 | 73 | def click(self, map, x, y, turn): 74 | map.click(x, y, turn) 75 | 76 | # check if has a none empty position in it's radius range 77 | def hasNeighbor(self, x, y, radius): 78 | start_x, end_x = (x - radius), (x + radius) 79 | start_y, end_y = (y - radius), (y + radius) 80 | 81 | for i in range(start_y, end_y + 1): 82 | for j in range(start_x, end_x + 1): 83 | if i >= 0 and i < self.len and j >= 0 and j < self.len: 84 | if self.board[i][j] != 0: 85 | return True 86 | return False 87 | 88 | # get all positions near chess 89 | def genmove(self, turn): 90 | fives = [] 91 | mfours, ofours = [], [] 92 | msfours, osfours = [], [] 93 | if turn == WHITE_CHESSMAN.Value: 94 | mine = 2 95 | opponent = 1 96 | else: 97 | mine = 1 98 | opponent = 2 99 | 100 | moves = [] 101 | radius = 1 102 | 103 | for y in range(self.len): # self.len=10 104 | for x in range(self.len): 105 | if self.board[y][x] == 0 and self.hasNeighbor(x, y, radius): # hasNeignbor查看周围是否有棋子 106 | score = self.pos_score[y][x] 107 | moves.append((score, x, y)) 108 | 109 | moves.sort(reverse=True) 110 | return moves 111 | 112 | def __search(self, AI_model, turn, depth, alpha=SCORE_MIN, beta=SCORE_MAX): 113 | # 用模型预测的值作为评估函数 114 | score = AI_model.get_score_ANN(self.board) 115 | # if depth <= 0 or abs(score) >= SCORE_FIVE: 116 | if depth <= 0: 117 | return score 118 | 119 | moves = self.genmove(turn) 120 | bestmove = None 121 | self.alpha += len(moves) 122 | 123 | # if there are no moves, just return the score 124 | if len(moves) == 0: 125 | return score 126 | 127 | for _, x, y in moves: 128 | self.board[y][x] = turn 129 | if turn == WHITE_CHESSMAN.Value: 130 | op_turn = BLACK_CHESSMAN.Value 131 | else: 132 | op_turn = WHITE_CHESSMAN.Value 133 | 134 | score = - self.__search(AI_model, op_turn, depth - 1, -beta, -alpha) 135 | 136 | self.board[y][x] = 0 137 | self.belta += 1 138 | 139 | # alpha/beta pruning 140 | if score > alpha: 141 | alpha = score 142 | bestmove = (x, y) 143 | if alpha >= beta: 144 | break 145 | 146 | if depth == self.maxdepth and bestmove: 147 | self.bestmove = bestmove 148 | return alpha 149 | 150 | def search(self, turn, depth, AI_model): 151 | self.maxdepth = depth 152 | self.bestmove = None 153 | score = self.__search(AI_model, turn, depth) 154 | # 找不到最佳的位置则返回(-1, -1) 155 | if self.bestmove == None: 156 | # 如果没有最好的点,则随机给一个 157 | for y in range(Line_Points): 158 | for x in range(Line_Points): 159 | if self.board[y][x] == 0: 160 | return score, x, y 161 | # 棋盘已满,认定为输 162 | return score, -1, -1 163 | else: 164 | x, y = self.bestmove 165 | self.temp_point = Point(x, y) 166 | return score, x, y 167 | 168 | def findBestChess(self, turn, AI_model): 169 | time1 = time.time() 170 | self.alpha = 0 171 | self.belta = 0 172 | score, x, y = self.search(turn, AI_SEARCH_DEPTH, AI_model) 173 | point = Point(x, y) 174 | time2 = time.time() 175 | # print('time[%.2f] (%d, %d), score[%d] alpha[%d] belta[%d]' % ( 176 | # (time2 - time1), x, y, score, self.alpha, self.belta)) 177 | self.board[y][x] = WHITE_CHESSMAN.Value 178 | return point, score 179 | -------------------------------------------------------------------------------- /源码/博弈单元/lab3/train/AI_alpha_beta.py: -------------------------------------------------------------------------------- 1 | '''alpha-beta剪枝''' 2 | 3 | # AI搜索的深度 4 | AI_SEARCH_DEPTH = 2 # 定义AI搜索的深度,深度2是最佳的 5 | from enum import IntEnum 6 | import time 7 | from collections import namedtuple 8 | 9 | Line_Points = 9 # 每行的点数 10 | 11 | class CHESS_TYPE(IntEnum): 12 | NONE = 0, 13 | SLEEP_TWO = 1, 14 | LIVE_TWO = 2, 15 | SLEEP_THREE = 3 16 | LIVE_THREE = 4, 17 | CHONG_FOUR = 5, 18 | LIVE_FOUR = 6, 19 | LIVE_FIVE = 7, 20 | 21 | 22 | CHESS_TYPE_NUM = 8 23 | 24 | FIVE = CHESS_TYPE.LIVE_FIVE.value 25 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 26 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 27 | 28 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 29 | Chessman = namedtuple('Chessman', 'Name Value Color') 30 | Point = namedtuple('Point', 'X Y') 31 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 32 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 33 | 34 | CHESS_TYPE_NUM = 8 35 | 36 | FIVE = CHESS_TYPE.LIVE_FIVE.value 37 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 38 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 39 | 40 | SCORE_MAX = 0x7fffffff 41 | SCORE_MIN = -1 * SCORE_MAX 42 | 43 | 44 | # SCORE_FIVE = 10000 45 | 46 | 47 | class ChessAI(): 48 | def __init__(self, line_points, chessman): 49 | self.len = line_points # 10 50 | self._my = chessman 51 | # 水平、竖直、左右斜方向 52 | self.record = [[[0, 0, 0, 0] for x in range(line_points)] for y in range(line_points)] 53 | self.count = [[0 for x in range(CHESS_TYPE_NUM)] for i in range(2)] 54 | self.pos_score = [[(9 - max(abs(x - 9), abs(y - 9))) for x in range(line_points)] for y in range(line_points)] 55 | self._opponent = BLACK_CHESSMAN if chessman == WHITE_CHESSMAN else WHITE_CHESSMAN 56 | # 单纯循环整个棋盘 57 | self.board = [[0] * line_points for _ in range(line_points)] 58 | 59 | def reset(self): 60 | for y in range(self.len): 61 | for x in range(self.len): 62 | for i in range(4): 63 | self.record[y][x][i] = 0 64 | 65 | for i in range(len(self.count)): 66 | for j in range(len(self.count[0])): 67 | self.count[i][j] = 0 68 | 69 | # 获得对手的棋,也就是电脑玩家鼠标点击的地方 70 | def get_opponent_drop(self, point): 71 | self.board[point.Y][point.X] = self._opponent.Value # 1 72 | 73 | def click(self, map, x, y, turn): 74 | map.click(x, y, turn) 75 | 76 | # check if has a none empty position in it's radius range 77 | def hasNeighbor(self, x, y, radius): 78 | start_x, end_x = (x - radius), (x + radius) 79 | start_y, end_y = (y - radius), (y + radius) 80 | 81 | for i in range(start_y, end_y + 1): 82 | for j in range(start_x, end_x + 1): 83 | if i >= 0 and i < self.len and j >= 0 and j < self.len: 84 | if self.board[i][j] != 0: 85 | return True 86 | return False 87 | 88 | # get all positions near chess 89 | def genmove(self, turn): 90 | fives = [] 91 | mfours, ofours = [], [] 92 | msfours, osfours = [], [] 93 | if turn == WHITE_CHESSMAN.Value: 94 | mine = 2 95 | opponent = 1 96 | else: 97 | mine = 1 98 | opponent = 2 99 | 100 | moves = [] 101 | radius = 1 102 | 103 | for y in range(self.len): # self.len=10 104 | for x in range(self.len): 105 | if self.board[y][x] == 0 and self.hasNeighbor(x, y, radius): # hasNeignbor查看周围是否有棋子 106 | score = self.pos_score[y][x] 107 | moves.append((score, x, y)) 108 | 109 | moves.sort(reverse=True) 110 | return moves 111 | 112 | def __search(self, AI_model, turn, depth, alpha=SCORE_MIN, beta=SCORE_MAX): 113 | # 用模型预测的值作为评估函数 114 | score = AI_model.get_score_ANN(self.board) 115 | # if depth <= 0 or abs(score) >= SCORE_FIVE: 116 | if depth <= 0: 117 | return score 118 | 119 | moves = self.genmove(turn) 120 | bestmove = None 121 | self.alpha += len(moves) 122 | 123 | # if there are no moves, just return the score 124 | if len(moves) == 0: 125 | return score 126 | 127 | for _, x, y in moves: 128 | self.board[y][x] = turn 129 | if turn == WHITE_CHESSMAN.Value: 130 | op_turn = BLACK_CHESSMAN.Value 131 | else: 132 | op_turn = WHITE_CHESSMAN.Value 133 | 134 | score = - self.__search(AI_model, op_turn, depth - 1, -beta, -alpha) 135 | 136 | self.board[y][x] = 0 137 | self.belta += 1 138 | 139 | # alpha/beta pruning 140 | if score > alpha: 141 | alpha = score 142 | bestmove = (x, y) 143 | if alpha >= beta: 144 | break 145 | 146 | if depth == self.maxdepth and bestmove: 147 | self.bestmove = bestmove 148 | return alpha 149 | 150 | def search(self, turn, depth, AI_model): 151 | self.maxdepth = depth 152 | self.bestmove = None 153 | score = self.__search(AI_model, turn, depth) 154 | # 找不到最佳的位置则返回(-1, -1) 155 | if self.bestmove == None: 156 | # 如果没有最好的点,则随机给一个 157 | for y in range(Line_Points): 158 | for x in range(Line_Points): 159 | if self.board[y][x] == 0: 160 | return score, x, y 161 | # 棋盘已满,认定为输 162 | return score, -1, -1 163 | else: 164 | x, y = self.bestmove 165 | self.temp_point = Point(x, y) 166 | return score, x, y 167 | 168 | def findBestChess(self, turn, AI_model): 169 | time1 = time.time() 170 | self.alpha = 0 171 | self.belta = 0 172 | score, x, y = self.search(turn, AI_SEARCH_DEPTH, AI_model) 173 | point = Point(x, y) 174 | time2 = time.time() 175 | # print('time[%.2f] (%d, %d), score[%d] alpha[%d] belta[%d]' % ( 176 | # (time2 - time1), x, y, score, self.alpha, self.belta)) 177 | self.board[y][x] = WHITE_CHESSMAN.Value 178 | return point, score 179 | -------------------------------------------------------------------------------- /源码/控制单元/README.md: -------------------------------------------------------------------------------- 1 | ## 控制单元总结 2 | 3 | ### 一、串口通信 4 | 5 | 树莓派的内存只有16GB,且很多深度学习框架并没有支持该系统的可执行文件,甚至需要自己去编译配置,那么这是一项极其耗时且费力的工作。在这一部分我将展示如何利用Socket进行windows和LInux的串口通信(推荐),如果你仍然执着于模型部署,那么请直接跳至第二部分。 6 | 7 | #### 1 什么是socket? 8 | 9 | 首先我们需要理解什么是网络编程,网络编程就是编写程序使两台联网的计算机之间能够进行通信,即能相互交换数据。 10 | 11 | 然后我们再来理解socket,socket即套接字,是操作系统提供的独立于具体协议的网络编程接口,使用socket可以很方便地编写出数据传输程序,实现计算机之间的通信,而无需考虑其背后的原理。 12 | 13 | socket 的一个典型应用就是 Web 服务器和浏览器:浏览器获取用户输入的 URL,向服务器发起请求,服务器分析接收到的 URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,就将文字、图片、视频等元素呈现给用户。 14 | 15 | #### 2 基于python的socket传输 16 | 17 | ##### 2.1 环境配置 18 | 19 | *具体的配置环境过程见第二部分,这里只展示包含socket的安装过程.* 20 | 21 | 注意!这里windows和树莓派都需要安装socket,届时需要分别启动进行通信。 22 | 23 | ```python 24 | pip install socket 25 | ``` 26 | 27 | ##### 2.2 代码详解 28 | 29 | Socket通信分为客户端与服务端。顾名思义,当二者同时启动时,客户端连接设置好的主机ip和串口(此处分别为192.168.149.1和22),发送已编码的字符串数据(这里包含3个参数:X坐标,Y坐标,棋局状态),服务端被连接后接受数据,并解码后传递给机械臂执行放置五子棋的动作。 30 | 31 | - transmit.py,即客户端: 32 | 33 | ```python 34 | import socket 35 | new_socket = socket.socket() #创建socket对象 36 | ip = "192.168.149.1" # 树莓派地址 37 | port = 22 # 设置默认端口 38 | new_socket.connect((ip,port)) 39 | i=0 40 | while 1: 41 | #这里只是接受输入,若是和树莓派配合只需要分装一个小函数接受博弈单元的输入即可 42 | #如:x,y,z = result(),result()为博弈单元结果 43 | x = input() 44 | y= input() 45 | z = input() 46 | t = x+","+y+","+z 47 | new_socket.send(t.encode()) 48 | i+=1 49 | if i==4: 50 | back_str = new_socket.recv(1024).decode() #结束数据 51 | break 52 | new_socket.close() #关闭客户端 53 | print("客户端结束运行") 54 | ``` 55 | 56 | - Sever.py,即服务器端: 57 | 58 | ```python 59 | import socket 60 | 61 | def main(): 62 | ''' 63 | socket communication between Windows and Linux 64 | ''' 65 | #服务端 66 | new_socket = socket.socket() # 创建 socket 对象 67 | ip = "192.168.149.1" # 获取本地主机名 68 | port = 22 # 设置端口 69 | new_socket.bind((ip, port)) # 绑定端口 70 | new_socket.listen(20) # 等待客户端连接并设置最大连接数 71 | while True: 72 | init_position() 73 | new_cil, addr = new_socket.accept() # 建立客户端连接。 74 | print('新进来的客户端的地址:', addr) 75 | t = new_cil.recv(1024).decode() 76 | t = t.split(',') 77 | #—————————————————————————————— 78 | put_chess(int(t[0]),int(t[1])) #控制树莓派进行下棋的函数put_chess() 79 | #—————————————————————————————— 80 | if(int(t[2]==0)): 81 | new_cil.close() # 关闭连接 82 | 83 | main() 84 | ``` 85 | 86 | #### 3 使用详解 87 | 88 | ==首先启用服务端!首先启用服务端!首先启用服务端!重要的事情说三遍!== 89 | 90 | 之后再开启客户端,进行通信服务。 91 | 92 | ##### 3.1 遇到的问题及解决方法 93 | 94 | Socket通信对端口并发要求很严格,往往因为调试的时候启动次数过多导致端口被占用,如下: 95 | 96 | ![image-20210726220832383-16273085145031](https://user-images.githubusercontent.com/60317828/127079293-d874bd19-c96a-4987-b140-c2b050c81ca3.png) 97 | 98 | 这里先观察对应端口进程,之后杀死进程即可,如下: 99 | 100 | ![image-20210726220847766-16273085291192](https://user-images.githubusercontent.com/60317828/127079307-c5152c09-04fa-4a2a-a08a-15eba1595b8f.png) 101 | 102 | 具体代码(别说你不会使Linux): 103 | 104 | ``` 105 | $ sudo lsof -i:xxx #你对应的端口号 106 | $ sudo kill -9 xxx #上图中PID所示进程(这里显示21227) 107 | ``` 108 | 109 | ### 二、环境配置 110 | 111 | #### 1 前言 112 | 113 | 首先说明下为什么进行环境配置,以及为什么不需要它。 114 | 115 | 模型是可以在本地进行训练得到的,但是假如要把模型部署到树莓派上的话,至少环境能跑推断。博弈单元和视觉单元涉及许多深度学习甚至强化学习的方法,如果环境不行的话根本运行不了,更不用说操控机械臂了。 116 | 117 | 但是,这也是不必须的,在给树莓派安装python的基础上。只需要用第一部分讲的socket进行通信,就可以让机械臂只负责控制,而不用跑推断了。 118 | 119 | #### 2 环境配置详解 120 | 121 | ##### 2.1 硬件环境 122 | 123 | ![image-20210726221924932](https://user-images.githubusercontent.com/60317828/127079355-882d8f1c-f426-405c-9be1-91b89a4cb54a.png) 124 | 125 | 观察到是32为Linux系统,注意下载包的时候要==aarch64==的。 126 | 127 | ##### 2.2 安装python 128 | 129 | 这个就不多说了,网上一堆教程,下一个linux版本的python就行 130 | 131 | ##### 2.3 重定向python3 132 | 133 | 因为Linux系统本身是安装好python2 和 python3的,但是有些python3的版本太老了,没法直接使,所以要么按2.2下载完重定向,要么直接重定向,如下: 134 | 135 | ![image-20210726221847086-16273091280673](https://user-images.githubusercontent.com/60317828/127079363-583cf065-271d-429a-abba-fd9a38a50a47.png) 136 | 137 | ##### 2.4 第三方库安装 138 | 139 | ```python 140 | sudo pip install h5py==2.9.0 Keras==2.3.1 numpy==1.20.3 opencv-python==4.1.1.26 scikit-image==0.18.1 scipy==1.5.1 tensorflow==2.0.0 141 | ``` 142 | 143 | ==*注意要加超级用户 sudo !*== 144 | 145 | ##### 2.5 深度学习框架安装 146 | 147 | 这个是真的狗,我记得我在这边搞了15个小时左右才弄完,主要原因是官网上没有树莓派的whl文件,其他的根本用不了。有大佬说可以直接编译,但我怕搞崩。毕竟2000¥一个机械臂啊~ 148 | 149 | pytorch的话记得是直接pip install的,tensorflow直接下载别人编译好的whl文件(如果找不到的话可以qq联系我,2485794339@qq.com,这里是tensorflow-2.0.0版本的) 150 | 151 | 安装 152 | 153 | done! 154 | 155 | ### 三、机械臂控制 156 | 157 | #### **技术方案概述:** 158 | 159 | 该部分工作主要包括两部分,分别是控制机械臂对五子棋进行抓取和放置。抓取部分我们采用主动“喂”棋子的方式进行,放置部分包含正逆运动学和深度学习两种方式进行计算和控制。 160 | 161 | #### 1 **抓取函数** 162 | 163 | 在经过大量的实验后,我们最终采用人为“喂”给机械臂五子棋的方案。 164 | 165 | 为防止机械臂下完棋子后遮挡摄像头识别的视线,且以一种更易交互的形式拿到棋子,我们编写了其初始位置函数,具体参数如下: 166 | 167 | | 2 | 3 | 4 | 5 | 6 | time sleep | 168 | | :--: | :--: | :--: | :--: | :--: | :--------: | 169 | | 500 | 300 | 800 | 700 | 850 | 0.5 s | 170 | 171 | #### 2 **放置函数** 172 | 173 | ##### 2.1 **映射函数** 174 | 175 | 当博弈单元提供下棋位置时,需要利用映射函数完成机械臂坐标系—电脑棋盘坐标系之间转换,映射函数如下: 176 | $$ 177 | X: A = -2* B+10\\ 178 | Y: A = 2.5* B+10 179 | $$ 180 | 其中,A是机械臂坐标系中坐标,B是电脑棋盘坐标系的坐标。 181 | 182 | ##### 2.2 **正逆运动学控制** 183 | 184 | 这个是机械臂自带的控制函数,参数为坐标位置,输出为3、4、5、6号四个舵机的旋转角度。由于五子棋直径约为2.5cm,为了在放置其他棋子时不影响其他已放置棋子的状态,且能随距离远近调整高度,总结出如下方案: 185 | 186 | 放置高度与坐标关系: 187 | $$ 188 | z = 0.05* y+1.5 189 | $$ 190 | *fine-tunning:* 191 | 192 | 将机械臂到达指定位置后,调整3、4、5号舵机位置,并使前爪旋转45度,以斜侧入的形式进行放置。 193 | 194 | ##### 2.3 深度学习 195 | 196 | 这里使用深度学习的方式,学习目标是构建目标位置与3、4、5、6号舵机旋转角度的映射关系。 197 | 198 | 首先基于正逆运动学的方法,记录机械臂在9*9棋牌上,共81个位置的舵机信息,构造训练集,详见position.txt。 199 | 200 | 之后构建了三层感知机,学习映射函数,在windows10、pytorch环境下进行训练,并将模型最终部署到树莓派上得以使用。具体参数如下: 201 | 202 | | 损失函数 | 学习率 | Epoch | 优化器 | Loss | 203 | | :------: | :----: | :---: | :----: | :----: | 204 | | MSE | 0.01 | 240 | Adam | 299.00 | 205 | 206 | *只是这里简单的搭了个MLP,精读方面还有很大的提升空间* 207 | 208 | #### 3 **实验结论** 209 | 210 | 我们对五子棋的正反放置位置、放置坐标范围进行实验,得到以下结论: 211 | 212 | 1) 因为五子棋的正反两面质量不同(正面弧、背面平),所以喂给机械臂五子棋时需要将背面朝特定方位,使得五子棋放置时不会出现翻滚导致位置偏移; 213 | 214 | 2) 未进行坐标系转换时机械臂控制良好,进行转换后发现机械臂在X轴两侧均有误差,且随距原点越远误差越大,但总体仍处于可接受范围。经讨论,认为是由于机械臂下需放置棋盘,导致前后不水平,使映射呈非线性的状态。 215 | 216 | ### 四、其他 217 | 218 | 1. 因为采用pip安装的时候需要联网下载,而本身咱们是通过局域网连接树莓派服务器的,所以要解决上网问题: 219 | 220 | ​ (1)整根网线,插树莓派上 221 | 222 | ​ (2)利用蓝牙通信(听玩过平衡小车的同学说可以这么搞) 223 | 224 | 2. 外接摄像头需要额外购入,最好买固焦的摄像头。然后是插电脑主机上还是插树莓派上根据采用方法一还是方法二决定。不过,有些函数就需要变动,无法直接使用. 225 | 226 | 3. 各文件用途: 227 | 228 | - ANN.py : 深度学习代码 229 | - move.py:机械臂控制代码,包含正逆运动学和深度学习两个接口 230 | - my_model.pth: 深度学习训练的模型 231 | - position.txt : 9*9棋盘共81个位置,每个位置对应机械臂坐标系下位置坐标 232 | - train.txt : 81个位置各舵机的参数,深度学习训练集 233 | - sever.py: 服务器端代码 234 | - transmit.py: 客户端代码 235 | -------------------------------------------------------------------------------- /源码/博弈单元/AI_alpha_beta.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from random import randint 3 | 4 | # AI搜索的深度 5 | AI_SEARCH_DEPTH = 3 # 定义AI搜索的深度,深度2是最佳的 6 | from enum import IntEnum 7 | import time 8 | from collections import namedtuple 9 | 10 | 11 | class CHESS_TYPE(IntEnum): 12 | NONE = 0, 13 | SLEEP_TWO = 1, 14 | LIVE_TWO = 2, 15 | SLEEP_THREE = 3 16 | LIVE_THREE = 4, 17 | CHONG_FOUR = 5, 18 | LIVE_FOUR = 6, 19 | LIVE_FIVE = 7, 20 | 21 | CHESS_TYPE_NUM = 8 22 | 23 | FIVE = CHESS_TYPE.LIVE_FIVE.value 24 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 25 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 26 | 27 | offset = [(1, 0), (0, 1), (1, 1), (1, -1)] 28 | Chessman = namedtuple('Chessman', 'Name Value Color') 29 | Point = namedtuple('Point', 'X Y') 30 | BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45)) 31 | WHITE_CHESSMAN = Chessman('白子', 2, (255, 255, 255)) 32 | 33 | CHESS_TYPE_NUM = 8 34 | 35 | FIVE = CHESS_TYPE.LIVE_FIVE.value 36 | FOUR, THREE, TWO = CHESS_TYPE.LIVE_FOUR.value, CHESS_TYPE.LIVE_THREE.value, CHESS_TYPE.LIVE_TWO.value 37 | SFOUR, STHREE, STWO = CHESS_TYPE.CHONG_FOUR.value, CHESS_TYPE.SLEEP_THREE.value, CHESS_TYPE.SLEEP_TWO.value 38 | 39 | SCORE_MAX = 0x7fffffff 40 | SCORE_MIN = -1 * SCORE_MAX 41 | SCORE_FIVE = 10000 42 | 43 | 44 | class ChessAI(): 45 | def __init__(self, line_points , chessman): 46 | self.len = line_points # 19 47 | self._my = chessman 48 | # 水平、竖直、左右斜方向 49 | self.record = [[[0, 0, 0, 0] for x in range(line_points)] for y in range(line_points)] 50 | self.count = [[0 for x in range(CHESS_TYPE_NUM)] for i in range(2)] 51 | self.pos_score = [[(9 - max(abs(x - 9), abs(y - 9))) for x in range(line_points)] for y in range(line_points)] 52 | self._opponent = BLACK_CHESSMAN if chessman == WHITE_CHESSMAN else WHITE_CHESSMAN 53 | # 单纯循环整个棋盘 54 | self.board = [[0] * line_points for _ in range(line_points)] 55 | 56 | 57 | def reset(self): 58 | for y in range(self.len): 59 | for x in range(self.len): 60 | for i in range(4): 61 | self.record[y][x][i] = 0 62 | 63 | for i in range(len(self.count)): 64 | for j in range(len(self.count[0])): 65 | self.count[i][j] = 0 66 | 67 | # 获得对手的棋,也就是电脑玩家鼠标点击的地方 68 | def get_opponent_drop(self, point): 69 | self.board[point.Y][point.X] = self._opponent.Value # 1 70 | 71 | def click(self, map, x, y, turn): 72 | map.click(x, y, turn) 73 | 74 | # check if has a none empty position in it's radius range 75 | def hasNeighbor(self, x, y, radius): 76 | start_x, end_x = (x - radius), (x + radius) 77 | start_y, end_y = (y - radius), (y + radius) 78 | 79 | for i in range(start_y, end_y + 1): 80 | for j in range(start_x, end_x + 1): 81 | if i >= 0 and i < self.len and j >= 0 and j < self.len: 82 | if self.board[i][j] != 0: 83 | return True 84 | return False 85 | 86 | # get all positions near chess 87 | def genmove(self, turn): 88 | fives = [] 89 | mfours, ofours = [], [] 90 | msfours, osfours = [], [] 91 | if turn == WHITE_CHESSMAN.Value: 92 | mine = 2 93 | opponent = 1 94 | else: 95 | mine = 1 96 | opponent = 2 97 | 98 | moves = [] 99 | radius = 1 100 | 101 | for y in range(self.len): # self.len=19 102 | for x in range(self.len): 103 | if self.board[y][x] == 0 and self.hasNeighbor(x, y, radius): # hasNeignbor查看周围是否有棋子 104 | score = self.pos_score[y][x] 105 | moves.append((score, x, y)) 106 | 107 | moves.sort(reverse=True) 108 | 109 | return moves 110 | 111 | def __search(self, turn, depth, alpha=SCORE_MIN, beta=SCORE_MAX): 112 | score = self.evaluate(turn) 113 | if depth <= 0 or abs(score) >= SCORE_FIVE: 114 | return score 115 | 116 | moves = self.genmove(turn) 117 | bestmove = None 118 | self.alpha += len(moves) 119 | 120 | # if there are no moves, just return the score 121 | if len(moves) == 0: 122 | return score 123 | 124 | for _, x, y in moves: 125 | self.board[y][x] = turn 126 | 127 | if turn == WHITE_CHESSMAN.Value: 128 | op_turn = BLACK_CHESSMAN.Value 129 | else: 130 | op_turn = WHITE_CHESSMAN.Value 131 | 132 | score = - self.__search(op_turn, depth - 1, -beta, -alpha) 133 | 134 | self.board[y][x] = 0 135 | self.belta += 1 136 | 137 | # alpha/beta pruning 138 | if score > alpha: 139 | alpha = score 140 | bestmove = (x, y) 141 | if alpha >= beta: 142 | break 143 | 144 | if depth == self.maxdepth and bestmove: 145 | self.bestmove = bestmove 146 | #print("alpha=" + str(alpha)) 147 | return alpha 148 | 149 | def search(self, turn, depth): 150 | self.maxdepth = depth 151 | self.bestmove = None 152 | score = self.__search(turn, depth) 153 | if self.bestmove == None: 154 | return score, -1, -1 155 | else: 156 | x, y = self.bestmove 157 | return score, x, y 158 | 159 | def findBestChess(self, turn): 160 | time1 = time.time() 161 | self.alpha = 0 162 | self.belta = 0 163 | score, x, y = self.search(turn, AI_SEARCH_DEPTH) 164 | point = Point(x, y) 165 | time2 = time.time() 166 | #print('time[%.2f] (%d, %d), score[%d] alpha[%d] belta[%d]' % ( 167 | # (time2 - time1), x, y, score, self.alpha, self.belta)) 168 | self.board[y][x] = WHITE_CHESSMAN.Value 169 | return point, score 170 | 171 | # calculate score, FIXME: May Be Improved 172 | def getScore(self, mine_count, opponent_count): 173 | mscore, oscore = 0, 0 174 | if mine_count[FIVE] > 0: 175 | return (SCORE_FIVE, 0) 176 | if opponent_count[FIVE] > 0: 177 | return (0, SCORE_FIVE) 178 | 179 | if mine_count[SFOUR] >= 2: 180 | mine_count[FOUR] += 1 181 | if opponent_count[SFOUR] >= 2: 182 | opponent_count[FOUR] += 1 183 | 184 | if mine_count[FOUR] > 0: 185 | return (9050, 0) 186 | if mine_count[SFOUR] > 0: 187 | return (9040, 0) 188 | 189 | if opponent_count[FOUR] > 0: 190 | return (0, 9030) 191 | if opponent_count[SFOUR] > 0 and opponent_count[THREE] > 0: 192 | return (0, 9020) 193 | 194 | if mine_count[THREE] > 0 and opponent_count[SFOUR] == 0: 195 | return (9010, 0) 196 | 197 | if (opponent_count[THREE] > 1 and mine_count[THREE] == 0 and mine_count[STHREE] == 0): 198 | return (0, 9000) 199 | 200 | if opponent_count[SFOUR] > 0: 201 | oscore += 400 202 | 203 | if mine_count[THREE] > 1: 204 | mscore += 500 205 | elif mine_count[THREE] > 0: 206 | mscore += 100 207 | 208 | if opponent_count[THREE] > 1: 209 | oscore += 2000 210 | elif opponent_count[THREE] > 0: 211 | oscore += 400 212 | 213 | if mine_count[STHREE] > 0: 214 | mscore += mine_count[STHREE] * 10 215 | if opponent_count[STHREE] > 0: 216 | oscore += opponent_count[STHREE] * 10 217 | 218 | if mine_count[TWO] > 0: 219 | mscore += mine_count[TWO] * 6 220 | if opponent_count[TWO] > 0: 221 | oscore += opponent_count[TWO] * 6 222 | 223 | if mine_count[STWO] > 0: 224 | mscore += mine_count[STWO] * 2 225 | if opponent_count[STWO] > 0: 226 | oscore += opponent_count[STWO] * 2 227 | 228 | return (mscore, oscore) 229 | 230 | def evaluate(self, turn, checkWin=False): 231 | self.reset() 232 | 233 | if turn == WHITE_CHESSMAN.Value: 234 | mine = 2 235 | opponent = 1 236 | else: 237 | mine = 1 238 | opponent = 2 239 | 240 | for y in range(self.len): 241 | for x in range(self.len): 242 | if self.board[y][x] == mine: 243 | self.evaluatePoint(x, y, mine, opponent) 244 | elif self.board[y][x] == opponent: 245 | self.evaluatePoint(x, y, opponent, mine) 246 | 247 | mine_count = self.count[mine - 1] 248 | opponent_count = self.count[opponent - 1] 249 | if checkWin: 250 | return mine_count[FIVE] > 0 251 | else: 252 | mscore, oscore = self.getScore(mine_count, opponent_count) 253 | return (mscore - oscore) 254 | 255 | def evaluatePoint(self, x, y, mine, opponent, count=None): 256 | dir_offset = [(1, 0), (0, 1), (1, 1), (1, -1)] # direction from left to right 257 | ignore_record = True 258 | if count is None: 259 | count = self.count[mine - 1] 260 | ignore_record = False 261 | for i in range(4): 262 | if self.record[y][x][i] == 0 or ignore_record: 263 | self.analysisLine(x, y, i, dir_offset[i], mine, opponent, count) 264 | 265 | # line is fixed len 9: XXXXMXXXX 266 | def getLine(self, x, y, dir_offset, mine, opponent): 267 | line = [0 for i in range(9)] 268 | 269 | tmp_x = x + (-5 * dir_offset[0]) 270 | tmp_y = y + (-5 * dir_offset[1]) 271 | for i in range(9): 272 | tmp_x += dir_offset[0] 273 | tmp_y += dir_offset[1] 274 | if (tmp_x < 0 or tmp_x >= self.len or 275 | tmp_y < 0 or tmp_y >= self.len): 276 | line[i] = opponent # set out of range as opponent chess 277 | else: 278 | line[i] = self.board[tmp_y][tmp_x] 279 | 280 | return line 281 | 282 | def analysisLine(self, x, y, dir_index, dir, mine, opponent, count): 283 | # record line range[left, right] as analysized 284 | def setRecord(self, x, y, left, right, dir_index, dir_offset): 285 | tmp_x = x + (-5 + left) * dir_offset[0] 286 | tmp_y = y + (-5 + left) * dir_offset[1] 287 | for i in range(left, right + 1): 288 | tmp_x += dir_offset[0] 289 | tmp_y += dir_offset[1] 290 | self.record[tmp_y][tmp_x][dir_index] = 1 291 | 292 | empty = 0 293 | left_idx, right_idx = 4, 4 294 | 295 | line = self.getLine( x, y, dir, mine, opponent) 296 | 297 | while right_idx < 8: 298 | if line[right_idx + 1] != mine: 299 | break 300 | right_idx += 1 301 | while left_idx > 0: 302 | if line[left_idx - 1] != mine: 303 | break 304 | left_idx -= 1 305 | 306 | left_range, right_range = left_idx, right_idx 307 | while right_range < 8: 308 | if line[right_range + 1] == opponent: 309 | break 310 | right_range += 1 311 | while left_range > 0: 312 | if line[left_range - 1] == opponent: 313 | break 314 | left_range -= 1 315 | 316 | chess_range = right_range - left_range + 1 317 | if chess_range < 5: 318 | setRecord(self, x, y, left_range, right_range, dir_index, dir) 319 | return CHESS_TYPE.NONE 320 | 321 | setRecord(self, x, y, left_idx, right_idx, dir_index, dir) 322 | 323 | m_range = right_idx - left_idx + 1 324 | 325 | # M:mine chess, P:opponent chess or out of range, X: empty 326 | if m_range >= 5: 327 | count[FIVE] += 1 328 | 329 | # Live Four : XMMMMX 330 | # Chong Four : XMMMMP, PMMMMX 331 | if m_range == 4: 332 | left_empty = right_empty = False 333 | if line[left_idx - 1] == empty: 334 | left_empty = True 335 | if line[right_idx + 1] == empty: 336 | right_empty = True 337 | if left_empty and right_empty: 338 | count[FOUR] += 1 339 | elif left_empty or right_empty: 340 | count[SFOUR] += 1 341 | 342 | # Chong Four : MXMMM, MMMXM, the two types can both exist 343 | # Live Three : XMMMXX, XXMMMX 344 | # Sleep Three : PMMMX, XMMMP, PXMMMXP 345 | if m_range == 3: 346 | left_empty = right_empty = False 347 | left_four = right_four = False 348 | if line[left_idx - 1] == empty: 349 | if line[left_idx - 2] == mine: # MXMMM 350 | setRecord(self, x, y, left_idx - 2, left_idx - 1, dir_index, dir) 351 | count[SFOUR] += 1 352 | left_four = True 353 | left_empty = True 354 | 355 | if line[right_idx + 1] == empty: 356 | if line[right_idx + 2] == mine: # MMMXM 357 | setRecord(self, x, y, right_idx + 1, right_idx + 2, dir_index, dir) 358 | count[SFOUR] += 1 359 | right_four = True 360 | right_empty = True 361 | 362 | if left_four or right_four: 363 | pass 364 | elif left_empty and right_empty: 365 | if chess_range > 5: # XMMMXX, XXMMMX 366 | count[THREE] += 1 367 | else: # PXMMMXP 368 | count[STHREE] += 1 369 | elif left_empty or right_empty: # PMMMX, XMMMP 370 | count[STHREE] += 1 371 | 372 | # Chong Four: MMXMM, only check right direction 373 | # Live Three: XMXMMX, XMMXMX the two types can both exist 374 | # Sleep Three: PMXMMX, XMXMMP, PMMXMX, XMMXMP 375 | # Live Two: XMMX 376 | # Sleep Two: PMMX, XMMP 377 | if m_range == 2: 378 | left_empty = right_empty = False 379 | left_three = right_three = False 380 | if line[left_idx - 1] == empty: 381 | if line[left_idx - 2] == mine: 382 | setRecord(self, x, y, left_idx - 2, left_idx - 1, dir_index, dir) 383 | if line[left_idx - 3] == empty: 384 | if line[right_idx + 1] == empty: # XMXMMX 385 | count[THREE] += 1 386 | else: # XMXMMP 387 | count[STHREE] += 1 388 | left_three = True 389 | elif line[left_idx - 3] == opponent: # PMXMMX 390 | if line[right_idx + 1] == empty: 391 | count[STHREE] += 1 392 | left_three = True 393 | 394 | left_empty = True 395 | 396 | if line[right_idx + 1] == empty: 397 | if line[right_idx + 2] == mine: 398 | if line[right_idx + 3] == mine: # MMXMM 399 | setRecord(self, x, y, right_idx + 1, right_idx + 2, dir_index, dir) 400 | count[SFOUR] += 1 401 | right_three = True 402 | elif line[right_idx + 3] == empty: 403 | # setRecord(self, x, y, right_idx+1, right_idx+2, dir_index, dir) 404 | if left_empty: # XMMXMX 405 | count[THREE] += 1 406 | else: # PMMXMX 407 | count[STHREE] += 1 408 | right_three = True 409 | elif left_empty: # XMMXMP 410 | count[STHREE] += 1 411 | right_three = True 412 | 413 | right_empty = True 414 | 415 | if left_three or right_three: 416 | pass 417 | elif left_empty and right_empty: # XMMX 418 | count[TWO] += 1 419 | elif left_empty or right_empty: # PMMX, XMMP 420 | count[STWO] += 1 421 | 422 | # Live Two: XMXMX, XMXXMX only check right direction 423 | # Sleep Two: PMXMX, XMXMP 424 | if m_range == 1: 425 | left_empty = right_empty = False 426 | if line[left_idx - 1] == empty: 427 | if line[left_idx - 2] == mine: 428 | if line[left_idx - 3] == empty: 429 | if line[right_idx + 1] == opponent: # XMXMP 430 | count[STWO] += 1 431 | left_empty = True 432 | 433 | if line[right_idx + 1] == empty: 434 | if line[right_idx + 2] == mine: 435 | if line[right_idx + 3] == empty: 436 | if left_empty: # XMXMX 437 | # setRecord(self, x, y, left_idx, right_idx+2, dir_index, dir) 438 | count[TWO] += 1 439 | else: # PMXMX 440 | count[STWO] += 1 441 | elif line[right_idx + 2] == empty: 442 | if line[right_idx + 3] == mine and line[right_idx + 4] == empty: # XMXXMX 443 | count[TWO] += 1 444 | 445 | return CHESS_TYPE.NONE 446 | --------------------------------------------------------------------------------