一、题目
1.1 要求
运用C语言数学运算库函数及easyx图形编程库函数编写一个掷色子游戏程序。
1.2 知识
掌握C语言的语法、语义、基础数据类型、数字、指针、结构体、联合体、文件等的基本概念;掌握ANSI C标准库的字符串、文件、数学运算、标准输入输出、日期时间、资源管理等基本库函数并能熟练运用。建立程序设计开发和算法设计的基本思维方式,充分利用网络开源资源,逐步掌握C语言的高级编程技巧。
1.3 能力
熟练运用当前流行的C/C++开发工具如Visual C++进行程序设计;熟练掌握并运用ANSI C的标准库解决相关问题;建立算法和程序设计的基本思维模式,熟练运用搜索工具和开源资源解决程序设计过程中存在的问题,培养解决复杂工程问题的能力,针对具体问题提出有效的解决方案,增强高级程序设计的能力;在交叉知识的讨论中培养创新意识,提高分析、发现、研究和解决问题的能力。
1.4 素质
以熟练使用相关开发工具、运用标准及扩展库为基础,具备从问题到算法抽象建模的独立思维素质;具备抽取问题核心本质,利用搜索引擎,从互联网获取相关开发资源的素质;通过课程中的分析讨论,培养沟通交流及相互协作的素质;通过课外导学的模式,提升自主学习和终身学习的意识,形成不断学习和适应发展素质。
二、 设计思路
2.1 需求分析
- 基本原理
运用随机数对六取余再加一的算法模拟掷色子的过程,运用电脑产生的随机数模拟现实生活中投掷色子的过程。 - 基本功能
首先玩家选择 Big or Small(押大小)并输入赌注金额,完成后电脑摇三个骰子(产生三个随机数)并计算总值,总值大于等于11小于等于18为“大”,总值大于等于3小于等于10为“小”。告诉玩家押对或是押错,玩家初始金额是 1000 元,赔率为1倍。玩家可以模拟现实生活中摇色子的过程。 - 数据流图
2.2 总体设计
- 总体结构
a) 开始界面:主要由“开始游戏”按钮和“规则介绍”按钮两部分构成,还可以选择背景音乐是否播放,为游戏的开始界面
b) 游戏界面:主要由三个骰子构成主界面,右侧四分之一为玩家余额以及系统提示语
c) 规则介绍界面:主要介绍游戏规则,点开即弹出 - 模块关系
玩家点开游戏后进入开始界面,开始界面下设游戏界面以及规则介绍界面,游戏界面与规则介绍界面并列,均可返回开始界面。 - 总体流程
先进入开始游戏界面,玩家先点击“规则介绍”按钮了解游戏流程,再返回开始界面,点击“开始游戏”按钮开始游戏。开始游戏后,玩家先选择big或者small,并输入赌注金额,之后界面显示三个骰子的大小以及总和,系统提示赌局结果,并重新显示玩家余额。
2.3 详细设计
- 开始界面
运用图形库函数,鼠标可点击区域有三个,分别为“开始游戏”按键区域,“游戏规则”按键区域,以及音乐播放图标区域。三个区域点击后对应的操作分别为,打开游戏界面,打开规则介绍界面,控制音乐停止与播放。 - 游戏界面
左边为三个骰子的图片,图片下方先不显示数字,右上角为玩家余额显示,每进行一轮游戏更新显示一次,右下角为系统提示语:“你赢了xx金币!太机智了!”或者“你输了xx金币!太笨了!”。玩家进入后先在提示框中选择大小,再输入赌注金额,系统进行随机数抽取,后在骰子图片下方显示骰子大小及总数,在右侧显示系统提示语,并实现金额变更。界面右上角有关闭按键,返回开始游戏界面 - 规则介绍界面
为开始游戏界面上方的一个悬浮框,右上角有关闭游戏按键,可关闭此悬浮框。此悬浮框主要显示内容为“游戏规则——玩家首先选择 Big or Small(押大小),选择完成后玩家输入赌注金额;之后系统开始摇三个骰子并计算总值,总值大于等于11小于等于18为“大”,总值大于等于3小于等于10为“小”;玩家初始金额是 1000 元,赔率为1倍。”
三、实现代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h> //使用srand((unsigned int) time(NULL)) 和 rand() 产生随机数
#include <easyx.h> //使用图形库函数(包含windows.h的头文件)
#include <conio.h> //使用_getch()函数
#include <mmsystem.h> //包含多媒体设备接口头文件(播放音乐)
#include <graphics.h>
#pragma comment(lib,"winmm.lib")//加载静态库(播放音乐)
#define win_width 900
#define win_height 500
char money[10] = "1000"; //玩家初始余额
int begin(void)
{
//设置一个背景色并以背景色清屏
setbkcolor(RGB(191, 181, 227));
cleardevice();
int botton[2][4] = { {600,250,150,50} , {600,330,150,50} };//界面上两个按钮的位置
//输入并加载背景图片
IMAGE img;
loadimage(&img, "./背景.jpg", win_width, win_height);//or窗口适应图片大小:int width = img.getwidth();
putimage(0, 0, &img);
//在背景图片上显示“开始游戏”的botton、“游戏规则”的botton
setlinecolor(BLACK); //线条颜色
setfillcolor(RGB(81, 191, 219)); //填充颜色
setlinestyle(PS_SOLID, 2); //线条样式
fillroundrect(botton[0][0], botton[0][1], botton[0][0] + botton[0][2], botton[0][1] + botton[0][3], 10, 10);
fillroundrect(botton[1][0], botton[1][1], botton[1][0] + botton[1][2], botton[1][1] + botton[1][3], 10, 10);
//将文字在botton里居中显示
settextcolor(RGB(40,62,89));
setbkmode(TRANSPARENT);
settextstyle(35, 0, "华文行楷");
char s1[] = "开始游戏";
int width1 = botton[0][0] + botton[0][2] / 2 - textwidth(s1) / 2;
int height1 = botton[0][1] + botton[0][3] / 2 - textheight(s1) / 2;
outtextxy(width1, height1, s1);
char s2[] = "游戏规则";
int width2 = botton[1][0] + botton[1][2] / 2 - textwidth(s2) / 2;
int height2 = botton[1][1] + botton[1][3] / 2 - textheight(s2) / 2;
outtextxy(width2, height2, s2);
//鼠标点击操作
ExMessage msg;
int ret = 0;
while (true) {
if (peekmessage(&msg, EM_MOUSE)) {
if (msg.x >= width1 && msg.x <= width1 + 150 && msg.y >= height1 && msg.y <= height1 + 50)
{
//消息分发
if (msg.message == WM_LBUTTONDOWN) {
printf("开始游戏被左击了");
ret = 2;
break;
}
}
if (msg.x >= width2 && msg.x <= width2 + 150 && msg.y >= height2 && msg.y <= height2 + 50)
{
//消息分发
if (msg.message == WM_LBUTTONDOWN) {
printf("游戏规则被左击了");
ret = 1;
break;
}
}
}
}
return ret;
}
int introduce(void)
{
//画一个圆角矩形装说明文字
setlinecolor(BLACK);
setfillcolor(RGB(112,142,190));
setlinestyle(PS_SOLID, 3);
fillroundrect(100,100,800,400,20,20);
//关闭按钮
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(50, 40, "黑体");
outtextxy(760, 100, "X");
//说明文字
settextcolor(RED);
setbkmode(TRANSPARENT);
settextstyle(40, 0, "幼圆");
char title[] = "游戏规则";
outtextxy(450 - textwidth(title) / 2, 120, title);
char line1[] = " 玩家首先选择 Big or Small(押大小),选";
char line2[] = "择完成后玩家输入赌注金额;之后系统开始摇三";
char line3[] = "个骰子并计算总值,总值大于等于11小于等于18";
char line4[] = "为“大”,总值大于等于3小于等于10为“小”;";
char line5[] = "玩家初始金额是 1000 元,赔率为1倍。";
settextcolor(RGB(40, 62, 89));
setbkmode(TRANSPARENT);
settextstyle(30, 0, "华文新魏");
outtextxy(140 , 180, line1);
outtextxy(140 , 220, line2);
outtextxy(140 , 260, line3);
outtextxy(140 , 300, line4);
outtextxy(140 , 340, line5);
//鼠标点击操作
ExMessage msg;
int ret = 0;
while (true) {
if (peekmessage(&msg, EM_MOUSE)) {
if (msg.x >= 750 && msg.x <= 800 && msg.y >= 100 && msg.y <=150)
{
//消息分发
if (msg.message == WM_LBUTTONDOWN) {
printf("关闭按钮被左击了");
break;
}
}
}
}
return ret;
}
int play(void)
{
//设置一个背景色并以背景色清屏
setbkcolor(WHITE);
cleardevice();
//将白色背景分区
setlinecolor(RGB(40, 62, 89)); //线条颜色
setlinestyle(PS_SOLID, 5); //线条样式
line(675, 0, 675, 500); //竖分割线
line(675, 200, 900, 200); //横分割线
//输入并加载骰子图片
IMAGE dice;
loadimage(&dice, "./骰子.jpg", 150, 150);
putimage(50, 150, &dice);
putimage(225, 150, &dice);
putimage(400, 150, &dice);
//显示关闭按钮
settextcolor(RGB(40, 62, 89));
setbkmode(TRANSPARENT);
settextstyle(50, 40, "黑体");
outtextxy(625, 0, "X");
//显示继续游戏按钮
settextcolor(RED);
setbkmode(TRANSPARENT);
settextstyle(25, 0, "楷体");
outtextxy(680, 450, "继续游戏");
//显示重新游戏按钮
settextcolor(RGB(40, 62, 89));
setbkmode(TRANSPARENT);
settextstyle(25, 0, "楷体");
outtextxy(790, 450, "重新游戏");
//右上角显示"当前余额"
settextcolor(RED);
setbkmode(TRANSPARENT);
settextstyle(30, 0, "楷体");
outtextxy(730, 50, "当前余额");
//右上角显示余额数值
setlinecolor(BLACK); //线条颜色
setfillcolor(RGB(112, 142, 190)); //填充颜色
setlinestyle(PS_SOLID, 3); //线条样式
fillroundrect(685, 120, 890, 180, 10, 10);//宽205,高60
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(50, 0, "黑体");
int width = 685 + 205 / 2 - textwidth(money) / 2;
int height = 120 + 60 / 2 - textheight(money) / 2;
outtextxy(width, height, money);
//弹出消息框,让玩家选择押大押小
int flag = 1; //默认玩家选择押大,压小则为0
HWND m_hWnd = GetHWnd();
if (MessageBox(m_hWnd, ("是否选择押大?"), ("押大小"), MB_ICONQUESTION | MB_YESNO) == IDNO) { flag = 0;}
//弹出消息框,让玩家输入赌注金额
char s[10];
InputBox(s,30,"请输入赌注金额(不超过一千万)");
Sleep(1000);
//显示三个骰子的随机结果
char show[3];
int outcome[3] = { 0 }, sum = 0;
int i = 0;
srand((unsigned int)time(NULL));
for (i = 0; i < 3; i++) {
outcome[i] = rand() % 6 + 1;
sum += outcome[i];
show[i] = outcome[i] + '0';
}
IMAGE dice1, dice2, dice3, dice4, dice5, dice6;
loadimage(&dice1, "./一点.jpg", 150, 150);
loadimage(&dice2, "./二点.jpg", 150, 150);
loadimage(&dice3, "./三点.jpg", 150, 150);
loadimage(&dice4, "./四点.jpg", 150, 150);
loadimage(&dice5, "./五点.jpg", 150, 150);
loadimage(&dice6, "./六点.jpg", 150, 150);
settextcolor(RGB(40, 62, 89));
setbkmode(TRANSPARENT);
settextstyle(50, 0, "幼圆");
switch (outcome[0]) {
case 1: putimage(50, 150, &dice1); break;
case 2: putimage(50, 150, &dice2); break;
case 3: putimage(50, 150, &dice3); break;
case 4: putimage(50, 150, &dice4); break;
case 5: putimage(50, 150, &dice5); break;
case 6: putimage(50, 150, &dice6); break;
}
outtextxy(125 - textwidth(show[0]) / 2, 400, show[0]);
Sleep(1000);
switch (outcome[1]) {
case 1: putimage(225, 150, &dice1); break;
case 2: putimage(225, 150, &dice2); break;
case 3: putimage(225, 150, &dice3); break;
case 4: putimage(225, 150, &dice4); break;
case 5: putimage(225, 150, &dice5); break;
case 6: putimage(225, 150, &dice6); break;
}
outtextxy(300 - textwidth(show[1]) / 2, 400, show[1]);
Sleep(1000);
switch (outcome[2]) {
case 1: putimage(400, 150, &dice1); break;
case 2: putimage(400, 150, &dice2); break;
case 3: putimage(400, 150, &dice3); break;
case 4: putimage(400, 150, &dice4); break;
case 5: putimage(400, 150, &dice5); break;
case 6: putimage(400, 150, &dice6); break;
}
outtextxy(475 - textwidth(show[2]) / 2, 400, show[2]);
Sleep(1000);
//在右下角显示提示语
if (flag == 1 && sum >= 11 || flag == 0 && sum <= 10)
{
settextcolor(RGB(128, 0, 0));
setbkmode(TRANSPARENT);
settextstyle(40, 0, "华文行楷");
outtextxy(720, 250, "你赢了!");
outtextxy(700, 310, "太机智了!");
}
else
{
settextcolor(RGB(128, 0, 0));
setbkmode(TRANSPARENT);
settextstyle(40, 0, "华文行楷");
outtextxy(720, 250, "你输了!");
outtextxy(720, 310, "太笨了!");
}
//******************************************************************
//更新余额(将字符串转化为数字)
Sleep(1000);
int money_s = 0;//整形的现有余额
int s_s = 0; //整形的赌注金额
int t = 1;
int n = strlen(money);
for (i = n - 1; i >= 0; i--) { //将字符串转化成整形的原有余额
money_s += (money[i] - '0') * t;
t *= 10;
}
n = strlen(s);
t = 1;
for (i = n - 1; i >= 0; i--) { //将字符串转化成整形的赌注金额
s_s += (s[i] - '0') * t;
t *= 10;
}
//更新余额(计算新的余额)
if (flag == 1 && sum >= 11 || flag == 0 && sum <= 10) money_s += s_s;
else money_s -= s_s;
//更行余额(将新余额转化为字符串)
if(money_s==0) strcpy_s(money, sizeof(money) / sizeof(money[0]), "0");
else
{
if (money_s > 0) flag = 0;
else {
flag = 1;
money[0] = '-';
money_s = -money_s;
}
for (i = flag; money_s > 0; i++) {
money[i] = money_s % 10 + '0';
money_s /= 10;
}
money[i] = '\0';
}
//倒序字符串
char tmp;
n = strlen(money);
if (flag == 0) {
for (i = 0; i < n / 2; i++) {
tmp = money[i];
money[i] = money[n - i - 1];
money[n - i - 1] = tmp;
}
}
else {
for (i = 1; i <= n / 2; i++) {
tmp = money[i];
money[i] = money[n - i ];
money[n - i ] = tmp;
}
}
//更行余额(显示新余额)
setlinecolor(BLACK); //线条颜色
setfillcolor(RGB(112, 142, 190)); //填充颜色
setlinestyle(PS_SOLID, 3); //线条样式
fillroundrect(685, 120, 890, 180, 10, 10); //宽205,高60
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(50, 0, "黑体");
width = 685 + 205 / 2 - textwidth(money) / 2;
height = 120 + 60 / 2 - textheight(money) / 2;
outtextxy(width, height, money);
//*************************************************************
//如果余额不足
if (flag == 1)
{
//显示你负债了
setlinecolor(BLACK); //线条颜色
setfillcolor(RGB(112, 142, 190)); //填充颜色
setlinestyle(PS_SOLID, 3); //线条样式
fillroundrect(250, 150, 650, 350, 10, 10); //宽400,高200
settextcolor(RED);
setbkmode(TRANSPARENT);
settextstyle(50, 0, "华文行楷");
width = 450 - textwidth("你负债了!") / 2;
height = 200 - textheight("你负债了!") / 2;
outtextxy(width, height, "你负债了!");
width = 450 - textwidth("请及时止损!!") / 2;
height = 300 - textheight("请及时止损!!") / 2;
outtextxy(width, height, "请及时止损!!");
//退出游戏
Sleep(3000);
strcpy_s(money, sizeof(money) / sizeof(money[0]), "1000");
return 0;
}
//鼠标点击操作
ExMessage msg;
int ret = 0;
while (true) {
if (peekmessage(&msg, EM_MOUSE)) {
//玩家选择退出
if (msg.x >= 625 && msg.x <= 675 && msg.y >= 0 && msg.y <= 50 && msg.message == WM_LBUTTONDOWN)
{
printf("关闭按钮被左击了");
strcpy_s(money, sizeof(money) / sizeof(money[0]), "1000");
ret = 0;
break;
}
//玩家选择继续游戏
if (msg.x >= 680 && msg.x <= 790 && msg.y >= 450 && msg.y <= 500 && msg.message == WM_LBUTTONDOWN)
{
printf("继续游戏按钮被左击了");
ret = 2;
break;
}
//玩家鼠标选择重新游戏
if (msg.x >= 790 && msg.x <= 900 && msg.y >= 450 && msg.y <= 500 && msg.message == WM_LBUTTONDOWN)
{
printf("重新游戏按钮被左击了");
strcpy_s(money, sizeof(money) / sizeof(money[0]), "1000");
ret = 2;
break;
}
}
}
return ret;
}
void BGM()
{
//打开音乐,播放音乐
//alias 取别名
//repeat 重复播放
mciSendString("open ./背景音乐.mp3 alias BGM", 0, 0, 0);
mciSendString("play BGM repeat", 0, 0, 0);
if (false)
{
mciSendString("close BGM", 0, 0, 0);
}
}
int main()
{
//打开一个图像窗口并显示命令行窗口
//EW_SHOWCONSOLE显示命令行窗口
initgraph(win_width, win_height);
//播放背景音乐
BGM();
//获取窗口句柄并设置窗口标题
HWND hnd = GetHWnd();
SetWindowText(hnd, "掷色子小游戏");
int screen = begin();
while (true)
{
if (screen == 1) screen = introduce();
else if (screen == 2) screen = play();
else screen = begin();
}
//按任意键关闭
char c = getchar();
//关闭图像窗口
closegraph();
return 0;
}