鸿蒙基于WiFi IoT套件开发的猜数字小游戏代码分享

系统
猜数字是一个很经典的小游戏,也是编程开发入门的典型,以下为基于WiFi IoT套件开发的猜数字小游戏的具体开发过程和效果。

猜数字是一个很经典的小游戏,也是编程开发入门的典型,以下为基于WiFi IoT套件开发的猜数字小游戏的具体开发过程和效果。

基本规则:

由甲方(玩家)默想一个1-99(包含)内的任意数字(整数),然后由乙方进行猜测,并询问甲方猜测的数字是大了还是小了,甲方根据实际情况进行回复,则乙方最多问6个问题,就一定能够猜中甲方默想的数字。

基本原理:

乙方问最多6次,包括最后一次说出猜中的数字,实际上乙方最多有7次猜测的机会。

而使用二分进行查找,2^7=128,则99以内的数字,完全可以覆盖,因此乙方绝对可以猜中。

实现概述:

以上的基本规则和基本原理明确了,我们要在WiFi IoT套件上实现,并且甲方需要参与,需要处理以下三个部分:

  1. 猜数字的主逻辑
  2. 使用OLED屏幕显示提示信息,让玩家进行互动操作:我们需要在屏幕上显示汉字,进行玩家当前猜测的数字,以及玩家按键后告知玩家结果
  3. 使用按键接收玩家操作(大了或者小了等):在这个实例中,我们使用了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
## BSP Settings 

# CONFIG_I2C_SUPPORT is not set 
CONFIG_I2C_SUPPORT=y 
# CONFIG_I2S_SUPPORT is not set​ 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  •  I2C复用端口设置:vendor/hisi/hi3861/hi3861/app/wifiiot_app/init/app_io_init.c
#ifdef CONFIG_I2C_SUPPORT 
    /* I2C IO复用也可以选择3/4; 9/10,根据产品设计选择 */ 
    // hi_io_set_func(HI_IO_NAME_GPIO_0, HI_IO_FUNC_GPIO_0_I2C1_SDA); 
    // hi_io_set_func(HI_IO_NAME_GPIO_1, HI_IO_FUNC_GPIO_1_I2C1_SCL); 
    hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); 
    hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); 
#endif​ 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

 主逻辑代码: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" 
 
/* 
0123456789 
请在心中默想一个1~99的整数,我能在6个问题之内猜出这个数 
想好了就按【USER】开始游戏吧,【RST】重启 
小了按【S1】,大了按【S2】,正确按【USER】 
第?个问题,是这个数吗:?? 
大了啊!那我再猜小一点 
小了啊!那我再猜大一点 
哈哈,我猜到了吧! 
按【USER】再玩一次(请先默想一个1~99的整数) 
你默想的数一定是?? 
 
//  开始:0,长度10 
//  开始:10,长度30 
//  开始:40,长度24 
//  开始:64,长度25 
//  开始:89,长度14 
//  开始:103,长度11 
//  开始:114,长度11 
//  开始:125,长度9 
//  开始:134,长度26 
//  开始:160,长度10 
*/ 
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; 
    } 
    // 4 "第?个问题,是这个数吗:??"
    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类型来存放输入的字符 
    char number; //电脑猜测的数字 
 
    while ((zf = gpio_button_get())!=KEY_EVENT_NONE) 
    { 
        // getchar();//忽略回车 
        char min_shu = 1;   // 1是初始最小数。 
        char max_shu = 100; // 100是初始最大数。 
 
        if (zf == KEY_EVENT_USER) 
        { 
            int jishu = 1; // 计数用的,6个问题以内嘛。 
            while (1)   // 条件一直为真,死循环,能用break跳出循环,或用return跳出整个函数。 
            { 
                number = (min_shu + max_shu) / 2; // 最小数和最大数的和除2 ,意思就是取它们的中间值。 
                printf("\n第%d个问题,是这个数吗:%d", jishu, number); 
                display_string(4,0,jishu, number); 
                zf = gpio_button_get(); 
                // getchar();//忽略回车 
 
                if (zf == KEY_EVENT_S2) 
                { 
                    printf("\n大了啊!那我再猜小一点\n"); 
                    display_string(5,2,0,0); 
                    max_shu = number - 1; //如果是大了,那最大值至少比目前的数小1。 
                    jishu++;              //回答次数加1 ,如果你回答了电脑6次问题,电脑还没有猜对,那电脑就输了。 
                } 
                if (zf == KEY_EVENT_S1) 
                { 
                    printf("\n小了啊!那我再猜大一点\n"); 
                    display_string(6,2,0,0); 
                    min_shu = number + 1; //如果是小了,那最小值至少比目前的数大1。 
                    jishu++;              //同上面,计数加1 
                } 
                if (zf == KEY_EVENT_USER) 
                { 
                    // printf("y\n"); 
                    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请查看附件】

#ifndef __OLED_H 
#define __OLED_H 
 
 
#define OLED_MODE 0 
#define SIZE 8 
#define XLevelL     0x00 
#define XLevelH     0x10 
#define Max_Column  128 
#define Max_Row     64 
#define Brightness  0xFF  
#define X_WIDTH     128 
#define Y_WIDTH     64       
 
 
#define OLED_CMD  0 //写命令 
#define OLED_DATA 1 //写数据 
 
 
#define u8 unsigned char 
#define u16 unsigned short 
#define u32 unsigned int 
 
//OLED控制用函数 
void delay_ms(unsigned int ms); 
void OLED_ColorTurn(u8 i); 
void OLED_DisplayTurn(u8 i); 
void OLED_WR_Byte(u8 dat,u8 cmd); 
void OLED_Set_Pos(u8 x, u8 y); 
void OLED_Display_On(void); 
void OLED_Display_Off(void); 
void OLED_Clear(void); 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey); 
u32 oled_pow(u8 m,u8 n); 
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey); 
void OLED_ShowString(u8 x,u8 y,char *chr,u8 sizey); 
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey); 
void OLED_ShowChineseString(u8 x,u8 y,u8 no[],u8 length,u8 sizey); 
void OLED_Direct_ShowString(u8 x,u8 y,char *chr,u8 sizey); 
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]); 
void OLED_Init(void); 
void oled_display_init(void); 
#endif 
  • 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.

 OLED汉字字模数据获取方式:

