C语言实现钢琴块小游戏(低仿拉胯版)

声明:这篇文章中出现的代码并非凑字数,与叙述内容无关的均已用文字代替,还请耐心阅读


(没错俺偷懒直接把作业报告改改(其实没怎么改)就发出来了)

(虽然说是小游戏,但不知为什么压缩后都超50MB了555)

首先上源码链接(内含食用方法)

发现用百度网盘发太费事了,所以直接传到github公开了,欢迎直接运行

GitHub - robin-bird-go/fake_piano_blocks: 钢琴块的低仿拉胯版

(以及总代码在链接里面,文中的基本上是半伪代码)

(先上个图镇楼,整了个简单gif)

一、开发环境

  1. 基本软件:vs2022和easy_x插件

  2. 使用已有库

#include<windows.h>
#include<stdio.h>
#include <stdlib.h>
#include<time.h>
#include <conio.h>
#include <graphics.h>
#include <time.h>
#include <math.h>

二、基本原理

  1. 菜单界面展示:利用<windows.h>库中的system函数进行窗口格式、显示内容操作(比如清屏"cls",暂停"pause"),COORD结构体来实现光标的移动

  2. 实时对输入的读取:利用<coino.h>库的_getch()函数来获取输入的按键值、_kbhit()来判断是否有按键值输入

  3. 游戏界面的绘制:利用<graphics.h>库的相关绘制操作、绘图(这里主要用到了线条、矩形绘制)的函数来形成基本画面和动态图像

  4. 游戏元素、变量的存储:该游戏的核心元素是钢琴块,其产生,消除的先后顺序正好是FIFO,符合队列特点,故用该数据结构实现;游戏数据记录是通过读取本地txt文件,但是展示时可能面临一页界面不足的问题,所以采用单向链表存储每一页的数据

  5. 游戏动态展示思维:游戏的画面也是类似于视频的”逐帧播放“,需要不停进行清屏、绘制,easy_x的库函数中有一系列批量绘制的函数可以实现双缓冲作用防止游戏画面闪烁

三、需求说明

作为一款轻量级的简单小游戏,在以下方面具有相应特点

  1. 在界面设计上,简单,功能清晰明了

  2. 在与用户交互上,尽量做到反馈及时准确,画面流畅舒适等

  3. 在游戏内容规则上,将相关设置和游戏玩法用简明扼要的方式呈现,能让体验者快速上手

  4. 在游戏条件上,应尽量从简单化,不需要过多的配置即可打开、运行游戏

四、成果展示

(1)基本功能

  1. 界面显示

    • 菜单界面

      先利用system("mode con cols=120 lines=40 ");将命令行窗口设置为120字符宽,40行高度

      在配合gotoxy()函数,将光标自由移动到指定位置,进行输出,例如星标的打出

      //星标的打出,n表示打在第几行,num表示一共多少选项
      void menu_select(int num, int n)
      {int i;for (i = 0; i < num; i++){if (i == n){gotoxy(35, 18 + i * 5);printf("-★-");gotoxy(64, 18 + i * 5);printf("-★-");}else{gotoxy(35, 18 + i * 5);printf("    ");gotoxy(64, 18 + i * 5);printf("    ");}}
      }

    • 游戏界面

      initgraph(100 * key_num + 120, 650);开始,这里宽度受到打击键个数的影响,高度恒为650;以closegraph();结束,关闭绘图(游戏)窗口

      绘制背景、图形,先set_sth_color(RGB()),set_sth_style(),再绘制相应图形如直线line(左端点x,左端点y,右端点x,右端点y),矩形fillrectangle(l,t,r,d)

  2. 钢琴块移动

    每次将blocks结构体的y值增加,并配合清屏、绘制即可实现

    while (tmp)
    {display_b(tmp);tmp->y += 3 * speed;tmp = tmp->next;
    }
  3. 击中判定以及发声

    在检测到外部输入时,根据blocks结构体的y(也就是钢琴块的下端)与打击区域的关系来给出相应处理,在区间外视为miss,在区间内,根据其距离打击重心的远近来给出不同的分数;发声是对应有bgm的版本的模式,利用一个简单的蜂鸣函数Beep(fre,time)实现,击中的处理均为使当前节点出队(具体结构体运用会在后面详细说明)

  4. 游戏属性的设置

    设置了一些可调整大小的参数,来改变游戏的属性,从而增加游戏的多样性

  5. 游戏数据的存储

    主要运用C语言的文件读取函数fopen(),fgets(),fscanf()来进行文件读、写,读到末尾用fscanf()== EOF来判定

