文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-03 15:54

关注

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/

猜数字是一个很经典的小游戏,也是编程开发入门的典型,以下为基于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,具体的按键作用如下:

原始代码修改处理:【代码基础为code-1.0.tar.gz】

  1. ## BSP Settings 
  2. # CONFIG_I2C_SUPPORT is not set 
  3. CONFIG_I2C_SUPPORT=y 
  4. # CONFIG_I2S_SUPPORT is not set​ 
  1. #ifdef CONFIG_I2C_SUPPORT 
  2.      
  3.     // hi_io_set_func(HI_IO_NAME_GPIO_0, HI_IO_FUNC_GPIO_0_I2C1_SDA); 
  4.     // hi_io_set_func(HI_IO_NAME_GPIO_1, HI_IO_FUNC_GPIO_1_I2C1_SCL); 
  5.     hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); 
  6.     hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); 
  7. #endif​ 

 主逻辑代码:guess.c

  1. #include  
  2. #include  
  3.  
  4. #include  
  5. #include  
  6. #include  
  7. #include  
  8. #include  
  9. #include  
  10.  
  11. #include "button/button.h" 
  12. #include "oled/oled.h" 
  13.  
  14.  
  15. char *str[] = { 
  16.     "0123456789"
  17.     "请在心中默想一个1~99的整数,我能在6个问题之内猜出这个数"
  18.     "想好了就按【USER】开始游戏吧,【RST】重启"
  19.     "小了按【S1】,大了按【S2】,正确按【USER】"
  20.     "第?个问题,是这个数吗:??"
  21.     "大了啊!那我再猜小一点"
  22.     "小了啊!那我再猜大一点"
  23.     "哈哈,我猜到了吧!"
  24.     "按【USER】再玩一次(请先默想一个1~99的整数)"
  25.     "你默想的数一定是??" 
  26. }; 
  27.  
  28. int pos[][2] = { 
  29.     {0, 10}, 
  30.     {10, 30}, 
  31.     {40, 24}, 
  32.     {64, 25}, 
  33.     {89, 14}, 
  34.     {103, 11}, 
  35.     {114, 11}, 
  36.     {125, 9}, 
  37.     {134, 26}, 
  38.     {160, 10} 
  39. }; 
  40.  
  41. void display_string(int idx,int delay,int num1, int num2){ 
  42.     int start=0; 
  43.     int len=0; 
  44.  
  45.     start = pos[idx][0]; 
  46.     len = pos[idx][1]; 
  47.     if(idx==4 && num2==100) { 
  48.         len = len +1; 
  49.     } 
  50.     u8 no[len]; 
  51.     for(int i=0;i
  52.         no[i] = start+i; 
  53.     } 
  54.     // 4 "第?个问题,是这个数吗:??"
  55.     if(idx==4) { 
  56.         no[1] = num1; 
  57.         if(num2==100) { 
  58.             no[len-3] = 1; 
  59.             no[len-2] = 0; 
  60.             no[len-2] = 0; 
  61.         } else { 
  62.             no[len-2] = num2/10; 
  63.             no[len-1] = num2%10; 
  64.         } 
  65.     } 
  66.     OLED_Clear(); 
  67.     OLED_ShowChineseString(0,0,no,len,16);         
  68.     usleep(delay*1000*1000);     
  69.  
  70. // 主任务 
  71. static void *GuessTask(const char *arg){ 
  72.     (void)arg; 
  73.  
  74.     gpio_button_init(); 
  75.     oled_display_init(); 
  76.  
  77.     OLED_Clear(); 
  78.     printf("请在心中默想一个1~100的整数,我能在6个问题之内猜出这个数是什么:\n"); 
  79.     display_string(1,2,0,0); 
  80.     printf("想好了就按【USER】开始游戏吧,【RST】重启\n"); 
  81.     display_string(2,2,0,0); 
  82.     printf("小了按【S1】,大了按【S2】,正确按【USER】\n"); 
  83.     display_string(3,0,0,0); 
  84.  
  85.     key_event_t zf; //声明char类型来存放输入的字符 
  86.     char number; //电脑猜测的数字 
  87.  
  88.     while ((zf = gpio_button_get())!=KEY_EVENT_NONE) 
  89.     { 
  90.         // getchar();//忽略回车 
  91.         char min_shu = 1;   // 1是初始最小数。 
  92.         char max_shu = 100; // 100是初始最大数。 
  93.  
  94.         if (zf == KEY_EVENT_USER) 
  95.         { 
  96.             int jishu = 1; // 计数用的,6个问题以内嘛。 
  97.             while (1)   // 条件一直为真,死循环,能用break跳出循环,或用return跳出整个函数。 
  98.             { 
  99.                 number = (min_shu + max_shu) / 2; // 最小数和最大数的和除2 ,意思就是取它们的中间值。 
  100.                 printf("\n第%d个问题,是这个数吗:%d", jishu, number); 
  101.                 display_string(4,0,jishu, number); 
  102.                 zf = gpio_button_get(); 
  103.                 // getchar();//忽略回车 
  104.  
  105.                 if (zf == KEY_EVENT_S2) 
  106.                 { 
  107.                     printf("\n大了啊!那我再猜小一点\n"); 
  108.                     display_string(5,2,0,0); 
  109.                     max_shu = number - 1; //如果是大了,那最大值至少比目前的数小1。 
  110.                     jishu++;              //回答次数加1 ,如果你回答了电脑6次问题,电脑还没有猜对,那电脑就输了。 
  111.                 } 
  112.                 if (zf == KEY_EVENT_S1) 
  113.                 { 
  114.                     printf("\n小了啊!那我再猜大一点\n"); 
  115.                     display_string(6,2,0,0); 
  116.                     min_shu = number + 1; //如果是小了,那最小值至少比目前的数大1。 
  117.                     jishu++;              //同上面,计数加1 
  118.                 } 
  119.                 if (zf == KEY_EVENT_USER) 
  120.                 { 
  121.                     // printf("y\n"); 
  122.                     printf("\n哈哈,我猜到了吧!\n"); 
  123.                     display_string(7,2,0,0); 
  124.                     printf("按【USER】再玩一次(请在心中先默想一个1~100的整数),【RST】重启\n"); 
  125.                     display_string(8,0,0,0); 
  126.                     break; 
  127.                 } 
  128.                 if (jishu == 7) 
  129.                 { 
  130.                     printf("\n你默想的数一定是%d",(min_shu + max_shu) / 2); 
  131.                     display_string(9,2,0,0); 
  132.                     printf("\n按【USER】再玩一次(请在心中先默想一个1~100的整数),【RST】重启\n"); 
  133.                     display_string(8,0,0,0); 
  134.                     break; 
  135.                 } 
  136.             } 
  137.         } 
  138.         else { 
  139.             printf("\n按键无效,请重新选择(按【USER】开始,【RST】重启):"); 
  140.         } 
  141.     } 
  142.     return NULL
  143.  
  144. // 程序入口 
  145. static void GuessEntry(void) 
  146.     osThreadAttr_t attr; 
  147.     WatchDogDisable(); 
  148.     SetLogLevel(HILOG_LV_ERROR); 
  149.  
  150.     attr.name = "GuessTask"
  151.     attr.attr_bits = 0U; 
  152.     attr.cb_mem = NULL
  153.     attr.cb_size = 0U; 
  154.     attr.stack_mem = NULL
  155.     attr.stack_size = 1024; 
  156.     attr.priority = osPriorityNormal; 
  157.  
  158.     if (osThreadNew((osThreadFunc_t)GuessTask, NULL, &attr) == NULL) { 
  159.         printf("[GuessNum] Falied to create GuessTask!\n"); 
  160.     } 
  161.  
  162. SYS_RUN(GuessEntry); 

主逻辑代码说明:

因为在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请查看附件】

  1. #ifndef __OLED_H 
  2. #define __OLED_H 
  3.  
  4.  
  5. #define OLED_MODE 0 
  6. #define SIZE 8 
  7. #define XLevelL     0x00 
  8. #define XLevelH     0x10 
  9. #define Max_Column  128 
  10. #define Max_Row     64 
  11. #define Brightness  0xFF  
  12. #define X_WIDTH     128 
  13. #define Y_WIDTH     64       
  14.  
  15.  
  16. #define OLED_CMD  0 //写命令 
  17. #define OLED_DATA 1 //写数据 
  18.  
  19.  
  20. #define u8 unsigned char 
  21. #define u16 unsigned short 
  22. #define u32 unsigned int 
  23.  
  24. //OLED控制用函数 
  25. void delay_ms(unsigned int ms); 
  26. void OLED_ColorTurn(u8 i); 
  27. void OLED_DisplayTurn(u8 i); 
  28. void OLED_WR_Byte(u8 dat,u8 cmd); 
  29. void OLED_Set_Pos(u8 x, u8 y); 
  30. void OLED_Display_On(void); 
  31. void OLED_Display_Off(void); 
  32. void OLED_Clear(void); 
  33. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey); 
  34. u32 oled_pow(u8 m,u8 n); 
  35. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey); 
  36. void OLED_ShowString(u8 x,u8 y,char *chr,u8 sizey); 
  37. void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey); 
  38. void OLED_ShowChineseString(u8 x,u8 y,u8 no[],u8 length,u8 sizey); 
  39. void OLED_Direct_ShowString(u8 x,u8 y,char *chr,u8 sizey); 
  40. void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]); 
  41. void OLED_Init(void); 
  42. void oled_display_init(void); 
  43. #endif 

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

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

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

具体获取方式如下:

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

  1. #ifndef __BUTTON_H 
  2. #define __BUTTON_H 
  3.  
  4. #include  
  5.  
  6. #define APP_DEMO_ADC 
  7. #define ADC_TEST_LENGTH 64 
  8. #define VLT_MIN 100 
  9. #define STATUS_LEN 4 
  10.  
  11. // 按键状态定义 
  12. typedef enum 
  13.     KEY_EVENT_NONE = 0, 
  14.     KEY_EVENT_S1, 
  15.     KEY_EVENT_S2, 
  16.     KEY_EVENT_USER 
  17. } key_event_t; 
  18.  
  19. //获取当前按键 
  20. key_event_t get_key_event(void); 
  21.  
  22. // ADC转换 
  23. hi_void convert_to_voltage(hi_u32 data_len); 
  24.  
  25. // ADC获取 
  26. void button_adc_test(void); 
  27.  
  28. // 设置 按键中断响应 
  29. void gpio_button_init(void); 
  30.  
  31. // 获取需要的按键状态 
  32. key_event_t gpio_button_get(void); 
  33.  
  34. #endif 

 按键部分代码说明:

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

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