版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Tc2.0编写俄罗斯方块游戏 很多编程爱好者都编写过俄罗斯方块的游戏程序。很久以前,我用Tc2.0也做过一个;最近 有好些朋友看见我以前的俄罗斯方块的程序后,问我是怎么做的。我一直想把这个程序的整个过程写一份详细的东西,与各位编程爱好者分 享,一直没空。正好现在放假了,而且离回家还有几天。于是我就把这个程序重新写了一遍, 尽量使程序的结构比较清晰好懂一些。同时写了下面的这份东西。俄罗斯方块游戏的程序中用到了一些方法。为了比较容易理解这些方法,我在讲述的同 时写了些专门针对这些方法的示例程序。这些示例程序力求短小,目的是用最小的代码能够 清楚的示例所用的方法。这些示例程序都经过tc2.0测试。最
2、后还附了完整的俄罗斯方块游 戏的源代码,和最终的可执行程序。如果你看了这份东东,有什么意见和想法,请发电子邮 件告诉我。我将会继续更新这分东东,最新的版本可以在我的个人主页上下载。下面的问题是有关俄罗斯方块程序的,其中有些是朋友问我的,有些是我认为可能会被 问到的。我尽量按问题从易到难排列这些问题。关于俄罗斯方块程序的一些问题: 个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个Tc2.0中怎么样设置图形显示?Tc2.0中常用图形函数的用法? 怎样获取金建盘输入? 怎样控制方块的移动?怎样控制时间间隔(用于游戏中控制形状的下落)?游戏中
3、的各种形状及整个游戏空间怎么用数据表示?游戏中怎么判断左右及向下移动的可能性?游戏中怎么判断某一形状旋转的可能性?按向下方向键时加速某一形状下落速度的处理?怎么判断某一形状已经到底?怎么判断某一已经被填满?怎么消去已经被填满的一行?怎么消去某一形状落到底后能够消去的所有的行?(如长条最多可以消去四行) 怎样修改游戏板的状态?怎样统计分数?怎样处理升级后的加速问题?怎样判断游戏结束?关于计分板设计的问题。关于“下一个,形状取法的问题。剩下的问题。 个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个个新的问题:我想有一个最高记录的显示,应该怎
4、么做呀?我想实现一个进度存储功能,应该怎么做呀?Tc2.0中怎么样设置图形显示?Tc2.0中有两种显示模式,一种是我们所熟知的字符模式,另一种是图形模式。在字符 模式下只能显式字符,如ASCII字符。一般是显示25行,每行80个字符。程序缺省的是字符模式。在字符模式下不能显式图形和进行绘图操作。 要想进行图形显示和绘图操作,必须切换到图形模式下。Tc2.0中用initgraph()函数可以切换到图形模式,用closegraph()可以从图形模式切 换回字符模式。initgraph()和closegraph()都是图形 函数,使用图形函数必须包括头文件”graphics.h”。void far
5、initgraph(int far *graphdriver,int far *graphmode,char far *pathtodriver);graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在 graphdriver选定后,指向图形显示模式序号变量的指针。pathtodriver表示存放图形驱动 文件的路径。Tc2.0中有多种图形驱动,每种图形驱动下又有几种图形显示模式。在我的程序中图形 驱动序号为VGA,图形显示模式序号为VGAHI0这是一种分辨率为640*480(从左到右坐标依 次为0-639,从上到下坐标依次为0-479),能够显示16种颜色的图形模式。
6、别的图形驱动序 号和图形显示模式序号,可以从手册或联机帮助中找到。pathtodriver指示存放图形驱动文件的路径。图形驱动序号不同,图形驱动文件也不同。 序号为VGA图形驱动对应egavga.bgi”这个图形驱动文件。egavga.bgi”一般在Tc目录下。void far closegraph(void);没有参数,从图形模式直接返回字符模式。initgraph()和closegraph()的常用用法如下: int gdriver = VGA, gmode=VGAHI, errorcode;/* initialize graphics mode */initgraph(&gdriver,
7、 &gmode, e:tc2);/* read result of initialization */ errorcode = graphresult();if (errorcode != grOk) /* an error occurred */printf(Graphics error: %sn”, grapherrormsg(errorcode);printf(Press any key to halt:);getch();exit(1); /* return with error code */ /* return to text mode */closegraph();Tc2.0中常
8、用图形函数的用法?在这里讲几个游戏中用到的绘图用的图形函数:setcolor();line();rectangle();settextjustify();outtextxy();setfillstyle();bar();void far setcolor(int color);设置画线、画框和在图形模式下显示文字的当前颜色。这个函数将影响line()、rectangle()和outtextxy()函数绘图的颜色。color可以取常的颜色常量:BLACK ? 0BLUE ? 1GREEN ? 2CYAN ? 3RED ? 4MAGENTA ? 5BROWN ? 6LIGHTGRAY ? 7DAR
9、KGRAY ? 8LIGHTBLUE ? 9LIGHTGREEN ?10LIGHTCYAN ?11LIGHTRED ?12LIGHTMAGENTA ?13YELLOW ?14WHITE ?15void far line(int x1,int y1,int x2,int y2);用当前颜色从(x1,y1)画一条到(x2,y2 )的线段。void far rectangle(int left,int top,int right,int bottom);用当前颜色画一个左上角为(left,top)、右下角为(right,bottom)的矩形框。void far settextjustify(int
10、horz,int vert);设置图形模式下文字输出的对齐方式。主要影响outtextxy()函数。horiz和vert可取如下枚举常量:horiz ?LEFT_TEXT ? 0 ?Left-justify text?CENTER_TEXT ? 1 ?Center text?RIGHT_TEXT ? 2 ?Right-justify textvert ?BOTTOM_TEXT ? 0 ?Justify from bottom?CENTER_TEXT ? 1 ?Center text?TOP_TEXT ? 2 ?Justify from topvoid far outtextxy(int x,i
11、nt y,char * textstring);在(x,y)处用当前字体(缺省的字体是DEFAULT_FONT)显示字符串textstring,字符串的对齐 方式由 settextjustify()指定。void far setfillstyle(int pattern,int color);设置图形的填充模式和填充颜色,主要影响bar()等函数。pattern 一般取枚举常量值 SOLID_FILL,color 的取值与 setcolor(int color)中 color 的取 值范围相同。介绍完了前面两个问题,现在来写一个程序。这个程序演示前了面所介绍的几个图形函 数。程序 progl.
12、c怎样获取金建盘输入?在Tc2.0中有一个处理键盘输入的函数bioskey();int bioskey(int cmd);当cmd为1时,bioskey()检测是否有键按下。没有键按下时返回0;有键按下时返回按 键码(任何按键码都不为0),但此时并不将检测到的按 键码从键盘缓冲队列中清除。当cmd为0时,bioskey()返回键盘缓冲队列中的按键码,并将此按键码从键盘缓冲队列 中清除。如果键盘缓冲队列为空,则一直等到有键按 下,才将得到的按键码返回。Escape键的按键码为0 x11b,下面的小程序可以获取按键的按键码。for (;)key=bioskey(0); /* wait for a
13、keystroke */printf(0 x%xn”,key);if (key=0 x11b) break; /* Escape */常用按键的按键码如下:#define VK_LEFT 0 x4b00#define VK_RIGHT 0 x4d00#define VK_DOWN 0 x5000#define VK_UP 0 x4800#define VK_HOME 0 x4700#define VK_END 0 x4f00#define VK_SPACE 0 x3920#define VK_ESC 0 x011b#define VK_ENTER 0 x1c0d完整的程序请参见prog2.c、
14、prog3.c。prog2.c获取按键的按键码,按Escape键退出程序。prog3.c根据不同的按键进行不同的操作,按Escape键退出程序。怎样控制方块的移动?方块移动的实现很简单,将方块原来的位置用背景色画一个同样大小的方块,将原来的 方块涂去。然后在新的位置上重新绘制方块就可以了。这样就实现了方块的移动。完整的程序请参见prog4.c。这个用方向键控制一个黄色的 小方块在屏幕上上、下、左、右移动。这个程序用到了前面几个问题讲的内容,如果你有点 忘了,还要回头看看哦。:)怎样控制时间间隔(用于游戏中控制形状的下落)?解决这个问题要用到时钟中断。时钟中断大约每秒钟发生18.2次。截获正常的
15、时钟中断 后,在处理完正常的时钟中断后,将一个计时变量加1。这样,每秒钟计时变量约增加18。需要控控制时间的时候,只需要看这个计时变量就 行了。截获时钟中断要用到函数getvect()和setvect()。两个函数的声明如下:?void interrupt (*getvect(int interruptno)();?void setvect(int interruptno, void interrupt (*isr)();保留字interrupt指示函数是一个中断处理函数。在调用中断处理函数的时候,所有的 寄存器将会被保存。中断处理函数的返回时的指令是iret,而不是一般函数用到的ret指令。
16、getvect()根据中断号interruptno获取中断号为interruptno的中断处理函数的入口地址。setvect()将中断号为interruptno的中断处理函数的入口地址改为isr()函数的入口地址。 即中断发生时,将调用isr()函数。在程序开始的时候截获时钟中断,并设置新的中断处理。在程序结束的时候,一定要记 着恢复时钟中断哦,不然系统的计时功能会出问题的。具体演示程序请参见prog5.c。由于中断处理大家可能用的不多,所以我把prog5.c这 个程序完整地贴在下面,并加上详细的解释。/* prog5.c */This is an interrupt service rout
17、ine. You can NOT compile this program with Test Stack Overflow turned on and get an executable file which will operate correctly. */*这个程序每隔1秒钟输出一个整数,10秒钟后结束程序。 按escape键提前退出程序。*/#include#include#include/* Escape key */#define VK_ESC 0 x11b#define TIMER 0 x1c /*时钟中断的中断号*/*中断处理函数在C和C+中的表示略有不同。如果定义了_cpl
18、usplus则表示在C+环境下,否则是在C环境下。*/#ifdef _cplusplus#define _CPPARGS .#else#define _CPPARGS#endifint TimerCounter=0; /*计时变量,每秒钟增加18。*/*指向原来时钟中断处理过程入口的中断处理函数指针(句柄)*/ void interrupt ( *oldhandler)(_CPPARGS);/* 新的时钟中断处理函数 */void interrupt newhandler(_CPPARGS) /* increase the global counter */TimerCounter+;/* c
19、all the old routine */ oldhandler();/*设置新的时钟中断处理过程*/void SetTimer(void interrupt (*IntProc)(_CPPARGS)oldhandler=getvect(TIMER);disable(); /*设置新的时钟中断处理过程时,禁止所有中断*/ setvect(TIMER,IntProc);enable(); /* 开启中断 */*恢复原有的时钟中断处理过程*/void KillTimer()disable();setvect(TIMER,oldhandler);enable();void main(void)in
20、t key,time=0;SetTimer(newhandler); /* 修改时钟中断 */for (;)if (bioskey(1)key=bioskey(0);if (key=VK_ESC) /* 按 escape 键提前退出程序 */printf(User cancel!n);break;if (TimerCounter18) /* 1 秒钟处理一次 */*恢复计时变量*/TimerCounter=0;time+;printf(%dn”,time);if (time=10) /* 10秒钟后结束程序*/printf(Program terminated normally!n); bre
21、ak;KillTimer(); /*恢复时钟中断*/游戏中的各种形状及整个游戏空间怎么用数据表示?以后我提到的形状都是指下面七种形之一及它们旋转后的变形体。我定义了一个结构来表示形状。struct shapeint xy8;int color;int next;-1 0 1 2-3口口口-2口口口-】0口口口所有的各种形状都可以放在4x4的格子里。假定第二列,第四行的格子坐标为(0,0)(如 上图中黑块所示),则每个形状的四个方块都可以用4个数对来表示。坐标X从左向右依次增加,y从上到下依次增加。表示的时候,组成该形状 的四个方块从左到右,从上到下(不一定非要按这个顺序)。如上面七种形状的第一
22、个用数对来表示就是(-2,0)、(-1,0)、(0,0)、(1,0)。结构shape 中的xy就是用来表示这4个数对的。为了简化程序,用一维数组xy8来表示。xy0、xy1 表示第一个数对,xy2、xy3表示第二个数对,依次类推。shape中的color表示形状的颜色,不同的形状有不同的颜色。七种形状及它们旋转后 的变形体一共有19种形状,用一个全局数组表示。假定旋转的方向是逆时针方向(顺时针方 向道理一样)。shape中的next就表示当前形状逆时针旋转后的下一个形状的序号。例如: 第一种形状及其旋转变形的形状用结构表示如下。 struct shape shapes19=/*x1,y1,x2
23、,y2,x3,y3,x4,y4, color, next*/ 0,-2,0,-1,0, 0,1, 0, CYAN,1,/* */-1, 0,0, 0,1,-1,1, 0, CYAN,2,/* # */ 0,-2,1,-2,1,-1,1, 0, CYAN,3,/* # */-1,-1,-1, 0,0,-1,1,-1, CYAN,0,/* # */游戏空间指的是整个游戏主要的界面(呵呵,这个定义我实在想不出更准确的,还请哪位 大虾指点)。实际上是一个宽10格子、高20格子的游戏板。用一个全局数组board1222表示。表示的时候:boardxy为1时表示游戏板 上(x,y)这个位置上已经有方块占着
24、了,boardxy为0表示游戏板上这位置还空着。为了便于判断形状的移动是否到边、到底,初始的时候在 游戏板的两边各加一列,在游戏板的下面加一行,全部填上1,表示不能移出界。即board0y,board11y(其中y从0到21)初始都为1, boardx21(其中x从1到10)初始都为1。1 2 3 4 5 6 7 8 910】口口?口口3口口口口口口口口口口4口口口口口口口口口口5口口口口口口口口口口&口口口?口口8OOOOOOOOOO9OOOOOOOOOO10OOOOOOOOOO11OOOOOOOOOO12OOOOOOOOOO13OOOOOOOOOO14OOOOOOOOOO15OOOOOOO
25、OOO16OOOOOOOOOO17OOOOOOOOOO18OOOOOOOOOO19OOOOOOOOOO20OOOOOOOOOOprog6.c演示了用结构表示各种形状的方法。虽然程序稍长一些,但并不是特别复杂。其中游戏板初始化部分并没有真正用到,但是后面的程序会用到的。其中SIZE定义为16,这样将整个屏幕的坐标系由原来的640X480转换成40 X30(640/16=40, 480/16=30)。游戏中所有的坐标都是基于40X30的坐标系的,这样有助于 简化程序。坐标的转换在程序中由DrawBlock(int x,int y)来体现。新的坐标系如下图所示:-8-7-6-5-4-3-2-1 0
26、1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口-?口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口-1 。口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口2口口口口口口口口口口口口口口口口口口口口口口口口口口口口口3口口口口口口口口口口口口口口口口口口口口口口口口口4口口口口口口口口口口口口口口口口口口口口口口口口口5口口口口口口口口口口口口
27、口口口口口口口口口口口口口6口口口口口口口口口口口口口口口口口口口口口口口口口/o89101112131415161718192021 2223242526新坐标中最主要的是就是上面两块黑色的部分。左边那块大的就是游戏板(横坐标从1 到10,纵坐标从1到20),右边那块小的就是显示“下一个”形状的部分(横坐标从14到 17,纵坐标从3到6)。这个新的坐标系是整个游戏的基础,后面所有的移动、变形等的计算都是基于这个坐标系的。游戏中怎么判断左右及向下移动的可能性?看懂了前面的各种形状和游戏板等的表示,接下来的东西就都好办多了。先来看一下某 个形状如何显示在游戏板当中。假设要在游戏板中 显示第一个形
28、状。第一个形状在结构中的表示如下:struct shape shapes19=/*x1,y1,x2,y2,x3,y3,x4,y4, color, next*/ 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1,那么这个组成形状四个方块的坐标表示为(0,-2)、(0,-1)、(0,0)和(1,0)。这实际上是 相对坐标。假形状的实际坐标指的是4x4方块中的第二列、第三行的方块的位置,设这个位置为(x,y)。那么组成这个形状的四个小方块的实际坐 标(以第一个形状为例)就是(x+0,y-2)、(x+0,y-1)、(x+0,y+0)和(x+1,y+0)。由于所有的 形状都可以在4x4的方
29、块阵列中表示,这样就找到了一种统一的方法来表示所有的形状了。-1 0 1 2-3口口口 相对坐标-2口口-】组成第一种形状的四个方块的相对坐标为(0,-2)、(0,-1)、(0,0)和(1,0)。0口口让我们看看形状是如何显示在游戏板中的(以第一个形状为例)。1 2 3 4 5 6 7 8 910】口口口形状的坐标为(2,3)。组成形状的四个方块的坐标由形状的2口口口口口口口口口坐标加上这四个小方块各自的相对坐标得出。它们分别是:3口口口口口口口口(2+0,3-2)、(2+0,3-1)、(2+0,3-0)和(2+1,3-0)。即:4口口口口口口口口口口(2,1)、(2,2)、(2,3)和(3,
30、3)。如左图所示。5口口口口口口口口口口&口口口7口口口口口口口口口形状的坐标为(1,9)。组成形状的四个方块的坐标分别是:8口口口口口口口口(1+0,9-2)、(1+0,9-1)、(1+0,9-0)和(1+1,9-0)。即:9口口口口口口口口(1,7)、(1,8)、(1,9)和(2,9)。如左图所示。口口口11口口口口口口口口口口12OOOOOOOOOO13OOOOOOOOOO14OOOOOOOOOO15OOOOOOOOOO16OOOOOOOOOO17OOOOOOOOOO18OOOOOOOOBO形状的坐标为(9,20)。组成形状的四个方块的坐标分别是: 口(9+0,20-2)、(9+0,20
31、-1)、(9+0,20-0)和(9+1,20-0)。即: 20OOOOOOOOBB (9,18)、(9,19)、(9,20)和(10,20)。如左图所示。从现在起,我不再举别的示例程序了。从现在开始所有的示例代码均来自于我写的 Russia.c”。为了记录游戏板的状态,用了一个全局数组board1222。boardxy(其 中x从0到11,y从1到21)等于1表示(x,y)这个位置已经被填充了,组成形状的四个方 块的坐标都不能为(x,y),否则将发生冲突。boardxy(其中x从1到10,y从1到20) 等于表示(x,y)这个位置还没有被填充。游戏板初始化时,给board0y,board11y
32、(其中y从1到21)都赋为1,给 boardx21(其中x从1到10)都赋为1。这相当于一开始就给游戏板左右和下方加了个 “边”。所有的形状都不能够移入这个“边”,否则将发生冲突。现在我们可以开始讨论如何判断一个形状向左、向右和向下移动的可能性了。先说个概 念,“当前形状”是指那个正在下落还没有落到底的那个形状。如果当前形状向左移动,不与 游戏板现有状态发生冲突,则可以向左移动。具体做法是:先假设当前形状已经向左移动了, 判断此时是否与游戏板现有状态发生冲突。如果不发生冲突,则可以向左移动。否则,不可 以向左移动。判断索引号为ShapeIndex的形状在坐标(x,y)是否与游戏板当前状态发生冲
33、突的代码如 下。我把详细的说明加在这段代码中。enum bool Confilict(int ShapeIndex,int x,int y) int i;/*对组成索引号为ShapeIndex的形状的四个方块依次判断*/for (i=0;i=7;i+,i+) /* i 分别取 0,2,4,6 */ /*如果四个方块中有任何一个方块的x坐标小于1或大于10,表示超出左边界或右边界。 此时,发生冲突。 */if (shapesShapeIndex.xy+x10) return True;/*如果四个方块中某个方块的y坐标小于1,表示整个形状还没有完全落入游戏板中。 此时,没有必要对这个方块进行判断
34、。*/if (shapesShapeIndex.xyi+1+y1) continue;/*如果四个方块中有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y)处 与游戏板当前状态冲突*/if (boardshapesShapeIndex.xy+xshapesShapeIndex.xyi+1+y) return True;/*四个方块中没有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y)处 没有与游戏板当前状态冲突*/ return False;对以上代码附加说明如下:shapesShapeIndex.xy (其中i等于0,2,4,6)表示组成索引号为ShapeIndex的形
35、状 的某个方块的x相对坐标。(i等于0时,表示第1个方块的x相对坐标;i等于2时,表示 第2个方块的x相对坐标;i等于4时,表示第3个方块的x相对坐标;i等于6时,表示第 4个方块的x相对坐标。)shapesShapeIndex.xy (其中i等于1,3,5,7)表示组成索引号为ShapeIndex的形状 的某个方块的y相对坐标。(i等于1时,表示第1个方块的y相对坐标;i等于3时,表示 第2个方块的y相对坐标;i等于5时,表示第3个方块的y相对坐标;i等于7时,表示第 4个方块的y相对坐标。)shapesShapeIndex.xy+x (其中 i 等于 0,2,4,6)表示索引号为 ShapeIndex 的形状的 坐标为(x,y)时,组成该形状的某个方块的x实际坐标。(i等于0时,表示第1个方块的x 实际坐标;i等于2时,表示第2个方块的x实际坐标;i等于4时,表示第3个方块的x 实际坐标;i等于6时,表示第4个方块的x实际坐标。)shapesShapeIndex.xy+y (其中 i 等于 1,3,5,7)表示索引号为 ShapeIndex 的形状的 坐标为(x,y)时,组成该形状的某个方块的y实际坐
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年湘潭技师学院高职单招职业适应性测试考试模拟试卷及参考答案详解(达标题)
- 2027年天柱山职业学院高职单招职业技能考试题库及答案详解【网校专用】
- 2025年河北承德双桥职业学院单招综合素质考试模拟试卷含答案详解【完整版】
- 2025年昆嵛山职业学院高职单招职业技能考试题库附参考答案详解(预热题)
- 2025年查干湖职业学院单招综合素质考试题库【原创题】附答案详解
- 2026年娄底职业技术学院高职单招职业技能考试题库及答案详解一套
- 2027年四川省攀枝花市高职单招职业技能考试模拟试卷附答案详解(研优卷)
- 2024年陕西三秦职业学院单招综合素质考试题库及答案详解【各地真题】
- 2027年湘楚专修学院高职高职单招职业技能考试题库附参考答案详解【模拟题】
- 2025年湘西文旅职业学院单招综合素质考试题库附参考答案详解(综合题)
- 2025-2026学年福建省厦门一中八年级(上)期中数学试卷
- 废弃化粪池回填施工方案
- DB11T 1080-2014 硬泡聚氨酯复合板现抹轻质砂浆外墙外保温工程施工技术规程
- 人事行政部门工作流程
- 光伏运维合同模板(3篇)
- 《老年社会工作》全套教学课件
- 浙江省宁波市海曙区2024-2025学年八年级下学期语文期末考试试卷
- 2025吉林长春国资委直属单位公开招聘试题含答案
- 浇花阅读理解答案
- CJ/T 340-2016绿化种植土壤
- 售电公司业务管理制度
评论
0/150
提交评论