一、前言
最近在阅读《unix-linux编程实践教程》,这本书很适合学习完Linux基础编程后想码点东西实践的朋友。它主要是通过带领读者学习编写Linux系统中常用的命令(ls、more等)来巩固基础知识。本人从中收获颇丰,在这里推荐给各位想学习Linux系统编程的朋友。下载路径:https://download.youkuaiyun.com/download/q1449516487/10724621
二、掷骰子游戏
1.curses库(图形函数库)
(1)这个游戏运用到了curses库,它是一个在Linux/Unix下广泛应用的图形函数库.,作用是可以绘制在终端下的用户界面和漂亮的图形。
(2)安装方法:sudo apt-get install libncurses5-dev
(3)重要函数
函数 | 功能 |
---|---|
initscr() | 初始化curses库和ttty (在开始curses编程之前,必须使用initscr()这个函数来开启curses模式) |
endwin() | 关闭curses并重置tty (结束curses编程时,最后调用的一个函数) |
move(y,x) | 将游标移动至 x,y 的位置 |
getyx(win,y,x) | 得到目前游标的位置(请注意!是 y,x 而不是&y,&x) |
clear() and erase() | 将整个萤幕清除(请注意配合refresh() 使用) |
echochar(ch) | 显示某个字元 |
addch(ch) | 在当前位置画字符ch |
mvaddch(y,x,ch) | 在(x,y) 上显示某个字元。相当於呼叫move(y,x);addch(ch); |
addstr(str) | 在当前位置画字符串str |
mvaddstr(y,x,str) | 在(x,y) 上显示一串字串。相当於呼叫move(y,x);addstr(str); |
printw(format,str) | 类似 printf() ,以一定的格式输出至萤幕 |
mvprintw(y,x,format,str) | 在(x,y) 位置上做 printw 的工作。相当於呼叫move(y,x);printw(format,str); |
getch() | 从键盘读取一个字元。(注意!传回的是整数值) |
getstr() | 从键盘读取一串字元。 |
scanw(format,&arg1,&arg2...) | 如同 scanf,从键盘读取一串字元。 |
beep() | 发出一声哔声 |
box(win,ch1,ch2) | 自动画方框 |
refresh() | 使屏幕按照你的意图显示。比较工作屏幕和真实屏幕的差异,然后refresh通过终端驱动送出那些能使真实屏幕于工作屏幕一致的字符和控制码。(工作屏幕就像磁盘缓存,curses中的大部分的函数都只对它进行修改) |
standout() | 启动standout模式(一般使屏幕发色) |
standend() | 关闭standout模式 |
2.时间间隔器
(1)使用到时间间隔器,主要的作用是让电脑自动掷骰子。该时间间隔期的本质是一个时钟信号,我们通过设定间隔时间,内核在到达我们设定的时间时就会向进程发送一个时钟信号,进而程序调用操作函数实现功能。(信号也可以理解为我们熟悉的中断)
(2)操作函数
函数 | int getitimer(int which, struct itimerval *curr_value); | |
---|---|---|
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); | ||
变量 | which | ITIMER_REAL:这个计时器计量真实事件,如同手表记录时间。也就是说不管程序在用户态还是核心态用了多少处理器时间它都记录。当这个计时器用尽,发送SIGALRM消息。 |
ITIMER_VIRTUAL:这个计时器只有进程在用户态运行时才计时。虚拟计时器的30s比实际计时器的30s要长。当虚拟计时器用尽,发送SIGVTALRM消息。 | ||
ITIMER_PROF:这个计时器在进程运行于用户态或由该进程调用而陷入核心态时计时。当这个计时器用尽时,发送SIGPROF消息。 | ||
new_value | it_value:初始时间(第一次执行的时间间隔) | |
it_interval:重复间隔 | ||
old_value | 用于获取已存在的时钟。 |
3.掷骰子游戏的构想
首先这是一个单机游戏,通过curses库来绘制图形,时钟信号来充当电脑的角色。开始游戏后玩家和电脑都有本金100元,每局下注的金额为固定的10元,通过规则会有1倍、3倍和5倍的赔率。
牌型 | 五倍牌:三颗骰子都相同 |
---|---|
三倍牌:三骰子为顺序排(123、234等) | |
普通牌:除五倍和三倍以外的牌型 | |
游戏规则 | 大倍率的牌型胜过小倍率的牌型 |
牌型相同时,点数大的胜出 |
4.代码
(1)主函数(main.c)
/*main.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curses.h>
#include "GameLib.h"
#include "dice.h"
#include "unistd.h"
extern Player player; //玩家
extern Computer computer; //电脑
extern Umpire umpire; //裁判
int main()
{
int c;
char str[10];
dice_init(); //游戏初始化
while((c = getchar()) != 'Q')//按键输入
{
if(c == 'r' && player.status == NoReady) //玩家每局游戏刚开始的时候状态为未准备,输入'r'表示准备完毕
{
player.status = Ready;
WriteStr(PLAYER_STATUS_X,PLAYER_STATUS_Y,strlen(BLANK),BLANK);
WriteStr(PLAYER_STATUS_X,PLAYER_STATUS_Y,strlen(READY),READY);
refresh();
}
else if(player.status == Ready && c == ' ')//玩家每按一下空格键代表摇一个骰子
{
if(!player.dice1.dice_flag)player.dice1.dice_flag = 1; //骰子1的标志,置1表示骰子数值确定
else if(!player.dice2.dice_flag)player.dice2.dice_flag = 1; //骰子2的标志,置1表示骰子数值确定
else if(!player.dice3.dice_flag)player.dice3.dice_flag = 1; //骰子3的标志,置1表示骰子数值确定
//当三个骰子都确定后,玩家的状态为操作完毕
if(player.dice1.dice_flag &&
player.dice2.dice_flag &&
player.dice3.dice_flag)
{
player.status = Finish;
WriteStr(PLAYER_STATUS_X,PLAYER_STATUS_Y,strlen(BLANK),BLANK);
WriteStr(PLAYER_STATUS_X,PLAYER_STATUS_Y,strlen(FINISH),FINISH);
}
}
money_rule();//判断输赢
if(player.status == Game_Win)//玩家胜利
{
ClearSCR(1,5,SCR_X/2-1,SCR_Y-11);
ClearSCR(SCR_X/2+1,5,SCR_X/2-1,SCR_Y-11);
ClearSCR(SCR_X*1/4+1,SCR_Y-7+3,SCR_X/2,7-3);
WriteStr(PLAYER_GR_X,PLAYER_GR_Y,strlen(GAME_WIN),GAME_WIN);
WriteStr(COMPUTER_GR_X,COMPUTER_GR_Y,strlen(GAME_FAIL),GAME_FAIL);
WriteStr(SCR_X/2,SCR_Y-3,12,"'Q' to exit");
refresh();
stop_shake();
}
else if(player.status == Game_Fail)//玩家失败
{
ClearSCR(1,5,SCR_X/2-1,SCR_Y-11);
ClearSCR(SCR_X/2+1,5,SCR_X/2-1,SCR_Y-11);
ClearSCR(SCR_X*1/4+1,SCR_Y-7+3,SCR_X/2,7-3);
WriteStr(PLAYER_GR_X,PLAYER_GR_Y,strlen(GAME_FAIL),GAME_FAIL);
WriteStr(COMPUTER_GR_X,COMPUTER_GR_Y,strlen(GAME_WIN),GAME_WIN);
WriteStr(SCR_X/2,SCR_Y-3,12,"'Q' to exit");
refresh();
stop_shake();
}
//当玩家和电脑都准备好时,裁判状态为开始
if(player.status == Ready && computer.status == Ready)
{
umpire.status = Start;
WriteStr(UMPIRE_STATUS_X,UMPIRE_STATUS_Y,strlen(BLANK),BLANK);
WriteStr(UMPIRE_STATUS_X,UMPIRE_STATUS_Y,strlen(GAME_START),GAME_START);
refresh();
}
//裁判状态为结束时,表示游戏结束,并重置各变量
if(umpire.status == Over)
{
umpire.status = NoReady;
player.dice1.dice_flag = 0;
player.dice2.dice_flag = 0;
player.dice3.dice_flag = 0;
player.status = NoReady;
computer.dice1.dice_flag = 0;
computer.dice2.dice_flag = 0;
computer.dice3.dice_flag = 0;
computer.status = NoReady;
computer.ready_ttg = computer.ready_ttm;
DrawDice(player.dice1.pos_x,player.dice1.pos_y,'#','?');
DrawDice(player.dice2.pos_x,player.dice2.pos_y,'#','?');
DrawDice(player.dice3.pos_x,player.dice3.pos_y,'#','?');
DrawDice(computer.dice1.pos_x,computer.dice1.pos_y,'#','?');
DrawDice(computer.dice2.pos_x,computer.dice2.pos_y,'#','?');
DrawDice(computer.dice3.pos_x,computer.dice3.pos_y,'#','?');
WriteStr(PLAYER_RESULT_X,PLAYER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(COMPUTER_RESULT_X,COMPUTER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(PLAYER_TOTAL_X,PLAYER_TOTAL_Y,strlen(BLANK),BLANK);
WriteStr(COMPUTER_TOTAL_X,COMPUTER_TOTAL_Y,strlen(BLANK),BLANK);
WriteStr(UMPIRE_STATUS_X,UMPIRE_STATUS_Y,strlen(BLANK),BLANK);
WriteStr(PLAYER_STATUS_X,PLAYER_STATUS_Y,strlen(NOREADY),NOREADY);
WriteStr(COMPUTER_STATUS_X,COMPUTER_STATUS_Y,strlen(NOREADY),NOREADY);
}
//当玩家和电脑都操作完毕后,计算本局输赢
if(player.status == Finish && computer.status == Finish)
{
dice_rule();//计算输赢并计算金钱收益
if(player.status == Win)//玩家本局胜利
{
if(player.dice_status == Ordinary)//普通牌型
{
WriteStr(PLAYER_RESULT_X,PLAYER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(PLAYER_RESULT_X,PLAYER_RESULT_Y,strlen(WIN),WIN);
WriteStr(COMPUTER_RESULT_X,COMPUTER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(COMPUTER_RESULT_X,COMPUTER_RESULT_Y,strlen(FAIL),FAIL);
}
else if(player.dice_status == Three_Times)//三倍
{
WriteStr(PLAYER_RESULT_X,PLAYER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(PLAYER_RESULT_X,PLAYER_RESULT_Y,strlen(THREE_TIMES),THREE_TIMES);
WriteStr(COMPUTER_RESULT_X,COMPUTER_RESULT_Y,strlen(TBLANK),TBLANK);
WriteStr(COMPUTER_RESULT_X,COMPUTER