猜数字是一个很经典的小游戏,也是编程开发入门的典型,以下为基于WiFi IoT套件开发的猜数字小游戏的具体开发过程和效果。
基本规则:
由甲方(玩家)默想一个1-99(包含)内的任意数字(整数),然后由乙方进行猜测,并询问甲方猜测的数字是大了还是小了,甲方根据实际情况进行回复,则乙方最多问6个问题,就一定能够猜中甲方默想的数字。
基本原理:
乙方问最多6次,包括最后一次说出猜中的数字,实际上乙方最多有7次猜测的机会。
而使用二分进行查找,2^7=128,则99以内的数字,完全可以覆盖,因此乙方绝对可以猜中。
实现概述:
以上的基本规则和基本原理明确了,我们要在WiFi IoT套件上实现,并且甲方需要参与,需要处理以下三个部分:
- 猜数字的主逻辑
- 使用OLED屏幕显示提示信息,让玩家进行互动操作:我们需要在屏幕上显示汉字,进行玩家当前猜测的数字,以及玩家按键后告知玩家结果
- 使用按键接收玩家操作(大了或者小了等):在这个实例中,我们使用了ADC方式来读取按键信息,从而获得玩家具体操作。所使用的按键为核心板上的USR按键,和OLED板上的S1,S2按键。使用ADC方式读取的时候,他们所使用的输入端口为GPIO5/ADC2,具体的按键作用如下:
-
- USR:开始游戏,或者确认
- S1:如果猜小了,则玩家按S1告知
- S2:如果猜大了,则玩家按S2告知
原始代码修改处理:【代码基础为code-1.0.tar.gz】
- 开启I2C:vendor/hisi/hi3861/hi3861/build/config/usr_config.mk
- I2C复用端口设置:vendor/hisi/hi3861/hi3861/app/wifiiot_app/init/app_io_init.c
主逻辑代码:guess.c
#include <stdio.h>
#include <unistd.h>
#include <ohos_init.h>
#include <cmsis_os2.h>
#include <hiview_config.h>
#include <hiview_log.h>
#include <wifiiot_watchdog.h>
#include <hi_task.h>
#include "button/button.h"
#include "oled/oled.h"
char *str[] = {
"0123456789",
"请在心中默想一个1~99的整数,我能在6个问题之内猜出这个数",
"想好了就按【USER】开始游戏吧,【RST】重启",
"小了按【S1】,大了按【S2】,正确按【USER】",
"第?个问题,是这个数吗:??",
"大了啊!那我再猜小一点",
"小了啊!那我再猜大一点",
"哈哈,我猜到了吧!",
"按【USER】再玩一次(请先默想一个1~99的整数)",
"你默想的数一定是??"
};
int pos[][2] = {
{0, 10},
{10, 30},
{40, 24},
{64, 25},
{89, 14},
{103, 11},
{114, 11},
{125, 9},
{134, 26},
{160, 10}
};
void display_string(int idx,int delay,int num1, int num2){
int start=0;
int len=0;
start = pos[idx][0];
len = pos[idx][1];
if(idx==4 && num2==100) {
len = len +1;
}
u8 no[len];
for(int i=0;i<len;i++){
no[i] = start+i;
}
if(idx==4) {
no[1] = num1;
if(num2==100) {
no[len-3] = 1;
no[len-2] = 0;
no[len-2] = 0;
} else {
no[len-2] = num2/10;
no[len-1] = num2%10;
}
}
OLED_Clear();
OLED_ShowChineseString(0,0,no,len,16);
usleep(delay*1000*1000);
}
static void *GuessTask(const char *arg){
(void)arg;
gpio_button_init();
oled_display_init();
OLED_Clear();
printf("请在心中默想一个1~100的整数,我能在6个问题之内猜出这个数是什么:\n");
display_string(1,2,0,0);
printf("想好了就按【USER】开始游戏吧,【RST】重启\n");
display_string(2,2,0,0);
printf("小了按【S1】,大了按【S2】,正确按【USER】\n");
display_string(3,0,0,0);
key_event_t zf;
char number;
while ((zf = gpio_button_get())!=KEY_EVENT_NONE)
{
char min_shu = 1;
char max_shu = 100;
if (zf == KEY_EVENT_USER)
{
int jishu = 1;
while (1)
{
number = (min_shu + max_shu) / 2;
printf("\n第%d个问题,是这个数吗:%d", jishu, number);
display_string(4,0,jishu, number);
zf = gpio_button_get();
if (zf == KEY_EVENT_S2)
{
printf("\n大了啊!那我再猜小一点\n");
display_string(5,2,0,0);
max_shu = number - 1;
jishu++;
}
if (zf == KEY_EVENT_S1)
{
printf("\n小了啊!那我再猜大一点\n");
display_string(6,2,0,0);
min_shu = number + 1;
jishu++;
}
if (zf == KEY_EVENT_USER)
{
printf("\n哈哈,我猜到了吧!\n");
display_string(7,2,0,0);
printf("按【USER】再玩一次(请在心中先默想一个1~100的整数),【RST】重启\n");
display_string(8,0,0,0);
break;
}
if (jishu == 7)
{
printf("\n你默想的数一定是%d",(min_shu + max_shu) / 2);
display_string(9,2,0,0);
printf("\n按【USER】再玩一次(请在心中先默想一个1~100的整数),【RST】重启\n");
display_string(8,0,0,0);
break;
}
}
}
else {
printf("\n按键无效,请重新选择(按【USER】开始,【RST】重启):");
}
}
return NULL;
}
static void GuessEntry(void)
{
osThreadAttr_t attr;
WatchDogDisable();
SetLogLevel(HILOG_LV_ERROR);
attr.name = "GuessTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)GuessTask, NULL, &attr) == NULL) {
printf("[GuessNum] Falied to create GuessTask!\n");
}
}
SYS_RUN(GuessEntry);
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
主逻辑代码说明:
因为在OLED上面显示字符(包括汉字),需要预先取得汉字的字模点阵数据;在这个实例中,会有不同的提示语出现,且未中文,为了方便处理,我将每句话的字模点阵数据单独取出,所以定义了str[],pos[][2],以及display_string(),用于显示对应的语句。其最终调用oled/oled.c中的OLED_ShowChineseString()来将汉字输出到OLED屏幕;特别的,语句4“第?个问题,是这个数吗:??”需要处理具体数字,所以进行了特殊的处理。
获取按键的部分,在button/button.c中的gpio_button_get(),代码随后展示,用于获取按键的状态
OLED部分代码:【以下为oled/oled.h,oled/oled.c和字模数据oled/oledfont.h请查看附件】
OLED汉字字模数据获取方式:
在OLED上面显示字符(包括汉字),本质上是描点,所以获取对应字符的点阵数据即可。
生成字模数据的工具为PCToLCD,设置为字符模式和C51格式;这个工具还可以用于取图片的点阵数据。
具体获取方式如下:
按键部分代码:【以下为button/button.h,button/button.c请查看附件】
按键部分代码说明:
当使用ADC方式来读取按键状态的时候,本质上,是读取了ADC输入端口的数据,这个数据进过一定的转换,能够化为对应的电压数据。而不同的按键按下后,ADC端口读取的电压是不同的,并且是在一定范围内波动的,对应按键的电压范围在上述vlt_val_scopes中进行了定义。我们获取到了对应的电压数据,然后与vlt_val_scopes每个范围数据进行对比,从而据此得到对应的按键信息。
实际结果演示:

视频地址: 链接: https://pan.baidu.com/s/1RtT8Wh3ZPbasJ-dK7x1QRg 提取码: vkyh
完整代码:

下载地址: https://pan.baidu.com/s/1RtT8Wh3ZPbasJ-dK7x1QRg 提取码: vkyh
乔帮主周六晚上辛苦了,回答了那么多问题。和粉丝们互动到10点多。
请问乔老师能把完整代码贴在文章附件下吗,百度云实在太慢了
已上传。
征文大赛正在火热进行中,楼主这么优秀的文章真的不考虑参加吗?
例如这篇在标题开头添加“#2020征文-开发板#“,
再找到相应的专栏位置投稿,
就可以参加比赛啦!
详细步骤可以点击链接https://harmonyos.51cto.com/posts/1940进行了解
用更多的文章来赢取更多的奖励和人气吧!期待楼主后续的活跃表现。
已经设置好啦!