本帖最后由 云天 于 2022-12-2 13:45 编辑
【项目背景】
我的老家在东北,出生在80年代,小时候闲暇之余也没有现代生活中这样丰富多彩的娱乐活动,娱乐方式的缺乏导致了“憋死牛”、“五子棋”、“玻璃弹珠”等一批对物质条件要求很低,而又随时随地可以进行的简易游戏。然而,随着社会生产力的不断进步、人们生活节奏的不断加快,“憋死牛”等“古老”的游戏逐渐开始不能满足人们对娱乐活动的感官要求,随着时间的推移,这些产生于过去的游戏将会慢慢淡出历史舞台。
今天我将用行空板将“憋死牛”游戏复活,并实现人与机器对战。
【憋死牛】
憋死牛又名“老虎吃食”,是中国民间棋类游戏,流行于东北、华北等地。憋死牛”的别称极多,诸如“憋死猫”“裤档棋”“剪子棋”“区字棋”“冈字棋”“堵茅坑”“茅坑棋”“走井”“跳枯井棋”“老虎吃食”“瞎子跳井”“蛤蟆跳井”“走牛脚塞”等。
民间棋类游戏是游戏的一大分支,既有趣又能锻炼孩子的思维能力。它在给幼儿带来快乐、丰富幼儿游戏生活的同时能促进幼儿身体、认知、社会性、良好个性及意志品质等的发展。
先在地上画一个大大的“区”字作为棋盘,再在“区”字右侧的两个角之间画一个圆圈作为“井”,这眼“井”在后面的走棋过程中是不可以逾越的。对弈双方各执两枚棋子,棋子一般都是就地取材。你用两片贝壳,我就用两块瓦片;你用两片树叶,我就用两粒石子,总之是有所区别就行了。每人所执的那两枚棋子就是所谓的“牛”。
【游戏规则】
1.剪刀石头布规定谁赢了谁先走; 2.每次每人只走一步,轮流走棋; 3.每次只可移动自己的其中一个棋子; 4.每个点位只允许存在一个棋子; 5.有“井”的那条路不能走; 5.一方把另一方的两头牛都“憋”死不能移动,就赢了; 6.开局第一步,不能将对方“憋死”。 棋规儿歌:棋盘两座山,红蓝上下站。沿线一步空位走,憋住对方是好汉。 【制作按钮】
受“带LED灯的数字按钮”的启发,制作一个LED灯加按钮,实现按下按钮灯亮灯熄,且可独立用程序控制灯的颜色及亮灭。
1、灯与按钮位置关系
灯在上,按钮在下,用热熔胶粘在一起。
2、制作半透明罩,方便按压。
3、使用micro:bit主板测试按钮
【硬件连接】
LED灯串接在一起形成灯带,接扩展板引脚P0,5个按钮分别接引脚P12,P13,P14,P15,P16。
【制作外壳】
【美化棋盘】
标识棋子位置、“井”及棋路。
【安装摄像头】 摄像头用于游戏开始第一步,“剪刀石头布”定谁赢了谁先走。
【程序编写】 1、棋盘初始化
列表“位置状态”,用于标记棋盘相应棋子位置现在是“红棋子”还是“蓝棋子”。
2、落红棋子
如果相应按钮被按下,通过以下程序“状态判断”,决定“红棋子”落下状态。
3、红棋子“状态判断”
先熄灭一个红棋子,才能走”空位“,让空位处亮灯(红棋子)。第一步不能将对方”憋死“。
4、落蓝棋子
如第一步蓝棋先手,不能将红棋一步”憋死“,棋路固定。之后等红棋子落下后,开始自动落蓝棋子,其中一个重要规则是:不能将自己的两个棋子横向摆放!所以机器方(蓝棋)从来不会输。
5、判胜负
因机器方(蓝棋)从来不会输,所以只需判定红方的”输状态“即可。蓝方胜,闪烁。
蓝棋“憋死”红棋
屏幕显示“蓝方胜”,棋盘灯闪烁。
6、演示视频
手动设置红方先手
7、识别“剪刀石头布”
开局,玩家(红棋)与机器方(蓝棋)通过”剪刀石头布”,决定谁先走第一步。
识别“剪刀石头布”是通过Google Teachable Machine,Google Teachable Machine是Google免费的无代码深度学习模型创建网络平台。使用该平台你可以构建模型来对图像,音频甚至姿势进行分类。完成上述操作后,你可以下载经过训练的模型并将其用于你的应用程序。你可以使用Tensorflow或PyTorch之类的框架来构建自定义的卷积神经网络,或者如果你想要一种简单的无代码方式进行此操作,则可以使用 Google Teachable Machine(https://teachablemachine.withgoogle.com/)平台为你完成相同的操作。
8、国内可通过英荔 AI 训练平台: https://train.aimaker.space/train/image 训练过程比较简单,不再过多介绍。 采集“剪刀石头布”图像。 训练模型 下载模型,并将模型文件“keras_model.h5”,放到行空板程序所在目录下。 利用棋盘上的灯,显示机器的“剪刀石头布”。 初始化 导入相应库,驱动摄像头,加载模型。 9、主程序 10、测试
机器胜
机器方(蓝棋)先手。 【演示视频】 “剪刀石头布”开局演示 【制作反思】 1、程序采用图形化,不够简洁 2、内部逻辑有待完善,如禁止红方困住的棋子跳出。 【游戏目的】 1、“憋死牛”游戏规则简单,集合了知识性、趣味性、竞技性的特点,在游戏中可以培养幼儿独立思考的能力,锻炼思维,启迪智慧,能让小朋友们乐在“棋”中,感受到“棋”乐无穷的游戏乐趣! 2、通过憋死牛游戏发展幼儿做事情的耐性,让孩子从小养成细心的习惯,逐步培养孩子找规律和推理的意识。 【游戏规律】 只要你不让自己的两头“牛”同时走到“区”字上下两条横线的两个端点上,那对方就永远拿你没办法。明白了这个诀窍之后,我的“牛”便再也没有被“憋死”过。
【Python源代码】
-
-
- # -*- coding: UTF-8 -*-
-
- # MindPlus
- # Python
- from pinpong.extension.unihiker import *
- from keras.preprocessing import image
- from pinpong.board import Board,Pin
- from pinpong.board import NeoPixel
- import tensorflow.keras
- import tensorflow as tf
- from unihiker import GUI
- from time import sleep
- import numpy as np
- import random
- import time
-
- # 自定义函数
- def QiPanChuShiHua():
- global WeiZhiZhuangTai,ZhuangTaiBiaoShi,np1,XuHao
- global p_p12_in,p_p13_in,p_p14_in,p_p15_in,p_p16_in
- global HongZi,LuoHongZiWanCheng,DiYiBu
- global ShangGeHongZiWeiZhi,KongZiWeiZhi, QianLiLuoZiWeiZhi
- WeiZhiZhuangTai = [2, 2, 1,1,0]
- ZhuangTaiBiaoShi = [0, 0,0,0,0]
- global 显示
- np1[0] = (255,0,0)
- np1[1] = (255,0,0)
- np1[2] = (0,0,255)
- np1[3] = (0,0,255)
- np1[4] = (0,0,0)
- XuHao = 0
- HongZi = 2
- LuoHongZiWanCheng = 0
- QianLiLuoZiWeiZhi = -1
- KongZiWeiZhi = 4
- 显示.config(text="憋死牛")
- time.sleep(5)
- def LuoLanZi():
- global QianLiLuoZiWeiZhi,LuoHongZiWanCheng,KongZiWeiZhi
- global DiYiBu
- if (DiYiBu == 2):
- DiYiBu = 0
- np1[2] = (0,0,0)
- np1[4] = (0,0,255)
- WeiZhiZhuangTai[2]=0
- WeiZhiZhuangTai[4]=1
- else:
- if (LuoHongZiWanCheng == 1):
- QianLiLuoZiWeiZhi = -1
- LuoHongZiWanCheng = 0
- if (KongZiWeiZhi == 4):
- if ((WeiZhiZhuangTai[3]) == 1):
- np1[3] = (0,0,0)
- np1[4] = (0,0,255)
- WeiZhiZhuangTai[3]=0
- WeiZhiZhuangTai[4]=1
- elif ((WeiZhiZhuangTai[0]) == 1):
- np1[0] = (0,0,0)
- np1[4] = (0,0,255)
- WeiZhiZhuangTai[0]=0
- WeiZhiZhuangTai[4]=1
- elif ((WeiZhiZhuangTai[2]) == 1):
- np1[2] = (0,0,0)
- np1[4] = (0,0,255)
- WeiZhiZhuangTai[2]=0
- WeiZhiZhuangTai[4]=1
- elif ((WeiZhiZhuangTai[1]) == 1):
- np1[1] = (0,0,0)
- np1[4] = (0,0,255)
- WeiZhiZhuangTai[1]=0
- WeiZhiZhuangTai[4]=1
- elif (KongZiWeiZhi == 3):
- if ((WeiZhiZhuangTai[2]) == 1):
- np1[2] = (0,0,0)
- np1[3] = (0,0,255)
- WeiZhiZhuangTai[2]=0
- WeiZhiZhuangTai[3]=1
- elif ((WeiZhiZhuangTai[4]) == 1):
- np1[4] = (0,0,0)
- np1[3] = (0,0,255)
- WeiZhiZhuangTai[4]=0
- WeiZhiZhuangTai[3]=1
- elif (KongZiWeiZhi == 2):
- if ((WeiZhiZhuangTai[3]) == 1):
- np1[3] = (0,0,0)
- np1[2] = (0,0,255)
- WeiZhiZhuangTai[3]=0
- WeiZhiZhuangTai[2]=1
- elif ((WeiZhiZhuangTai[1]) == 1):
- np1[1] = (0,0,0)
- np1[2] = (0,0,255)
- WeiZhiZhuangTai[1]=0
- WeiZhiZhuangTai[2]=1
- elif ((WeiZhiZhuangTai[4]) == 1):
- np1[4] = (0,0,0)
- np1[2] = (0,0,255)
- WeiZhiZhuangTai[4]=0
- WeiZhiZhuangTai[2]=1
- elif (KongZiWeiZhi == 1):
- if ((WeiZhiZhuangTai[0]) == 1):
- np1[0] = (0,0,0)
- np1[1] = (0,0,255)
- WeiZhiZhuangTai[0]=0
- WeiZhiZhuangTai[1]=1
- elif ((WeiZhiZhuangTai[2]) == 1):
- np1[2] = (0,0,0)
- np1[1] = (0,0,255)
- WeiZhiZhuangTai[2]=0
- WeiZhiZhuangTai[1]=1
- elif ((WeiZhiZhuangTai[4]) == 1):
- np1[4] = (0,0,0)
- np1[1] = (0,0,255)
- WeiZhiZhuangTai[4]=0
- WeiZhiZhuangTai[1]=1
- elif (KongZiWeiZhi == 0):
- if ((WeiZhiZhuangTai[1]) == 1):
- np1[1] = (0,0,0)
- np1[0] = (0,0,255)
- WeiZhiZhuangTai[1]=0
- WeiZhiZhuangTai[0]=1
- elif ((WeiZhiZhuangTai[4]) == 1):
- np1[4] = (0,0,0)
- np1[0] = (0,0,255)
- WeiZhiZhuangTai[4]=0
- WeiZhiZhuangTai[0]=1
- def ZhuangTaiPanDuan():
- global XuHao,HongZi,LuoHongZiWanCheng,DiYiBu
- global QianLiLuoZiWeiZhi,KongZiWeiZhi
- if ((ZhuangTaiBiaoShi[XuHao]) == 0):
- ZhuangTaiBiaoShi[XuHao]=1
- if ((WeiZhiZhuangTai[XuHao]) == 0):
- if (HongZi == 1):
- if (not (QianLiLuoZiWeiZhi == XuHao)):
- QianLiLuoZiWeiZhi = XuHao
- np1[XuHao] = (255,0,0)
- WeiZhiZhuangTai[XuHao]=2
- HongZi = 2
- LuoHongZiWanCheng = 1
- elif ((WeiZhiZhuangTai[XuHao]) == 2):
- if (HongZi == 2):
- if (DiYiBu == 1):
- if (XuHao == 1):
- DiYiBu = 0
- np1[XuHao] = (0,0,0)
- WeiZhiZhuangTai[XuHao]=0
- HongZi = 1
- QianLiLuoZiWeiZhi = XuHao
- KongZiWeiZhi = XuHao
- else:
- if (not (QianLiLuoZiWeiZhi == XuHao)):
- QianLiLuoZiWeiZhi = XuHao
- np1[XuHao] = (0,0,0)
- WeiZhiZhuangTai[XuHao]=0
- HongZi = 1
- KongZiWeiZhi = XuHao
- def HuiFuDeng():
- np1[0] = (0,0,0)
- np1[1] = (0,0,0)
- np1[2] = (0,0,0)
- np1[3] = (0,0,0)
- np1[4] = (0,0,0)
- def ShanShuo():
- time.sleep(3)
- while not ((button_a.is_pressed()==True)):
- np1[0] = (0,0,255)
- np1[1] = (0,0,255)
- np1[2] = (0,0,255)
- np1[3] = (0,0,255)
- np1[4] = (0,0,255)
- time.sleep(0.1)
- np1[0] = (0,0,0)
- np1[1] = (0,0,0)
- np1[2] = (0,0,0)
- np1[3] = (0,0,0)
- np1[4] = (0,0,0)
- time.sleep(0.1)
- QiPanChuShiHua()
- def PanShengFu():
- global 显示
- global KongZiWeiZhi
- WeiZhi0ZhuangTai = ((WeiZhiZhuangTai[0]) == 2)
- WeiZhi1ZhuangTai = ((WeiZhiZhuangTai[1]) == 2)
- WeiZhi2ZhuangTai = ((WeiZhiZhuangTai[2]) == 2)
- WeiZhi3ZhuangTai = ((WeiZhiZhuangTai[3]) == 2)
- WeiZhi4ZhuangTai = ((WeiZhiZhuangTai[4]) == 1)
- if ((WeiZhi0ZhuangTai == 1) and ((WeiZhi1ZhuangTai == 1) and (WeiZhi4ZhuangTai == 1))):
- if (KongZiWeiZhi == 3):
- 显示.config(text="蓝方胜")
- ShanShuo()
- elif ((WeiZhi2ZhuangTai == 1) and ((WeiZhi3ZhuangTai == 1) and (WeiZhi4ZhuangTai == 1))):
- if (KongZiWeiZhi == 0):
- 显示.config(text="蓝方胜")
- ShanShuo()
- def ShiTou():
- np1[0] = (0,0,0)
- np1[1] = (0,0,0)
- np1[2] = (0,0,0)
- np1[3] = (0,0,0)
- np1[4] = (255,255,0)
- def JianDao():
- np1[0] = (255,255,0)
- np1[1] = (255,255,0)
- np1[2] = (0,0,0)
- np1[3] = (0,0,0)
- np1[4] = (255,255,0)
- def Bu():
- np1[0] = (255,255,0)
- np1[1] = (255,255,0)
- np1[2] = (255,255,0)
- np1[3] = (255,255,0)
- np1[4] = (255,255,0)
- def LuoHongZi():
- global XuHao
- XuHao = 0
- if (p_p12_in.read_digital()==True):
- ZhuangTaiPanDuan()
- else:
- ZhuangTaiBiaoShi[XuHao]=0
- XuHao = 1
- if (p_p13_in.read_digital()==True):
- ZhuangTaiPanDuan()
- else:
- ZhuangTaiBiaoShi[XuHao]=0
- XuHao = 2
- if (p_p14_in.read_digital()==True):
- ZhuangTaiPanDuan()
- else:
- ZhuangTaiBiaoShi[XuHao]=0
- XuHao = 3
- if (p_p15_in.read_digital()==True):
- ZhuangTaiPanDuan()
- else:
- ZhuangTaiBiaoShi[XuHao]=0
- XuHao = 4
- if (p_p16_in.read_digital()==True):
- ZhuangTaiPanDuan()
- else:
- ZhuangTaiBiaoShi[XuHao]=0
-
-
- Board().begin()
- u_gui=GUI()
- import cv2
- p_p12_in=Pin(Pin.P12, Pin.IN)
- p_p13_in=Pin(Pin.P13, Pin.IN)
- p_p14_in=Pin(Pin.P14, Pin.IN)
- p_p15_in=Pin(Pin.P15, Pin.IN)
- p_p16_in=Pin(Pin.P16, Pin.IN)
- cap = cv2.VideoCapture()
- cap.open(0)
- cap.set(cv2.CAP_PROP_FPS, 1)#帧数
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) #设置摄像头图像宽度
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) #设置摄像头图像高度
- cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) #设置OpenCV内部的图像缓存,可以极大提高图像的实时性。
- cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
- model = tensorflow.keras.models.load_model('keras_model.h5')
- labels = ['Rock','scissors','paper','background']
- font = cv2.FONT_HERSHEY_SIMPLEX
- success = True
- image = 0
- cv2.namedWindow('Frame',cv2.WND_PROP_FULLSCREEN) #窗口全屏
- cv2.setWindowProperty('Frame', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) #窗口全屏
- pin1=Pin(Pin.P0, Pin.OUT)
- np1 = NeoPixel(pin1,5)
- Bu()
- time.sleep(3)
- HuiFuDeng()
- while not (False):
- success, image = cap.read()
- if (success == False):
- break
- image = cv2.flip(image,1)
- img = cv2.resize(image,(224,224))
- image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE) #旋转屏幕
- img = np.array(img,dtype=np.float32)
- img = np.expand_dims(img,axis=0)
- img = (img / 255)
- prediction = model.predict(img)
- predicted_class = labels[np.argmax(prediction)]
- SuiJiShu = (random.randint(1, 3))
- print(predicted_class)
- if (predicted_class == "Rock"):
- if (SuiJiShu == 1):
- ShiTou()
- win = "Draw"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- for index in range(5):
- buzzer.pitch(131,4)
- elif (SuiJiShu == 2):
- JianDao()
- win = "Red Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 1
- time.sleep(5)
- break
- else:
- Bu()
- win = "Blue Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 2
- time.sleep(5)
- break
- if (predicted_class == "paper"):
- if (SuiJiShu == 1):
- ShiTou()
- win = "Blue Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 2
- time.sleep(5)
- break
- elif (SuiJiShu == 2):
- JianDao()
- win = "Draw"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- for index in range(5):
- buzzer.pitch(131,4)
- else:
- Bu()
- win = "Red Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 1
- time.sleep(5)
- break
- if (predicted_class == "scissors"):
- if (SuiJiShu == 1):
- ShiTou()
- win = "Red Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 1
- time.sleep(5)
- break
- elif (SuiJiShu == 2):
- JianDao()
- win = "Blue Win"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- DiYiBu = 2
- time.sleep(5)
- break
- else:
- Bu()
- win = "Draw"
- cv2.putText(image, win, (20,130), font, 2, (0,255,0), 3)
- cv2.imshow("Frame", image)
- for index in range(5):
- buzzer.pitch(131,4)
- cv2.imshow("Frame", image)
- if cv2.waitKey(1) & 0xff== 113:
- break
- cap.release()
- cv2.destroyAllWindows()
- 显示=u_gui.draw_text(text="憋死牛",x=10,y=130,font_size=50, color="#0000FF")
- QiPanChuShiHua()
-
- while True:
- LuoHongZi()
- PanShengFu()
- LuoLanZi()
-
复制代码
|