(2)游戏模式

游戏模式有三种,分别为:

  1. 有bgm版本/无bgm原版

前者主要多了一个击中某些特定音符的发声效果,界面是一样的

  1. 双向魔改版

这里主要是将游戏界面分为了两部分,左边往下移动,右边往上移动,打击线的位置对称,保证每次只会在两边中的一边进行击打钢琴块

具体界面可以在后面运行结果展示以及附带游戏体验视频中观看

(3)核心代码/思路分析

[1]总体的编程过程

  1. 参数化设置,便于不断调试修改

    对于一些经常被使用到,但无需更改值的量,被定义为宏后,放于文件顶端,方便集中修改,因为窗口的尺寸、文字输出的位置,大小等都是十分需要进行实际运行,观察输出来一步步调整的,参数化设置提供了极大的便利

  2. 模块化编程(多文件)

    (i)内容:该项目包含3个源文件(main.cpp,menu.cpp,game.cpp),2个头文件(menu.h,game.h),也就是一个主程序,和两个模块(一个是菜单,一个是游戏)

    (ii)过程:

    • 先从菜单界面显示开始,通过学习网络上的文章,在main.c中先编写出相应的函数,引用对应的库函数,使之编译,运行通过后,再开始代码转移;

    • //main.c文件中
      #include <windows.h>
      //#include ....
      ​
      //清屏
      void clr(void)
      {system("cls");
      }
      ​
      //int main()....

    • 创建/寻找你想放入的模块对应的.cpp.h文件,并参考下面格式进行补充

    • //menu.h
      /*
      头文件放入以下内容(一般不在这里引用头文件)
      1.宏定义(带值)     #define  
      2.结构体声明  typedef struct ...;
      3.常量定义(带值)  const data_type <x> = ...;
      4.变量声明  ▲容易被报错重定义,如果想用全项目均可访问的,建议用extern▲extern data_type <x>;
      5.函数声明   void fun(void);
      */
      #pragma once
      #define main_menu_choice 4
      typedef struct _page//每一页的数据
      {int n;//这个表示存了多少行int data[9][7];char time[9][20];struct _page* last;struct _page* next;
      }p, * pp;
      extern pp head;//此时它还没有值,只是被声明了
      const int choose[3][3] = { {1,2,3},{1,2,3},{4,5,6} };
      void clr(void);//函数声明

    • //menu.cpp
      /*
      1.该文件下需要的头文件引用  #include...
      (特别提醒,一定要在非主程序.cpp文件下引用同名的.h文件)
      2.变量定义(如果需要初值,可以在这里设置)  data_type <x> = value;
      3.函数定义  void fun(){...}
      */
      #include "menu.h"
      //#include <stdio.h> ...
      ​
      //清屏,函数定义被移动到这里了
      void clr(void)
      {system("cls");
      }

    • 最后记得主程序也要引用自己定义的.h头文件,用#include "head.h"格式,是双引号,否则可能会引用失败

    • 甚至,对于一些比较复杂的、关联性大,需要一次性写出所有函数再debug的内容,可以重新开一个新的项目,单独调试,成功后再移植过来

    • 总之,对于一个较为复杂,功能较多的项目,应分而治之,逐级调试后再整合

  3. 游戏的运行模式处理

    (i)循环性:由于游戏需要实时与用户交互,随时监测输入的信息并及时给出输出,所以整个程序的主体是在while(1)的循环里的,而大多数功能模块,也在while(1)循环中,只在特定的条件下被break,跳转到其他的代码块中,从此次经验看,整体代码有如下框架:

    //主菜单
    int main()
    {while(1){清屏根据输入值调整屏幕显示内容,输出主菜单while(1){监测有无外部输入if(有)break;            }获取外部输入if(输入 == value_1){清屏         给出对应显示while(1){清屏获取外部输入if(输入 == ord_1)对应显示..else if(...)break;}}else if(输入 == value_2)....                            }           return 0;
    }

    而游戏主体部分更是如此

    //游戏部分
    void game()
    {初始化界面,内存while(1){while(未超出打击区域极限){移动钢琴块清屏,显示检测外部输入有无if(有)break;}获取输入if(表示暂停){while(1)遇到对应条件,退出}else if(到达打击区域)  击中与否进行判断以及处理else if(超出打击区域)对应处理    } 输出游戏结束的结果
    }

    (ii)界面动态性:其实是与循环性相成的,因为画面会因为玩家操作而改变,这涉及清屏重绘的反复性,但是绘制总会有先后性,如果仅仅是在while循环里清屏,逐个绘制,容易使画面闪烁,而在网上看到的很多解决办法即是使用双缓冲机制,而强大的easy_x库提供了3个有力的工具,可以直接实现这样的作用,即

    void BeginBatchDraw();
    // 结束批量绘制,并执行指定区域内未完成的绘制任务
    void EndBatchDraw(int left,int top,int right,int bottom
    );
    // 执行指定区域内未完成的绘制任务
    void FlushBatchDraw(int left,int top,int right,int bottom
    ); 

    后两者没有太大的区别,使用方法为

    BeginBatchDraw();
    绘制操作
    FlushBatchDraw();

    这样就可以让绘制的内容一次性被输出在画面上,而不分先后,从而解决闪烁问题。

