当前位置:   article > 正文

C语言贪吃蛇课程设计实验报告(包含贪吃蛇项目源码)_贪吃蛇大作战课题简述

贪吃蛇大作战课题简述

文末有贪吃蛇代码全览,代码有十分细致的注释!!!
文末有贪吃蛇代码全览,代码有十分细致的注释!!!
文末有贪吃蛇代码全览,代码有十分细致的注释!!!

码文不易,给个免费的小星星和免费的赞吧,关注也行呀(⑅•͈ᴗ•͈).:*♡ 

不要白嫖哇(⁍̥̥̥᷄д⁍̥̥̥᷅ ू )伤心

目录

1 课题分析 

1.1研究背景与现状

1.2研究意义与研究步骤

2 设计概述

2.1 项目具体内容

2.2 系统框图

2.2.1程序结构图

2.2.2游戏流程图

2.2.3查看规则界面流程图

2. 系统模块划分

3 详细设计说明

3.1 主菜单界面设计说明

3.1.1 设计说明

3.1.2 功能展示

3.2 查看规则界面设计说明

3.2.1 设计说明

3.2.2 功能展示

3.3 开始游戏界面设计说明

3.3.1 设计说明

3.3.2 功能展示

4 结论


 

设计题目: 贪吃蛇大作战

设计内容与要求:

设计内容:

使用C语言编程,设计出贪吃蛇游戏功能。其中该项目主要分为三个界面,分别是菜单界面,规则界面和游戏主体界面。

创新点: 将蛇身单一颜色变为随游戏进程变化的彩虹色,修改速度机制和分数奖励机制,新增鼠标交互式菜单,增强游戏体验。

设计要求:

通过游戏设计巩固C语言知识,合理规范书写函数并正确调用。运用easyx增加拓展性内容,理解所使用函数的方法。

设计中遇到报错及时调试分析,查阅资料,对同一功能进行多方法比较使用,确保代码正确,正常运行。

指导教师:

年 月 日

1 课题分析 


1.1研究背景与现状

随着计算机行业迅速发展,也涌现了多种热门编程语言,作为使用十分广泛的高级程序设计语言,C语言程序开发学习尤为重要,其绘图能力强,可移植性,具有强大数据处理能力的特点,适于编写系统软件、图形和动画。

当今游戏成为时下比较流行的一种消遣方式,贪吃蛇这款游戏正好符合大众心理,适应人群广泛,具有很强的娱乐性和交互性,可以丰富人们娱乐时间。

贪吃蛇作为一款小游戏,运行简单,易上手,游戏机制的刺激性强,能引人入胜,爱不释手,且相较于大型游戏的长时间消耗,贪吃蛇对碎片化娱乐时间更具有合理性,可以做到简单易行,满足人们需求。

本文主要目的为研究并设计C语言贪吃蛇游戏,利用EasyX Graphics Library免费绘图库实现游戏画面,函数设计与调用,制定游戏规则与运行机制,并在Windows控制台主机输出画面,实现游戏运行。

1.2研究意义与研究步骤

研究意义:

在快节奏社会中,人们时间更加紧凑,娱乐休闲时间也显得十分紧促,在大型游戏受众范围广的情况下,轻游戏和快游戏更紧贴胃口,在碎片化时间里让用户得到更满足的快节奏娱乐体验。

通过贪吃蛇小游戏,人们不仅可以在休闲时间娱乐,还可以在游戏中记录自己的分数记录,在一次次挑战中提升自我,游戏的用意也是告诉人们不断向前,突破自我,向着目标前行才能取得成功。同时,研究C语言课程设计,编写贪吃蛇游戏,可以锻炼思维,熟悉代码运用,有利于为未来项目开发积累经验,全面发展。

研究步骤:

(1)设计: 游戏最重要的是界面显示设计,要考虑游戏窗体大小,文字内容提示,让用户在打开游戏过程中有良好的运行体验,明确每个功能的作用与游戏操作。其次是设计流畅良好的键鼠操作,让玩家有更良好的交互反馈。

(2)游戏程序测试是关键步骤。每增加一个游戏功能函数,就要对其进行实例测试,确保代码无报错、贪吃蛇运行过程无误、游戏界面无不良输出。并在键鼠交互保证其流畅性和稳定性,为用户提供良好的游戏体验。