在OLED上面显示字符(包括汉字),本质上是描点,所以获取对应字符的点阵数据即可。

生成字模数据的工具为PCToLCD,设置为字符模式和C51格式;这个工具还可以用于取图片的点阵数据。

具体获取方式如下:

按键部分代码:【以下为button/button.h,button/button.c请查看附件】

#ifndef __BUTTON_H 
#define __BUTTON_H 
 
#include <hi_types_base.h> 
 
#define APP_DEMO_ADC 
#define ADC_TEST_LENGTH 64 
#define VLT_MIN 100 
#define STATUS_LEN 4 
 
// 按键状态定义 
typedef enum 

    KEY_EVENT_NONE = 0, 
    KEY_EVENT_S1, 
    KEY_EVENT_S2, 
    KEY_EVENT_USER 
} key_event_t; 
 
//获取当前按键 
key_event_t get_key_event(void); 
 
// ADC转换 
hi_void convert_to_voltage(hi_u32 data_len); 
 
// ADC获取 
void button_adc_test(void); 
 
// 设置 按键中断响应 
void gpio_button_init(void); 
 
// 获取需要的按键状态 
key_event_t gpio_button_get(void); 
 
#endif 
  • 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.

 按键部分代码说明:

当使用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

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2012-01-10 12:48:52

Java

2015-09-29 09:38:50

Java程序猜大小

2020-11-10 12:08:25

开发框架

2019-09-23 09:11:02

Python文本编辑器操作系统

2023-01-03 15:16:27

2022-12-27 14:39:38

2023-02-23 14:30:27

游戏Tcl

2023-02-13 08:26:28

猜数字Basic

2022-08-04 13:55:08

拼数字小游戏鸿蒙

2020-11-12 09:44:43

鸿蒙

2012-09-11 09:19:35

JavaScriptJSjQ

2022-08-25 21:41:43

ArkUI鸿蒙

2020-11-13 11:53:52

4.WiFi IoT

2021-10-04 18:49:46

Fortran 77语言猜数字

2021-01-12 06:42:50

Lua脚本语言编程语言

2018-01-22 20:35:27

微信小游戏开发

2020-10-30 17:57:11

鸿蒙HiSpark

2022-06-03 16:59:13

编程语言Awk

2022-08-22 17:28:34

ArkUI鸿蒙

2012-01-17 12:39:09

JavaSwing
点赞
收藏

51CTO技术栈公众号