目录
前言
2024电赛结束,获得了省级二等奖。大部分的问题都已经解决,但由于是最后一年,早上八点开工,晚上10点结束。并没有留出过多时间,导致最后一问以及第三问没能完美解决,该题目最佳解决方案仍为使用视觉解决,由于之前未学习openmv识别,因此采用了光电传感来解决本题,本文章会对比赛中的实现方案以及三子棋下法的算法设计进行详细讲述。
-------本方案简述方法为目标性解法,实际解法在制作中发生了很多不同的问题,最终才确定并制作了如下的实现。
一,题目简述
1,任务
设计并制作三子棋游戏装置,能够控制机械臂或其他机构放置棋子,实现人机对弈。棋盘由黑色实线围成9 个方格,人、机分别从棋子放置处拾取棋子并放置到方格中,先将己方的3个棋 子连成一线(横连、竖连、斜连皆可)即获胜。
2, 要求
(1)装置能将任意1颗黑棋子放置到5号方格中。(5分)
(2)装置能将任意 2 颗黑棋子和 2 颗白棋子依次放置到指定方格中。(20 分)
(3)将棋盘绕中心±45°范围内旋转后,装置能将任意2颗黑棋子和2颗 白棋子依次放置到指定方格中。(20分)
(4)装置执黑棋先行与人对弈(第1步方格可设置),若人应对的第1步白 棋有错误,装置能获胜。(20分)
(5)人执黑棋先行,装置能正确放置白棋子以保持不输棋。(20分)
(6)对弈过程中,若人将装置下过的1颗棋子变动位置,装置能自动发现 并将该棋子放置回原来位置。(10分)
(7)其他。(5分)
(8)设计报告。(20分)
3, 说明
(1)三子棋棋盘和棋子在测评时由选手自带。棋盘尺寸如图1所标,其背 景颜色由选手自定;棋子直径约22±2mm,材质由选手自定。图1中的蓝色标 注及虚线等,实物中不出现。黑、白棋子在放置处各摆成1列,棋子间距不限。
(2)装置放置棋子的过程中,不可触压黑实线;放置后不可脱离方格区域; 放置一颗棋子的时间不大于15s。否则扣分。
(3)要求(2)( 3)中,装置可设置黑棋子和白棋子被放置的方格号。
(4)要求(4)( 5)中,人下完1步棋后,通过按动装置上的某唯一指定按 钮通知装置,同时启动计时;装置下完1步棋后,通过亮灯指示,计时停止。
(5)要求(6)中,在人下棋期间,并不下新子,而是将装置下过的1颗棋 子变动位置;轮到装置下时,装置能将被变动的棋子放置回原来位置,时间不大 于15s。
(6)装置应能适应正常室内照明环境,测试时不得有特殊照明条件要求。
二,效果展示
系统搭建与实现在电赛文章中都有写,本文重点介绍比赛的心路历程与过程电赛文章
全国大学生电子竞赛E题三字游戏(非视觉)效果展示电赛文章
三,题目分析
根据题目要求分析,题目立案应旨在使用视觉解决该题目。题目使用标准三子棋玩法,并且需使用机械移动黑或白棋进行放置至棋盘内部任意位置。需要注意的是,根据说明第(2)条可知,放置装置必须托举起棋子以避免触碰黑线。同时也可避免触碰已放置棋子。根据题目要求,需要能控制装置放置至可选择的位置,同时还需能进入正常对弈状态并能获胜/保平。
初步对题目判断,我们需要制作的是:一个可以托举棋子并可以进行位置移动的机械设备;一个嵌入了对弈算法与调试模式(可自我决定将棋子放置在哪个位置)的逻辑控制单元;同时由于对弈需求,我们还需一个能传回棋盘数据的传感器。同时我们还需知道棋子预摆放与取得数量,防止取“空气”的现象发生。同时也应能区分敌我放置的棋子进行不同标注。
对于系统的操作方式,还需要制作一个多级菜单来满足不同问的不同需求,同时也能方便对系统进行调试分析。
四,解决方案
1,移动棋子
对于托举棋子可使用方案为:机械臂;龙门架等。
其中机械臂对指向位置(机械臂定位)有较强难度,需要对各个坐标的定位以及机械臂伸展程度进行测定并得出相关公式才能进行精准化的定位与抓取。龙门架可以通过对步进电机的精细操作并计步以达到实现将抓取设备精准定位至所需位置的需求。
抓取方式可以选择的方式有,传统机械爪,气泵负压抓取,还有磁力。使用传统机械爪有很大的概率会使抓取位附件的棋子受到干扰,气泵式的对于棋子的平整度有较大需求,而磁力可以更加精准的抓取所需取用的棋子,占用空间小,对周围棋子的干扰都较少。
2,定位棋子
定位棋子可使用光电对棋盘上的棋子位置进行监测并传回核心处理器从而对棋盘棋子位置进行处理识别。通过算法区分便可对敌我进行识别。
同时也可使用例如对特殊材质(同使用特殊材质棋子)进行检测以确定棋子位置。列如带电感线圈与磁性材质的材料都可以使传感器进行检测。由于在抓取棋子方面选定了使用铁磁材质的棋子,而题目对于棋盘材质并无具体要求,因此最终决定使用最简单的光电传感器来对棋子位置进行评定,同时由于放置棋子为自主放置,设备可对放置位置进行记录,因此可以做到分辨棋子的敌友关系。
3,核心算法
整个设备基础在于多级菜单与棋子的定位以及放置位置的寻找,在完成基础功能后就是对棋局的算法实现,对于三子棋先手与后手在题目要求就可以看出,先手具有绝对优势,在后手的情况下最好的结果便是平局,也就是对棋局的防守要做到完善。在先手的情况下,也得进行防守,但在人下错一步后也得有取胜的动作,也就是要对棋局的是否能够获胜进行判断。
五,系统实现
系统实现中在算法实现中不对基础的IO调用,程序菜单以及基础采集进行讲述,将着重对三子棋的下棋算法以及如何实现系统定位进行详细讲述。
龙门架定位以及移动算法
龙门架使用的电机为42系列步进电机作为驱动电机,移动使用皮带传动以保证精确度。实物图片如下:
根据42系列步进电机相关资料,使用L298NH桥启动板对该步进电机进行单片机编程从而实现手动驱动。可以实现对步进电机的步数精确化控制。(步进电机控制代码与步进电机说明图如下)
void all_stop()
{
digitalWrite(9,LOW);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,LOW);
digitalWrite(5,LOW);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,LOW);
delay(2);
}
void down_for()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
}
}
void down_back()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
}
}
void up_for()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
}
}
void up_back()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
}
通过手动控制步数以达到可以单位进行移动,可为系统的定位(坐标)进行计算与移动,从而达到精确位置。进行详细调控后得到坐标如下
int white_1[]={28,14};
int white_2[]={29,19};
int white_3[]={29,24};
int white_4[]={29,29};
int white_5[]={29,34};
int black_1[]={4,14};
int black_2[]={4,19};
int black_3[]={4,24};
int black_4[]={4,29};
int black_5[]={4,34};
int base_loc[]={0,0};
int loc[]={0,0};
int p1[]={20,3};
int p2[]={21,7};
int p3[]={21,12};
int p4[]={16,3};
int p5[]={16,8};
int p6[]={16,11};
int p7[]={11,3};
int p8[]={11,8};
int p9[]={12,12};
通过坐标定位棋盘位置P ,白棋放置位置white ,黑棋放置位置black 。可以做到操作机械臂前进至任意所需前往的位置。*(取用白棋 \ 取用黑棋 | 棋盘各位置)
拾取棋子使用特殊棋子材料(铁磁材料),使用电磁铁对棋子进行失去与放置,由于棋子拾取后移动可能会导致碰触其他棋子,因此还架设了升降机构以抬升拾取棋子高度来避免受到大幅度干扰。
三子棋下棋算法
以整个龙门架的起始点为原点,以龙门架的前后,左右行程为坐标标轴建立极坐标系,找出棋盘各个位置的极坐标值,使用角度传感器检测棋盘转动的 角度,将其转化弧度制,依据转动前的棋盘坐标与棋盘转动的角度,通过公式即可算出旋转后的极坐标值,将其转换为直角坐标,即可规划旋转后的每个棋盘位置的行棋路径。
三子棋赢棋算法原理主要基于检测棋盘上所有的可能赢棋的线路,判断是否有玩家达成了三个连续棋子的排列。首先由红外寻迹模块检测每个位置的落子状态,其次是实现赢棋的条件。具体可分为两种情况,为先手时和为后手时。后手时:若对方首先落子棋盘中间位置时,则落子棋盘的四角位置中的任意 位置。若对方不落子棋盘中间位置时,则第一步抢占中间位置,则可保证不输 棋。之后通过检测棋盘位置的状态,若有对手落子,则该格的权值记为1,若有己方落子,则权值记为3,通过计算各条线上的权值,当某一条线的权值为2 时,则落子该条线的空位进行截堵,可保证不输棋。 先手时:保证能够不输棋,则第一步落子棋盘中间位置,若对方第一步落子 棋盘四个角位置的任意位置,则第二步落子在以棋盘中间位置对称的位置,进入防守模式;若对方第一步落子棋盘中间位置的上下左右四个位置中的任意无子位置,则落子与之相邻的两个任意一无子位置,进入进攻模式。若进入防守模式,则通过检测棋盘位置的状态,若有对手落子,则该位置的权值记为 1,若有己方落子,则权值记为3,通过计算各条线上的权值,当某一条线的权 值为2时,则落子该条线的空位进行截堵,可保证不输棋;若进入进攻模式, 则第三步落子第二步棋子的相邻位置,之后通过检测棋盘位置的状态,若有对 手落子,则该格的权值记为1,若有己方落子,则权值记为3,通过计算各条线 上的权值,当某一条线的权值为6时,则落子该条线的空位,则可赢棋。棋盘棋子位置改变检测算法 使用红外循迹模块检测棋盘所有位置,若棋盘上有对方落子,则将该位置 的权值记为1;若有己方落子,则将该位置的权值记为3。将所有位置的权值相加,若前后时刻棋盘所有位置的权值总和不变,则对比前后两个时刻棋盘所有 位置的状态若有变化,则是移动的棋子,系统将根据前后时刻发生变化的坐 标值进行计算并规划出行子路径,并控制龙门架将改变的棋子移回原位。
判断算法如下 |
int win_scan()//胜利判断 胜利返回1 不胜利返回0
{
int sum1=0;
for(int u=1;u<=3;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=4;u<=6;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=7;u<=9;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
//=====================================
for(int u=1;u<=7;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=2;u<=8;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=3;u<=9;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
//==============================================
for(int u=1;u<=9;u=u+4)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=3;u<=7;u=u+2)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
return 0;
}
int danger_scan()//返回危险位置,或0
{
// cheat();
int lll=10;
int sum=0;
for(int u=1;u<=3;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u2=1;u2<=3;u2++) if(win_num[u2]==0) lll = u2; return lll; }
if(sum==2){ for(int u2=1;u2<=3;u2++) if(win_num[u2]==0) lll = u2; return lll; }
sum=0;
for(int u=4;u<=6;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=4;u<=6;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=4;u<=6;u++) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=7;u<=9;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
sum=0;
//=====================================
for(int u=1;u<=7;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=1;u<=7;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=2;u<=8;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=2;u<=8;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=3;u<=9;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=3;u<=9;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
//==============================================
for(int u=1;u<=9;u=u+4)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=1;u<=9;u=u+4) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=3;u<=7;u=u+2)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=3;u<=7;u=u+2) if(win_num[u]==0) lll = u; return lll; }
sum=0;
return 0;
}
void win_black()
{
while(digitalRead(button1))
{
if(!digitalRead(button3))
{
get_black();
piece_loc();
if(piece_place[4])
{
//先手下棋
play(5);
while(1)
{
no1:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_black();
piece_loc();
if(cheat_dec())goto no1;
// if(win_scan())resetFunc();
if(danger_scan())play(danger_scan());
else
{
{
sum=0;
for(int z=1;z<=9;z++)
{
sum = win_num[z]+sum;
}
if(sum==4)
{ sum=0; Serial.print("win_mode:") ;
if(win_num[2])
{Serial.println("2");
play(4);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[4])
{Serial.println("4");
play(2);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[6])
{Serial.println("6");
play(2);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[8])
{Serial.println("8");
play(4);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
} }
sum=0;
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto no1;}
}
}
}
}
}
}
else
{
play(1);
while(1)
{
//后手下棋
yes1:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_black();
piece_loc();
if(cheat_dec())goto yes1;
if(danger_scan())play(danger_scan());
else
{
for(int x=1;x<=9;x=x+2)
{
if(!win_num[x]){play(x);goto yes1;}
else
{
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto yes1;}
}
}
}
}
}
}
}
}
}
}
void win_white()
{
while(digitalRead(button1))
{
if(!digitalRead(button3))
{
get_white();
piece_loc();
if(piece_place[4])
{
//先手下棋
play(5);
while(1)
{
no:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_white();
piece_loc();
if(cheat_dec())goto no;
// if(win_scan())resetFunc();
if(danger_scan())play(danger_scan());
else
{
{
sum=0;
for(int z=1;z<=9;z++)
{
sum = win_num[z]+sum;
}
if(sum==4)
{ sum=0; Serial.print("win_mode:") ;
if(win_num[2])
{Serial.println("2");
play(4);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[4])
{Serial.println("4");
play(2);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[6])
{Serial.println("6");
play(2);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[8])
{Serial.println("8");
play(4);while(digitalRead(button3)); {get_white(); play(1);}goto no;
} }
sum=0;
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto no;}
}
}
}
}
}
}
else
{
play(1);
while(1)
{
//后手下棋
yes:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_white();
piece_loc();
if(cheat_dec())goto yes;
if(danger_scan())play(danger_scan());
else
{
for(int x=1;x<=9;x=x+2)
{
if(!win_num[x]){play(x);goto yes;}
else
{
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto yes;}
}
}
}
}
}
}
}
}
}
}
六,实现与调试
最终代码(纯手打,自己编写,真的累死了)
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
void(* resetFunc) (void) = 0;
//函数定义区
int white_1[]={28,14};
int white_2[]={29,19};
int white_3[]={29,24};
int white_4[]={29,29};
int white_5[]={29,34};
int black_1[]={4,14};
int black_2[]={4,19};
int black_3[]={4,24};
int black_4[]={4,29};
int black_5[]={4,34};
int base_loc[]={0,0};
int loc[]={0,0};
int p1[]={20,3};
int p2[]={21,7};
int p3[]={21,12};
int p4[]={16,3};
int p5[]={16,8};
int p6[]={16,11};
int p7[]={11,3};
int p8[]={11,8};
int p9[]={12,12};
int x; int y; int z;
char val=' ';
int piece_place[9]={0};
int win_num[10]={0};
int mode=1;int place=1;int go_place=1;int get_place=1;
int go_white_num=11; int go_black_num=16;
//1:界面1(黑)2:界面2(白)3:界面3(正常)4:调试
int button1=26,button2=24,button3=22;
int menu_num=1;
int base;
int record_human=0;
int sum;
int cheat_round_rec[50][10]={0};
int all_round=0;
int human_bad=0;
int me_good=0;
void button_init()
{
pinMode(button1, INPUT_PULLUP); //初始化按键
pinMode(button2, INPUT_PULLUP); //初始化按键
pinMode(button3, INPUT_PULLUP); //初始化按键
}
void OLED_process()
{
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.print(F("memu:"));
display.println(menu_num);
display.print("Moed=");
display.println(mode);
display.print("place:");
display.println(place);
display.print(base);display.print(" ");display.print(sct()-base);
display.display();
}
//OLED使用函数在此上------------------------------------------------------------------
void setup(){
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
Serial.begin(9600);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(52,OUTPUT);
digitalWrite(52, LOW) ;
button_init();
for(int k=23;k<=39;k=k+2)
{
pinMode(k,INPUT_PULLUP);
}
pinMode(30,OUTPUT);
pinMode(A0,INPUT);
// up(); //自检
// for(int a=0;a<4;a++)
// {
// up_back();
// down_back();
// }
// down();
delay(500);
for(int j=0;j<3;j++)
{
down_back();
up_back();
}
delay(20);
down_for();
OLED_process();
base=sct();
}
void loop(){
all_stop();
// delay(200);
//piece_loc();
// for(int h=0;h<=8;h++)Serial.print(piece_place[h]);
// Serial.println();
if(!digitalRead(button1))
{
if(menu_num==6) menu_num=1;
else menu_num++;
delay(200);
OLED_process();
}
if(!digitalRead(button2))
{
if(menu_num==1 || menu_num==2)
{
if(place==9)place=1;
else place++;
}
if(menu_num==3 || menu_num==4)
{
if(place==9)place=1;
else place++;
}
delay(200);
OLED_process();
}
if(!digitalRead(button3))
{
if(menu_num==1) { get_white(); go_for(place);down();go_for(10);}
if(menu_num==2) { get_black(); go_for(place);down();go_for(10);}
if(menu_num==5) {win_white();}
if(menu_num==6) {win_black();}
// zhuan();
if(menu_num==3) {zhuan(); get_white(); go_for(place);down();go_for(10);}
if(menu_num==4) {zhuan(); get_black(); go_for(place);down();go_for(10);}
}
//下面为调试区-------------------------------------------------------------------------------------------------------------
// if(Serial.available()>0){//检验在串口缓存区中是否有数据,如果有则返回1,没有就是0.
// val = char(Serial.read());
// // if(val=='W'){//
// // up_for();
// // }
// // if(val=='S'){//
// // up_back();
// // }
// // if(val=='A'){//
// // down_back();
// // }
// // if(val=='D'){//
// // down_for();
// // }
// // if(val=='Q'){//
// // up();
// // }
// // if(val=='E'){//
// // down();
// // }
// if(val=='1') go_for(1) ;
// if(val=='2') go_for(2) ;
// if(val=='3')go_for(3);
// if(val=='4') go_for(4) ;
// if(val=='5')go_for(5);
// if(val=='9') go_for(9) ;
// if(val=='0')go_for(10);
// if(val=='Q')up();
// if(val=='E')down();
// }
// for(int i=1;i<10;i++)
// {
// go_for(i);delay(500);
// }
// up();
// delay(1000);
// go_for(5);
// delay(100);
// down();
// delay(1000);
// go_for(10);
// go_for(7);
// go_for(9);
// go_for(6);
// go_for(4);
// go_for(1);
// go_for(3);
// go_for(10); 扫描路径规划
//while(1);
//piece_loc();
}
int cheat_dec()
{
int xm=0;
int ym=0;
int m=0;
for(int u=1;u<=9;u++)
{
if(cheat_round_rec[all_round-1][u]) xm++;
}
for(int u=1;u<=9;u++)
{
if(cheat_round_rec[all_round-1][u] ) ym++;
}
if(xm-ym==1)
{
for(int u=1;u<9;u++)
{ if(cheat_round_rec[all_round-1][u] < cheat_round_rec[all_round][u] ){ human_bad=u; win_num[u]=0;}
if(cheat_round_rec[all_round-1][u] > cheat_round_rec[all_round][u] ) {me_good=u; win_num[u]=1;} }
down();go_for(human_bad);up();go_for(me_good);down();go_for(10);
return 1;
}
else
return 0;
}
void zhuanhua(int *x,int *y,int angle)//传入x,y坐标及其转动角度
{
// double pi= 3.14;
// double radian = angle * (PI / 180.0);
// int c=0;
// int x1=*x,y1=*y;
// int x2=16-x1;
// int y2=16-y1;
// int y_angle=atan(y1/x1);
// int b=sqrt((16-x1)*(16-x1)+(8-y1)*(8-y1));
// int a=sqrt(16*16+8*8);
// double angle_c=acos((x2*y2+y2*x2)/(sqrt(x1*x1+y1*y1)*sqrt(x2*x2+y2*y2)))+radian;
// int c=sqrt(a*a+b*b-2*a*b*cos(angle_c));
// int angle_b=asin(b*sin(angle_c)/c);
// int *x=c*cos(angle_b+y_angle);
// int *y=c*sin(angle_b+y_angle);
int angle11=angle;
double pi= 3.1415;
double radian = angle * (pi / 180.0);
//double chang=45*(PI/180.0);
int x1=*x-16,y1=*y-8;
int bb=*x;int yy=*y;
int r=sqrt(x1*x1+y1*y1);
int a=2*(r*sin(0.5*radian));
int i=0;int j=0;
//Serial.println(111111);
// for(i=0;i<30;i++)
// {
// for(j=0;j<30;j++)
// {
// int q=sqrt((16-i)*(16-i)+(8-j)*(8-j));
// int p=sqrt((bb-i)*(bb-i)+(yy-j)*(yy-j));
// if((q==r)&&(p==a))
// {
// *x=i;
// *y=j;
// }
// }
// }
// return;
int angle11=angle;
if(angle<0)
{
angle11=angle11+360;
}
Serial.println(angle11);
int x1=*y-8;
Serial.println('x1=');
Serial.println(x1);
int y1=*x-16;
Serial.println('y1=');
Serial.println(y1);
int x11,y22;
double angle22=angle11*(PI/180.0);
x11=x1*cos(angle22)-y1*sin(angle22)+8;
y22=x1*sin(angle22)+y1*cos(angle22)+16;
*x=y22;
*y=x11;
return;
}
void zhuan()
{
int bb=sct()-base;
zhuanhua(&p1[0], &p1[1], bb);
zhuanhua(&p2[0], &p2[1], bb);
zhuanhua(&p3[0], &p3[1], bb);
zhuanhua(&p4[0], &p4[1], bb);
zhuanhua(&p5[0], &p5[1], bb);
zhuanhua(&p6[0], &p6[1], bb);
zhuanhua(&p7[0], &p7[1], bb);
zhuanhua(&p8[0], &p8[1], bb);
zhuanhua(&p9[0], &p9[1], bb);
Serial.println(p1[0]);Serial.println(p1[1]);
}
void play(int r) // 下棋到r位置,需要先取子
{
go_for(r);
down();
win_num[r]=3;
go_for(10);
}
int win_scan()//胜利判断 胜利返回1 不胜利返回0
{
int sum1=0;
for(int u=1;u<=3;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=4;u<=6;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=7;u<=9;u++)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
//=====================================
for(int u=1;u<=7;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=2;u<=8;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=3;u<=9;u=u+3)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
//==============================================
for(int u=1;u<=9;u=u+4)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
for(int u=3;u<=7;u=u+2)
{
sum1=sum1+win_num[u];
}
if(sum1==3)return 1;
sum1=0;
return 0;
}
int danger_scan()//返回危险位置,或0
{
// cheat();
int lll=10;
int sum=0;
for(int u=1;u<=3;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u2=1;u2<=3;u2++) if(win_num[u2]==0) lll = u2; return lll; }
if(sum==2){ for(int u2=1;u2<=3;u2++) if(win_num[u2]==0) lll = u2; return lll; }
sum=0;
for(int u=4;u<=6;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=4;u<=6;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=4;u<=6;u++) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=7;u<=9;u++)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
sum=0;
//=====================================
for(int u=1;u<=7;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=1;u<=7;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=2;u<=8;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=2;u<=8;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=3;u<=9;u=u+3)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=3;u<=9;u=u+3) if(win_num[u]==0) lll = u; return lll; }
sum=0;
//==============================================
for(int u=1;u<=9;u=u+4)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=1;u<=9;u=u+4) if(win_num[u]==0) lll = u; return lll; }
sum=0;
for(int u=3;u<=7;u=u+2)
{
sum=sum+win_num[u];
}
if(sum==6){ for(int u=7;u<=9;u++) if(win_num[u]==0) lll = u; return lll; }
if(sum==2){ for(int u=3;u<=7;u=u+2) if(win_num[u]==0) lll = u; return lll; }
sum=0;
return 0;
}
void win_black()
{
while(digitalRead(button1))
{
if(!digitalRead(button3))
{
get_black();
piece_loc();
if(piece_place[4])
{
//先手下棋
play(5);
while(1)
{
no1:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_black();
piece_loc();
if(cheat_dec())goto no1;
// if(win_scan())resetFunc();
if(danger_scan())play(danger_scan());
else
{
{
sum=0;
for(int z=1;z<=9;z++)
{
sum = win_num[z]+sum;
}
if(sum==4)
{ sum=0; Serial.print("win_mode:") ;
if(win_num[2])
{Serial.println("2");
play(4);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[4])
{Serial.println("4");
play(2);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[6])
{Serial.println("6");
play(2);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
}
if(win_num[8])
{Serial.println("8");
play(4);while(digitalRead(button3)); {get_black(); play(1);}goto no1;
} }
sum=0;
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto no1;}
}
}
}
}
}
}
else
{
play(1);
while(1)
{
//后手下棋
yes1:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_black();
piece_loc();
if(cheat_dec())goto yes1;
if(danger_scan())play(danger_scan());
else
{
for(int x=1;x<=9;x=x+2)
{
if(!win_num[x]){play(x);goto yes1;}
else
{
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto yes1;}
}
}
}
}
}
}
}
}
}
}
void win_white()
{
while(digitalRead(button1))
{
if(!digitalRead(button3))
{
get_white();
piece_loc();
if(piece_place[4])
{
//先手下棋
play(5);
while(1)
{
no:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_white();
piece_loc();
if(cheat_dec())goto no;
// if(win_scan())resetFunc();
if(danger_scan())play(danger_scan());
else
{
{
sum=0;
for(int z=1;z<=9;z++)
{
sum = win_num[z]+sum;
}
if(sum==4)
{ sum=0; Serial.print("win_mode:") ;
if(win_num[2])
{Serial.println("2");
play(4);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[4])
{Serial.println("4");
play(2);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[6])
{Serial.println("6");
play(2);while(digitalRead(button3)); {get_white(); play(1);}goto no;
}
if(win_num[8])
{Serial.println("8");
play(4);while(digitalRead(button3)); {get_white(); play(1);}goto no;
} }
sum=0;
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto no;}
}
}
}
}
}
}
else
{
play(1);
while(1)
{
//后手下棋
yes:
if(!digitalRead(button3))
{
for(int o=1;o<=9;o++) Serial.print(win_num[o]);
Serial.println();
get_white();
piece_loc();
if(cheat_dec())goto yes;
if(danger_scan())play(danger_scan());
else
{
for(int x=1;x<=9;x=x+2)
{
if(!win_num[x]){play(x);goto yes;}
else
{
for(int x=1;x<=9;x=x+1)
{
if(!win_num[x]){play(x);goto yes;}
}
}
}
}
}
}
}
}
}
}
void get_white()
{
go_for(go_white_num);
up();
go_white_num++;
}
void get_black()
{
go_for(go_black_num);
up();
go_black_num++;
}
int sct()
{
int ba=analogRead(A0);
ba=ba/3.19;
return ba;
}
void piece_loc()
{
all_round++;
delay(200);
piece_place[0]=digitalRead(27);
piece_place[1]=digitalRead(33);
piece_place[2]=digitalRead(39);
piece_place[3]=digitalRead(25);
piece_place[4]=digitalRead(31);
piece_place[5]=digitalRead(37);
piece_place[6]=digitalRead(23);
piece_place[7]=digitalRead(29);
piece_place[8]=digitalRead(35);
for(int j=0;j<=8;j++)
{
cheat_round_rec[all_round][j+1]=piece_place[j];
Serial.print(piece_place[j]);
if(!piece_place[j])
{
if(!win_num[j+1]){win_num[j+1]=1; record_human=j+1;}
}
} Serial.println();
}
void run_up()
{
digitalWrite(10,HIGH);
digitalWrite(11,LOW);
delay(1600);
digitalWrite(10,LOW);
}
void run_down()
{
digitalWrite(10,LOW);
digitalWrite(11,HIGH);
delay(1600);
digitalWrite(11,LOW);
}
void go_for(int f)
{
if(f==1){ go_up(p1[0]); go_down(p1[1]); }
if(f==2){ go_up(p2[0]); go_down(p2[1]); }
if(f==3){ go_up(p3[0]); go_down(p3[1]); }
if(f==4){ go_up(p4[0]); go_down(p4[1]); }
if(f==5){ go_up(p5[0]); go_down(p5[1]); }
if(f==6){ go_up(p6[0]); go_down(p6[1]); }
if(f==7){ go_up(p7[0]); go_down(p7[1]); }
if(f==8){ go_up(p8[0]); go_down(p8[1]); }
if(f==9){ go_up(p9[0]); go_down(p9[1]); }
if(f==10){
digitalWrite(52,HIGH);
go_up(base_loc[0]); go_down(base_loc[1]);
for(int j=0;j<2;j++)
{
down_back();
up_back();
}
delay(20);
down_for();
all_stop();
digitalWrite(52,LOW);
}
//down_back(); down_for();
if(f==11){ go_up(white_1[0]); go_down(white_1[1]); }
if(f==12){ go_up(white_2[0]); go_down(white_2[1]); }
if(f==13){ go_up(white_3[0]); go_down(white_3[1]); }
if(f==14){ go_up(white_4[0]); go_down(white_4[1]); }
if(f==15){ go_up(white_5[0]); go_down(white_5[1]); }
if(f==16){ go_up(black_1[0]); go_down(black_1[1]); }
if(f==17){ go_up(black_2[0]); go_down(black_2[1]); }
if(f==18){ go_up(black_3[0]); go_down(black_3[1]); }
if(f==19){ go_up(black_4[0]); go_down(black_4[1]); }
if(f==20){ go_up(black_5[0]); go_down(black_5[1]); }
// loc[0]=0;
// loc[1]=0;
}
void go_down(int s)
{
if(loc[1]<s)
{
while((s-loc[1])>0)
// if((s[0]-loc[0])>0)
{down_for();loc[1]++;}
// down_for();down_back();
}
else
{
while((s-loc[1])<0)
// if((s[0]-loc[0])>0)
{down_back();loc[1]--;}
// down_back();down_for();
}
all_stop();
// while((s[1]-loc[1])==!0)
// if((s[1]-loc[1])>0){down_for();loc[1]++;}
}
void go_up(int s)
{
if(loc[0]<s)
{
while((s-loc[0])>0)
// if((s[0]-loc[0])>0)
{up_for();loc[0]++;}
}
else
{
while((s-loc[0])<0)
// if((s[0]-loc[0])>0)
{up_back();loc[0]--;}
}
all_stop();
// while((s[1]-loc[1])==!0)
// if((s[1]-loc[1])>0){down_for();loc[1]++;}
}
void up()
{
run_down();
digitalWrite(30,HIGH);delay(500);
run_up();
}
void down()
{
delay(50);
digitalWrite(30,LOW);delay(500);
}
void all_stop()
{
digitalWrite(9,LOW);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,LOW);
digitalWrite(5,LOW);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,LOW);
delay(2);
}
void down_for()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
}
}
void down_back()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
digitalWrite(9,HIGH);
digitalWrite(8,LOW);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,LOW);
digitalWrite(6,HIGH);
delay(2);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
delay(2);
}
}
void up_for()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
}
}
void up_back()
{
for(int i=1;i<10;i++)//10为一厘米
{
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,LOW);
digitalWrite(2,HIGH);
delay(2);
digitalWrite(5,LOW);
digitalWrite(4,HIGH);
digitalWrite(3,HIGH);
digitalWrite(2,LOW);
delay(2);
}
}
// 上部分向前移动 //十步一厘米
// digitalWrite(5,LOW);
// digitalWrite(4,HIGH);
// digitalWrite(3,HIGH);
// digitalWrite(2,LOW);
// delay(2);
// digitalWrite(5,LOW);
// digitalWrite(4,HIGH);
// digitalWrite(3,LOW);
// digitalWrite(2,HIGH);
// delay(2);
// digitalWrite(5,HIGH);
// digitalWrite(4,LOW);
// digitalWrite(3,LOW);
// digitalWrite(2,HIGH);
// delay(2);
// digitalWrite(5,HIGH);
// digitalWrite(4,LOW);
// digitalWrite(3,HIGH);
// digitalWrite(2,LOW);
// delay(2);
// 上部分向后移动 //十步一厘米
// digitalWrite(5,HIGH);
// digitalWrite(4,LOW);
// digitalWrite(3,HIGH);
// digitalWrite(2,LOW);
// delay(2);
// digitalWrite(5,HIGH);
// digitalWrite(4,LOW);
// digitalWrite(3,LOW);
// digitalWrite(2,HIGH);
// delay(2);
// digitalWrite(5,LOW);
// digitalWrite(4,HIGH);
// digitalWrite(3,LOW);
// digitalWrite(2,HIGH);
// delay(2);
// digitalWrite(5,LOW);
// digitalWrite(4,HIGH);
// digitalWrite(3,HIGH);
// digitalWrite(2,LOW);
// delay(2);
//废稿-------------------------------------------------------------------------------------------------------------//
// //向右走
// digitalWrite(4,HIGH);
// delay(2);
// digitalWrite(4,LOW);
// delay(2);
// // digitalWrite(2,HIGH);
// // delay(2);
// // digitalWrite(2,LOW);
// // delay(2);
// // digitalWrite(5,HIGH);
// // delay(2);
// // digitalWrite(5,LOW);
// // delay(2);
// digitalWrite(3,HIGH);
// delay(2);
// digitalWrite(3,LOW);
// delay(2);
// //向坐走
// digitalWrite(2,HIGH);
// delay(1);
// digitalWrite(2,LOW);
// delay(1);
// digitalWrite(8,HIGH);
// delay(1);
// digitalWrite(8,LOW);
// delay(1);
// digitalWrite(4,HIGH);
// delay(1);
// digitalWrite(4,LOW);
// delay(1);
// digitalWrite(6,HIGH);
// delay(1);
// digitalWrite(6,LOW);
// delay(1);
// digitalWrite(3,HIGH);
// delay(1);
// digitalWrite(3,LOW);
// delay(1);
// digitalWrite(9,HIGH);
// delay(1);
// digitalWrite(9,LOW);
// delay(1);
// digitalWrite(5,HIGH);
// delay(1);
// digitalWrite(5,LOW);
// delay(1);
// digitalWrite(7,HIGH);
// delay(1);
// digitalWrite(7,LOW);
// delay(1);
//向右走
// digitalWrite(5,HIGH);
// digitalWrite(3,HIGH);
// delay(2);
// digitalWrite(5,LOW);
// digitalWrite(4,HIGH);
// delay(2);
// digitalWrite(3,LOW);
// digitalWrite(2,HIGH);
// delay(2);
// digitalWrite(4,LOW);
// digitalWrite(5,HIGH);
// delay(2);
//digitalWrite(3,HIGH);
// digitalWrite(3,HIGH);
// delay(2);