2 设计概述


2.1 项目具体内容

该项目通过C程序语言以及EasyX Graphics Library绘图库设计出贪吃蛇游戏程序。其中该项目主要分为三个界面,分别是主菜单界面,规则界面和开始游戏界面。

通过主菜单界面我们可以进入开始游戏界面,通过鼠标交互点击按钮,即可开始游戏,游戏可实时计分。在查看规则界面可以看到贪吃蛇游戏规则设定,并查看游戏历史最高分。如果想退出游戏,便可在主菜单选择退出按钮结束程序运行。

2.2 系统框图

2.2.1程序结构图

贪吃蛇游戏程序主要由主菜单界面,游戏界面,规则界面和退出游戏界面构成如图2-1所示。

4b494c684320487ca7da8f9d09949a57.png

图2-1 程序结构图

2.2.2游戏流程图

游戏的主体由几个函数构成,分别为游戏初始化函数,画面显示函数,分数读写函数,交互函数,下面是游戏运行的流程图,如图2-2所示:

633104eaa664467e8cb673137a9f3bc0.png

图2-2 游戏流程图 

2.2.3查看规则界面流程图

查看规则界面由读取最高分、界面文字输出和鼠标按钮交互实现,定义结构体鼠标,判断其行为,如果不点击按钮,则处于规则界面不进行任何操作,如图2-3所示:

c85b4619525b4ac194eb55f4c0fb6b21.png

图2-3 规则界面流程图

 

2. 系统模块划分

课程项目设计中,贪吃蛇游戏主要分为三个界面,分别是菜单界面,规则界面和游戏主体界面。模块划分为主菜单模块、游戏初始化、画面显示、蛇移动模块、与键盘输入有关的更新(即键盘控制蛇的移动方向)、与输入无关的更新(移动速度控制),奖励机制、分数模块

在主菜单界面设计当中,我们通过easyx图形库来设计出按钮的选项,并对界面着色,通过监控鼠标左键的行为及鼠标点击位置来判断用户所选择的按钮选项,以此实现交互,完成界面跳转

当选择“开始游戏”选项,则进入游戏开始函数,进行游戏的初始化和最高分读取,对蛇及画面进行初始化,而后进入循环,当不满足游戏的失败条件,界面就会一直更新绘图,确保游戏的持续进行

其中在贪吃蛇游戏的速度机制和奖励机制分别做了改良,速度可以同时满足长按方向键加速前进,并且吃的食物越多,速度越快;分数奖励机制则满足一定的阈值限定,每当吃的食物达到一定程度,分数会以倍数增加,提高奖励分。

在游戏失败结算界面中,我们添加了分数显示,更直观地看到此局游戏中用户所得分数,而在分数模块,会进行txt文件读写操作,如果玩家分数大于最高分,则此局分数覆盖最高分。

 

3 详细设计说明


3.1 主菜单界面设计说明

3.1.1 设计说明

主菜单界面运用图形库的绘画功能,绘画出按钮矩形,并在按钮输出提示文字,让玩家理解其功能作用,并通过while函数时刻监控鼠标消息,当鼠标左键单击时,再进行if判断语句,当符合其中一个按钮的点击位置时,就进入该if语句中的函数,实现跳转功能

3.1.2 功能展示

主菜单界面如图3-1所示。

69a7eec0a0214c09815766f32ca98e10.png

图3-1 主菜单界面

3.2 查看规则界面设计说明

3.2.1 设计说明

查看规则界面功能:在查看规则界面中,玩家可以了解规则事项以及游戏涉及到的按键操作,同时在此界面显示最高分,让玩家有一个游戏目标,在了解相关规则后,玩家可以点击按钮返回主菜单,选择开始游戏或退出游戏。 

具体实现:实现的界面展示与主菜单一致,读取最高分则利用到编写的分数读写函数,把txt文件中的分数读取并显示于界面上

3.2.2 功能展示

查看规则界面如图3-2所示。

abc801551e254690a9b617d21a746b06.png

图3-2查看规则界面

3.3 开始游戏界面设计说明

3.3.1 设计说明