[2]运用的数据结构知识

  1. 钢琴块元素的存储->链式队列

    • (1)使用背景:由于游戏模式是不断产生新的元素,再消除已被击中的元素,符合FIFO的特点,故用队列的结构来存储方块,实现过程如下

    • (2)流程:先定义钢琴块结构体,存储其相关信息,再定义队列

    • typedef struct _block
      {int x;    //这个是左下角的坐标int y;int fre;  //对于有声音的方块,存其频率int time; //对于有声音的方块,存其发声时长struct _block* next; //用的链式队列,可以不用担心溢出问题
      }b, * pb;
      typedef struct _queue
      {pb head;pb tail;int num;  //存储当前队列一共多少元素
      }que, * qq;

    • 再定义入队、出队的操作函数,包含指针的改变,队列元素个数的增/减,特别之处在于需要注意,出队时及时free(p)释放空间

    • void in_queue(pb nb)
      {q->tail->next->next = nb;q->tail->next = nb;q->num++;
      }
      //出队操作,这里就是把方块消失,不能再显示了,而且记得及时释放空间
      void out_queue()
      {pb tmp = q->head->next;q->head->next = tmp->next;free(tmp);q->num--;
      }

    • 结合游戏背景,设置判定条件,即何时入队(在队列的元素个数小于6个时,无bgm模式是只要有一个钢琴块被消除,立刻出队,并新入队元素;在有bgm的模式麻烦一些,因为可能一次性会加得总数超过6个),何时出队(统一规定,只要在击打区间击中,即出队,对于有bgm的模式还允许在方块的下端超出击打范围,判定miss时出队)这里以无bgm简单模式为例子,同时为了方便阅读,重点关注队列操作的内容,省去一些非相关的函数,转用一些伪代码

    • void init_block2(int n)
      {//先初始化队列和队头尾结点和一个结点q = (qq)malloc(sizeof(que));初始化队列pb nb;nb = (pb)malloc(sizeof(b));队头尾结点初始化q->head->next = q->tail->next = nb;q->num = 1;//再对剩余钢琴块初始化int i = 5;while (i){nb = (pb)malloc(sizeof(b));nb->y = (4 - q->num) * 110;nb->x = (rand() % n) * 100;nb->next = NULL;in_queue(nb);i--;}
      }
      //成功击中方块
      void hit_b23()
      {out_queue();
      }
      //持续获取新的方块,在有方块出队且剩余时,保持有6个方块,当方块数目<=6,开始继续获取方块
      void get_block2(int n)
      {pb nb = (pb)malloc(sizeof(b));nb->y = q->tail->next->y - 110;nb->x = (rand() % n) * 100;nb->next = NULL;in_queue(nb);
      }
      void game2(int n, int ac)
      {//先把初始化界面整出来init_block2(n);pb tmp = q->head->next;int now = 1;while (tmp && now <= 6){display_b(tmp);//将钢琴块显示在界面上tmp = tmp->next;now++;}设置暂停界面提示system("pause");char in = 0;int c, flag = 0;//开始正式游戏while (1){输出提示if (第一个节点为空)break;while (第一个节点没有超出击打区域){in = 0;if (q->head->next->y >= 550 - ac * ac * ac_unit)in = _kbhit();if (in != 0)break;清屏,开始批量绘图pb tmp = q->head->next;创建画面while (tmp){display_b(tmp);//显示每个钢琴块tmp->y += 3 * speed;tmp = tmp->next;}输出提示批量绘图,显示画面Sleep(20);//系统暂停20ms,以控制钢琴块移动速度}in = _getch();if (输入空格,暂停){while (1){in = _getch();if (再次输入空格,退出暂停,继续游戏)break;else{结束并退出游戏,记录数据}}}if (超出打击区域){//超出打击区域极限,判定miss记录数据,结束并退出游戏}else if (in && q->head->next->y >= 550 - ac * ac * ac_unit){//在打击区域,进行打击正确性的判定c = q->head->next->x / 100;if (in == key[c]){计分hit_b23();}else{int j = 0;for (j = 0; j < n; j++){if (j != c){if (key[j] == in){记录数据并退出游戏}}}}}if (q->num < 6)get_block2(n);else if (q->num == 0)break;}结束批量绘图显示游戏结束信息记录该局游戏信息
      }

  2. 本地数据的存储->双向链表

    • (1)使用背景:玩家进行游戏的次数未免会很多,而相应的记录数据量也会增大,在进行本地游戏记录查询时,会想浏览任意页数、任意行的信息,涉及向前和向后访问的需求,所以使用双向链表来存储(将数据进行9行/页的分组后的)每页的信息

      • (2)流程:定义页数信息

  • typedef struct _page   //每一页的数据{int n;             //这个表示存了多少行int data[9][7];    //一页最多9行,每行有7个数据,分数,连击数等char time[9][20];  //这个存游戏时间struct _page* last;struct _page* next;
    }p, * pp;

  • 双向链表基本操作,在创建新链表(涉及到是否需要创建一个新的页来继续存数据的判断),尾部添加新结点,读取结点信息

  • //从尾部添加新链表void in_link(pp link, int i, int* list, char* tt)
    {int j;for (j = 0; j < 7; j++)link->data[i][j] = list[j];strcpy(link->time[i], tt);
    }//读取txt文件形成链表
    void store_data(void)
    {rewind(data_fp);//让文件被重读int i, j;pp tmp = head;if (未读到文件末)将临时读取的值存入节点while (未读到文件末){存临时读取值if (i < 9)//也就是当读取的行数没到9行时{值存入当前页节点i++;}else{//创建一个新的页节点,并构建前后关联pp new_page = (pp)malloc(sizeof(p));new_page->n = i = 0;in_link(new_page, i, info, ti);new_page->last = tmp;new_page->next = NULL;tmp->next = new_page;tmp = new_page;new_page->n = i = 1;}}
    }//读取一页的信息并显示在窗口
    void read_data_new(pp pa)
    {int i = 0, j;清屏输出while (i < pa->n){输出pa第i行的数据i++;}
    }

  • 应用到主程序中,仍部分使用伪代码,由于涉及指针,所以用完后记得释放空间

  • else if (选择浏览本地游戏记录){对头指针初始化store_data();read_data_new(tmp);		while (1){in = _getch();if (in == 13)//利用双指针进行迭代,逐个释放空间{tmp = head;pp l = head->next;while (l || tmp){free(tmp);tmp = l;if(tmp)l = tmp->next;}break;}else if (in == 'w')//读上一页{if (tmp->last){tmp = tmp->last;read_data_new(tmp);}}else if (in == 's')//读下一页{if (tmp->next){tmp = tmp->next;read_data_new(tmp);}}}}

(4)未实现功能/待解决的问题

  1. 关于含bgm的版本

    本意是想在击打特定钢琴块时发出声音的,但由于beep函数本身占用CPU主进程,会导致界面得等声音发出结束后再继续更新,使游戏过程卡顿,这个可以尝试用threads.h库函数进行进程的分支,多线程操作,但是由于配置问题,没能成功安装该库,还有改进的空间

  2. 关于输入读取

    游戏只单纯地用了读取输入的_getch()函数,但遇到用户在短时间内输入大量内容,会使得缓冲区字符堆积,影响后续对用户输入的及时体验,目前未能找到一个较好的解决方法

五、运行结果

 

六、总结

第一次尝试做游戏,能在写函数的过程中,体会到与以往C语言编程、做题不一样的编程风格,也能将自己所学的数据结构知识用于其中解决一些实际问题,收获颇丰,更感受到了做软件的不易和工程量之大,首次尝试在界面上、游戏体验上仍存在着很多的不足,以及改进的空间,希望未来能学得更多,在编程之路上越走越远!

七、参考文章

[1] C++如何定义多个文件使用全局变量_hugongda123的专栏-CSDN博客_多文件全局变量怎么定义

[2] 控制台光标(一): 隐藏光标_nocomment_84的博客-CSDN博客_隐藏控制台光标

[3] getch()功能与用法_YuJar的专栏-CSDN博客_getch()的功能

[4] 函数kbhit()是干什么的?_百度知道

在此鸣谢帮孩子内测的uu们,以及各位优秀的csdn博主们(还有隔壁软编助教23333,整的那个中国象棋的板子很有参考性)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/353351.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

用unity做的简单小游戏------“小球酷跑“

游戏介绍: 游戏由小球和障碍物组成&#xff0c;在所布置的游戏背景中进行游戏&#xff0c;如图所示。 游戏主要以控制小球移动躲过障碍物继续行走为玩法&#xff0c;是一个简单的不够完整的小游戏&#xff0c;下面将会简单地介绍在unity中如何制作出这个小游戏。 场景设置: 先…

C++ 字符跑酷#1 游戏制作实录

版本号&#xff1a;1.0 我是~~~oneNBmetel&#xff01;&#xff01;&#xff01;我知道metel错了但我懒得改&#xff08;逃 我们今天来做&#xff01;一个简简单单的C跑酷游戏&#xff01;&#xff01;&#xff01; 首先&#xff0c;既然是做游戏&#xff0c;那头文件是必不…

C++ 字符跑酷#4 游戏制作实录

版本号&#xff1a;1.3 嗨&#xff0c;我是一块铌金属 上次的字符酷跑&#xff0c;我做完之后&#xff0c;还是觉得不太满意&#xff0c;正好&#xff0c;题刷完了&#xff0c;作业也做完了&#xff0c;那就……做游戏吧 但是&#xff0c;在我刚想开一个新坑的时候&#xff…

Java单元测试学习(一)

Java单元测试学习&#xff08;一&#xff09; 使用TestContainer和docker结合启动redis 前提 docker环境 目录结构 依赖—这里有个小插曲 配置RedisTemplate时一直报错Error creating bean with name ‘redisConnectionFactory’ defined in class path resource [org/spr…

地震勘探基础(八)之地震动校正

地震动校正 在地震资料数字处理过程中&#xff0c;速度分析&#xff0c;动校正和水平叠加三个处理内容是相互关联的。水平叠加是为了提高地震资料的信噪比&#xff0c;要想得到好的叠加效果&#xff0c;必须做好动校正。而做好动校正&#xff0c;需要进行准确的速度分析。只有…

独立站卖家如何应对PayPal风险?3大策略教你安全收款!

PayPal是全球风险控制做得最好的第三方在线支付平台&#xff0c;PayPal付款是钱直接到卖家PayPal账户。但随着外贸交易的日益发展&#xff0c;恶意买家的问题也越来越多。如何防范风险&#xff0c;保证收款安全&#xff0c;成为独立站卖家们所关注的问题。下面为大家分享三种策…

pyhon的运算符和字符串格式化方式

pyhton的变量类型 这里可以值得一提的是&#xff0c;python是一种弱类型的语言&#xff0c;使用的感觉有些像C的auto变量类型&#xff0c;定义变量不需要写类型名字&#xff0c;只需要变量名就会自动匹配 # int a 10 # float b 10.333 # string c "nihao" # dic…

oracle自定义函数 for in loop示例

1、新建type&#xff0c;就是返回结果集有什么&#xff0c;这里就写什么&#xff08;相当于表的字段&#xff09; CREATE OR REPLACE TYPE "TYPE_NQ_FORM_STATISTICS" as object (recordid varchar2(500),form_name varchar2(200),sortone varchar2(100),sorttwo …

辨别MagicKeyboard的真伪(序列号验证版)

RT 楼主前两天海鲜市场买了一个magic Keyboard, 大概是这个样子的 起来感觉没啥差别&#xff0c;橙色也蛮好。 今天某位大佬告诉我鉴别真假的方法&#xff0c;看了之后我心都凉了 写出来给大家避避坑 将键盘用连接到Mac电脑上&#xff0c;打开系统报告&#xff0c;看USB下面的…

WinMerge使用

1、介绍&#xff1a;是一款运行于Windows系统下的免费开源的文件比较/合并工具&#xff0c;使用它可以非常方便地比较多个文档内容甚至是文件夹与文件夹之间的文件差异。 2、对于测试人员的作用&#xff1a;可以用来比较测试数据内容&#xff0c;如在进行回归测试报表数据的时…

windows系统上使用magic trackpad妙控触摸板

windows系统上使用magic trackpad妙控触摸板 另外出自用全新 jd自营随时可以全保换新 jd自营购买的 apple magic trakpad 妙控板 还有保险 随时可换新 前言 最近在家学习很少打游戏&#xff0c;想了一下翻出了我箱子里我之前mac mini用的trackpad&#xff0c;因为我之前的笔…

magic-api 框架使用

概述 先说一下为什么选择这个框架,在搬砖过程中百分之八十的代码是增删改查操作,复杂的逻辑只是占了不多部分,这个框架能够使简单增删改查的时间大大减少. magic-api 是一个基于Java的接口快速开发框架&#xff0c;编写接口将通过magic-api提供的UI界面完成&#xff0c;自动映…

Git for windows 和 cygwin

git for windows 根目录和安装目录 C:\Program Files\Gitcygwin 根目录和安装目录 C:\cygwin64建议环境变量设置. cygwin使用gitFW的命令 cygwin下装 vim插件 cygwin 配置 在当前目录打开cygwin(存在无法在中文路径下打开目录的问题) 计算机\HKEY_CLASSES_ROOT\Director…

WINCE KITL工具

KITL(Kernel Independent Transport Layer)是基于Windows CE平台的一种软件技术&#xff0c;开发商基于它可以很容易地支持各种调试功能。因为WindowsCE的调试是一种远程调试&#xff0c;所以开发工作站&#xff08;运行PB的机器&#xff09;和设备端必须要有相应的通信通道&am…

Windows--cygwin

原文网址&#xff1a;Windows--cygwin_IT利刃出鞘的博客-CSDN博客 写在前头的话 cygwin只是模拟一个Linux环境&#xff0c;使用它无法进入Windows系统的盘的路径&#xff0c;个人认为不如git bash好用。 下载 Cygwin InstallationIndex of /cygwin/Index of /cygwin/ 安装 …

如何获取 C#程序 内核态线程栈

一&#xff1a;背景 1. 讲故事 在这么多的案例分析中&#xff0c;往往会发现一些案例是卡死在线程的内核态栈上&#xff0c;但拿过来的dump都是用户态模式下&#xff0c;所以无法看到内核态栈&#xff0c;这就比较麻烦&#xff0c;需要让朋友通过其他方式生成一个蓝屏的dump&…

win7配置magic mouse和keyboard

记录一下我是如何在win7下配置magic mouse 和keyboard的。 首先打开笔记本的蓝牙&#xff0c;然后进入到控制面板&#xff0c;找到添加设备。 键盘很好添加&#xff0c;当屏幕显示一串数字时&#xff0c;到键盘上去按对应的数字键就行了。 让我意外的鼠标的配置&#xff0c;…

NYOJ 348 Magic

题目链接&#xff1a;http://acm.nyist.net/JudgeOnline/problem.php?pid348 题意&#xff1a;给你n张牌&#xff0c;让你变一个魔术&#xff1a;第1次把上面的1张牌放到底部&#xff0c;然后最上面的牌就是1&#xff0c;然后拿走1。第2次把上面的2张牌依次放到底部&#xff…

D. Magic Gems

http://codeforces.com/contest/1117/problem/D 题意&#xff1a;n&#xff0c;m(1e18) &#xff1b;有一些魔法石&#xff0c;一个魔法石可以分裂成m个普通宝石&#xff0c;每个宝石站一个单位空间&#xff1b;问有多少集合使得站n个空间&#xff1b; 思路&#xff1a; #inc…

以全能之力造非凡旗舰:荣耀Magic3系列新品发布

8月12日&#xff0c;标志性全能科技旗舰荣耀Magic3系列新品正式发布&#xff0c;荣耀Magic3、荣耀Magic3 Pro、荣耀Magic3至臻版三款机型集中亮相。 融合秩序美学、高端材质、美妙破晓时刻&#xff0c;造就非凡设计&#xff1b;延续荣耀AI与影像优势&#xff0c;首次将电影工业…