开始游戏界面功能:实现游戏的主体,绘画蛇、食物与游戏界面,键盘操作贪吃蛇移动吃食物,界面展示最高分,并随着进程进行,实时记录分数,当游戏结束时,弹出结算画面字样

具体实现:通过设置画布大小确定界面,并画横竖线把画布分为小方格,计算固定的像素值,把每个矩形方格都一一对应方格数组。在游戏初始化时遍历该数组来绘画蛇以及食物,此后每一次画面更新,都会遍历数组刷新蛇的长度和食物位置。

实时记录分数则通过定义一个int变量,根据分数机制增加对应数值,然后转化成char类型存入字符数组,再将其输出至画面。

游戏结算界面则通过判断蛇头所处位置,让全局变量改变数值,跳出游戏的循环,并输出相应文字。

3.3.2 功能展示

游戏界面如图3-3图3-4所示。

5fce5f7a149a4da5bf3b89c40cab6eb7.png

图3-3 游戏界面

06ad991a06b7439bad1abb8a994f0e04.png

 图3-4 游戏结算界面

 

4 结论


通过一个学期的C语言课程的学习,我与我的组员对c语言有了更深一步的了解。从一开始的什么都不会,自己一点点慢慢的摸索。发现书本上学到的东西还是很不够的,还有好多东西需要课外的学习。对于贪吃蛇,知道了它的实现原理,学会了对程序的模块设计、数据结构设计的简单分析。并通过源码分析讲述了各个模块的实现方法。在几个模块的实现过程中渗透了部分图形功能函数。通过本文的编写过程 ,掌握了以下几点知识点:

1.图形系统的初始化和关闭

2.各种画图函数的使用

3.结构体的定义

5.函数嵌套及调用

6.键盘操作

总的来说,编程还是一个很需要耐心的工作,特别是有bug找不出来的时候,特别需要我静下心来好好研究。很多时候都没有耐心改下去了。这次学习对我们组的耐心是一个极大的磨砺,收获还是蛮多的,在这次课程设计中我们巩固了C语言知识,学会了合理规范书写函数并正确调用,并且能够运用easyx增加拓展性内容,最重要的是发现了自己的不足之处。

我们接下来会再接再厉,不断实践,不断突破自己,争取做出更好的作品。

附录:

贪吃蛇程序如下:

  1. #include <graphics.h>
  2. #include <windows.h>
  3. #include <iostream>
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <cstdio>
  7. #define Width 40 //宽40格
  8. #define Height 30 //高30格
  9. #define Size 20 //格子大小:20
  10. int blocks[Width][Height] = {0}; //用以表示所有方格
  11. char moveDir; //表示运动方向
  12. char oldmove; //旧的移动方向
  13. int fx, fy; //food食物坐标
  14. int addspeed = 15; //控制初始速度
  15. int failure = 0; //用以判断游戏是否失败,失败赋值为 1
  16. int score = 0; //记录分数
  17. int max = 0; //记录最高分
  18. int k = 1; //奖励机制初始值
  19. char num[20]; //输出分数数组
  20. char best[20]; //最高分数组
  21. void initGame();
  22. void show(); //图像绘制更新显示函数
  23. void WithInput(); //与输入有关的更新
  24. void WithoutInput(); //与输入无关的更新
  25. void movesnake(); //蛇的移动函数
  26. void readscore(); //读取分数
  27. void writescore(); //写入分数
  28. void ShowWord(); //界面文字
  29. void drawmenu(); //主菜单
  30. void gamestart(); //开始游戏
  31. void seerule(); //查看规则
  32. void back(); //退出游戏
  33. int main() {
  34. drawmenu();
  35. return 0;
  36. }
  37. void initGame() {
  38. int i;
  39. initgraph(1000, 600); //①初始化绘图窗口,格子个数乘格子大小即为长度
  40. setbkcolor(CYAN); //设置背景颜色
  41. BeginBatchDraw(); //easyx中实现批绘图功能的函数,可以消除图像闪烁
  42. cleardevice(); //使用当前背景色清空绘图设备
  43. setlinecolor(WHITE); //划线颜色为白色
  44. for (i = Size; i < Width * Size+1; i += Size) { //用for循环绘制多条线
  45. line(i, 0, i, Height * Size); //竖线坐标从x1(i,0)-> y1(i,Height * Size)
  46. }
  47. for (i = Size; i < Height * Size; i += Size) {
  48. line(0, i, Width * Size, i); //横线坐标从x2(0,i) -> y2(Width * Size, i)
  49. }
  50. moveDir = oldmove = 'd'; //初始化默认蛇行进方向朝右
  51. blocks[Width / 2][Height / 2] = 1; /*正中间画蛇头,蛇为赋值的方格
  52. 0则为空白区域*/
  53. for (i = 1; i < 4; i++) {
  54. blocks[Width / 2 - i][Height / 2] = i + 1; //y坐标不变,更改x坐标,在蛇头后方画蛇身
  55. }
  56. srand(time(0)); //srand函数产生一个时间种子,从而达到真正的随机效果
  57. fx = rand() % (Width - 1) + 1; //随机数除39取余并+1,则为食物所生成的格子x坐标
  58. fy = rand() % (Height - 1) + 1; //随机数除取余并+1,则为食物所生成的格子y坐标
  59. }
  60. void show() {
  61. cleardevice();
  62. for (int i = 0; i < Width; i++) { //遍历所有方格,更新蛇的颜色
  63. for (int j = 1; j < Height; j++) {
  64. if (blocks[i][j] != 0) {
  65. setfillcolor(HSVtoRGB(blocks[i][j] * 10, 0.9, 1)); //HSV转RGB颜色,色调H 0°->360°,此处设置每长一个蛇身,提升10°色调,饱和度0.9,明度1
  66. }else{
  67. setfillcolor(CYAN); //否则更新为正常背景颜色
  68. }
  69. fillrectangle(i * Size, j * Size, (i + 1) * Size, (j + 1) * Size); //填充,(参数为左上角和右下角坐标)
  70. }
  71. }
  72. setfillcolor(LIGHTGREEN); //食物颜色
  73. fillrectangle(fx * Size, fy * Size, (fx + 1) * Size, (fy + 1) * Size);
  74. ShowWord();
  75. FlushBatchDraw(); /*BeginBatchDraw执行后,任何绘图操作都将暂时不输出到绘图窗口上
  76. 直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。*/
  77. }
  78. void ShowWord() {
  79. if (failure) {
  80. settextcolor(LIGHTRED); //设置字体颜色
  81. settextstyle(80, 0, _T("宋体")); //设置字体样式
  82. setbkmode(TRANSPARENT);
  83. outtextxy(240, 220, "游戏失败");
  84. settextstyle(40, 0, _T("宋体"));
  85. sprintf(num, "%d", score); //将int转换为char并存入num中
  86. outtextxy(260, 360, "分数:"); //显示的字体及坐标
  87. outtextxy(380, 360, num);
  88. }
  89. else { //②
  90. settextcolor(BLACK); //设置分数颜色
  91. settextstyle(25, 0, _T("隶书")); //设置字体样式
  92. setbkmode(TRANSPARENT); //设置当前设备图案填充和文字输出时的背景模式,THANSPARENT为透明背景
  93. sprintf(num, "%d", score); //将int转换为char并存入num中
  94. outtextxy(860, 40, "分数:"); //显示的字体及坐标
  95. outtextxy(940, 42, num);
  96. outtextxy(845, 73, "最高分:");
  97. sprintf(best, "%d", max);
  98. outtextxy(940, 75, best);
  99. }
  100. }
  101. void readscore() { //③
  102. FILE* fpread = fopen("score.txt", "r"); //以只读的方式打开文件
  103. if (fpread == NULL) {
  104. return;
  105. }
  106. fscanf(fpread, "%d", &max);
  107. fclose(fpread);
  108. }
  109. void writescore() {
  110. FILE* fpWrite = fopen("score.txt", "w"); //"w"打开并写入文本文件.(若不存在则新建,反之,则从头写,覆盖原内容)
  111. if (fpWrite == NULL) {
  112. return ;
  113. }
  114. fprintf(fpWrite, "%d", score);
  115. fclose(fpWrite);
  116. }
  117. void WithInput() {
  118. if (_kbhit() && failure == 0) {
  119. //键盘输入控制蛇的方向
  120. char input = _getch();
  121. if (input == 'a' || input == 's' || input == 'd' || input == 'w') {
  122. moveDir = input;
  123. //设定规则:当向某一方向行动时,按下反向键不起作用(防止误触导致判断为咬到蛇身游戏失败),强制将按下的反向键变为当前运动方向
  124. if (moveDir == 'a' && oldmove == 'd') {
  125. moveDir = 'd';
  126. }
  127. else if (moveDir == 's' && oldmove == 'w') {
  128. moveDir = 'w';
  129. }
  130. else if (moveDir == 'd' && oldmove == 'a') {
  131. moveDir = 'a';
  132. }
  133. else if (moveDir == 'w' && oldmove == 's') {
  134. moveDir = 's';
  135. }
  136. else {
  137. oldmove = input;
  138. }
  139. movesnake();
  140. }
  141. }
  142. }
  143. void WithoutInput() {
  144. if (failure) { //先判断是否失败,失败则返回
  145. return;
  146. }
  147. //Sleep(100); //更新速度控制蛇的移动速度,但使用sleep会产生键盘控制与画面的延迟,所以不使用
  148. //movesnake();
  149. static int speed = 1; //设置一个静态变量speed,利用循环特定次数来触发movesnake函数
  150. speed++;
  151. if (speed == addspeed) { //每15帧移动一次,同时实现长按方向键加快蛇的移动速度
  152. movesnake();
  153. speed = 1;
  154. }
  155. }
  156. void movesnake() {
  157. int i, j;
  158. //对蛇进行更新,蛇每个格数值都+1,以便后面预备一个数值为1的新蛇头,当吃到食物时,新蛇头改变颜色加入蛇身中
  159. for (i = 0; i < Width; i++) {
  160. for (j = 0; j < Height; j++) {
  161. if (blocks[i][j] != 0) {
  162. blocks[i][j]++;
  163. }
  164. }
  165. }
  166. int oldhx, oldhy, oldtx, oldty; //旧蛇头和旧蛇尾的坐标
  167. int tailblock = 0;
  168. for (i = 0; i < Width; i++) {
  169. for (j = 0; j < Height; j++) {
  170. if (tailblock < blocks[i][j]) {
  171. tailblock = blocks[i][j]; //遍历找出最大值即为蛇尾
  172. oldtx = i;
  173. oldty = j;
  174. }
  175. if (blocks[i][j]==2) { //寻找旧蛇头
  176. oldhx = i;
  177. oldhy = j;
  178. }
  179. }
  180. }
  181. //根据蛇的运动方向来赋值新蛇头的xy坐标
  182. int newhx = oldhx, newhy = oldhy; //定义新蛇头
  183. switch (moveDir) {
  184. case'a':
  185. newhx -= 1;
  186. break;
  187. case's':
  188. newhy += 1;
  189. break;
  190. case'd':
  191. newhx += 1;
  192. break;
  193. case'w':
  194. newhy -= 1;
  195. break;
  196. }
  197. //判断游戏是否失败
  198. if (newhx >= Width || newhx < 0 || newhy >= Height || newhy < 0 || blocks[newhx][newhy] != 0) {
  199. failure = 1;
  200. return;
  201. }
  202. //令蛇头方格值为1
  203. blocks[newhx][newhy] = 1;
  204. //对吃到食物以及蛇尾的处理 ⑤
  205. if (newhx == fx && newhy == fy) { //吃到食物,重新随机数生成新食物坐标
  206. score = score + k; //吃到食物分数+k
  207. if (score % 2 == 0) { //通过判断吃食物的数量来叠加奖励分
  208. k = k + 1;
  209. }
  210. if (score > max) { //与最高分判断,条件成立才能覆盖最高分
  211. writescore(); //写入最高分
  212. }
  213. //④
  214. if (score) { //“加速”判断,通过判断分数增大的取值,加快蛇的运动速度,score不为0时进入该判断语句
  215. if (score % 2 == 0) { //便于测试结果明显,设置每吃2个食物,蛇速度加快1帧
  216. addspeed--;
  217. }
  218. }
  219. fx = rand() % (Width - 1) + 1;
  220. fy = rand() % (Height - 1) + 1;
  221. }else{ //未吃到食物
  222. blocks[oldtx][oldty] = 0;
  223. }
  224. }
  225. void drawmenu() {
  226. MOUSEMSG m; //定义结构体鼠标m
  227. initgraph(600, 600); //定义画布大小
  228. setbkcolor(CYAN); //设置背景颜色
  229. cleardevice(); //使用当前背景色清空绘图设备,类似system(cls)的刷新
  230. setfillcolor(WHITE); //方框颜色
  231. fillrectangle(140, 50, 460, 170); //矩形左上角xy坐标和右下角xy坐标
  232. fillrectangle(120, 220, 480, 350); //矩形左上角xy坐标和右下角xy坐标
  233. fillrectangle(100, 400, 500, 540); //矩形左上角xy坐标和右下角xy坐标
  234. settextcolor(BLACK); //设置字体颜色
  235. settextstyle(50, 0, _T("楷体")); //设置字体格式
  236. setbkmode(TRANSPARENT); //去除文字背景
  237. outtextxy(200, 85, "开始游戏"); //文字输出位置的xy坐标
  238. outtextxy(200, 260, "查看规则");
  239. outtextxy(200, 445, "退出游戏");
  240. while (1) {
  241. m = GetMouseMsg(); //获取一个鼠标消息
  242. if (m.x >= 140 && m.x <= 460 && m.y >= 50 && m.y <= 170) { //判断鼠标点击的位置
  243. if (m.uMsg == WM_LBUTTONDOWN) { //当鼠标按下左键
  244. gamestart(); //开始游戏
  245. }
  246. }
  247. else if (m.x >= 120 && m.x <= 480 && m.y >= 220 && m.y <= 350) {
  248. if (m.uMsg == WM_LBUTTONDOWN) { //当鼠标按下左键
  249. seerule(); //查看规则
  250. }
  251. }
  252. else if (m.x >= 100 && m.x <= 500 && m.y >= 400 && m.y <= 540) {
  253. if (m.uMsg == WM_LBUTTONDOWN) { //当鼠标按下左键
  254. back(); //关闭菜单退出游戏
  255. }
  256. }
  257. }
  258. }
  259. void gamestart() {
  260. readscore(); //读取最高分
  261. initGame(); //游戏初始化
  262. while (1) { //循环进行界面实时刷新,直至游戏判定失败
  263. show(); //界面显示
  264. WithoutInput(); //先调用与输入无关的更新
  265. WithInput();
  266. }
  267. }
  268. void seerule() {
  269. MOUSEMSG m; //定义结构体鼠标m
  270. readscore(); //读取历史最高分
  271. initgraph(600, 600); //定义画布大小
  272. setbkcolor(CYAN); //设置背景颜色
  273. cleardevice(); //使用当前背景色清空绘图设备,类似system(cls)的刷新
  274. setfillcolor(WHITE); //方框颜色
  275. fillrectangle(100, 400, 500, 540); //矩形左上角xy坐标和右下角xy坐标
  276. settextcolor(BLACK); //设置字体颜色
  277. settextstyle(50, 0, _T("楷体")); //设置字体格式
  278. setbkmode(TRANSPARENT); //去除文字背景
  279. outtextxy(200, 445, "返回菜单");
  280. settextcolor(BLACK); //设置字体颜色
  281. settextstyle(30, 0, _T("楷体")); //设置字体格式
  282. setbkmode(TRANSPARENT); //去除文字背景
  283. outtextxy(45, 30, "WASD控制蛇移动,长按方向键可加速移动");
  284. outtextxy(45, 80, "碰到墙壁游戏失败");
  285. outtextxy(45, 130, "吃的食物越多,分数奖励越高");
  286. outtextxy(45, 180, "历史最高分:");
  287. sprintf(best, "%d", max);
  288. outtextxy(220, 180, best);
  289. while (1) {
  290. m = GetMouseMsg(); //获取一个鼠标消息
  291. if (m.x >= 100 && m.x <= 500 && m.y >= 400 && m.y <= 540) {
  292. if (m.uMsg == WM_LBUTTONDOWN) { //当鼠标按下左键
  293. drawmenu(); //返回主菜单
  294. }
  295. }
  296. }
  297. }
  298. void back() {
  299. closegraph(); //关闭画面
  300. exit(0); //退出程序
  301. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/505793
推荐阅读
相关标签
  

闽ICP备14008679号