linux下基于ncurses的扫雷程序

        刚写完一个扫雷程序,linux下基于ncurses。
        程序中使用 a, s, w, d控制光标分别向左、上、右、下移动,
                   使用 j 挖开雷坑,k标记雷坑中有雷,用红色表示,l标记不确定是否安全的雷坑,
                   并开一个线程专门负责接收用户输入
                                           图片
        源代码如下:
 
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include <semaphore.h>

int leiqu[20][20] = {0}; //雷区,20行20列
int leiquOpened[20][20] = {0};  //记录游戏者对每个雷坑的操作
// 0:未打开  1:已被打开 2:标记为雷3:标记为不确定
int lieNum = 100;   //100颗雷
int pos_cursor_X = 10,pos_cursor_Y = 10;//光标的位置
sem_t bin_sem;    //信号量
bool Isalive = 1;   //游戏是否还活着,1表示还活着,0表示死掉了

//初始化雷区
bool initleiqu()
{
//在雷区随机埋下100颗雷
int n1,n2;
for(int i = 1;i<= lieNum;)
{
n1 = (int) (20 * (rand()/(RAND_MAX+1.0)));
n2 = (int) (20 * (rand()/(RAND_MAX+1.0)));
if(leiqu[n1][n2] == 0)
{
leiqu[n1][n2] = -1;
i++;
// printf("%d;%d\n",n1,n2);
}
else 
continue;
}
//计算每个安全位置周围有多少颗雷
for(int j = 0;j<20;j++)
{
for(int k = 0;k<20;k++)
{
int a = 0;
if(leiqu[j][k] == 0)
{
if(j == 0)
{
if(k == 0)
a = ( (leiqu[j+1][k] == -1 ? 1:0) + (leiqu[j][k+1] == -1 ? 1:0) + (leiqu[j+1][k+1] == -1 ? 1:0) );
if(k>0 && k<19)
a = ( (leiqu[j][k-1] == -1 ? 1:0) + (leiqu[j][k+1] == -1 ? 1:0) + (leiqu[j+1][k-1] == -1 ? 1:0) +
       (leiqu[j+1][k] == -1 ? 1:0) + (leiqu[j+1][k+1] == -1 ?1:0));
if(k==19)
a = ( (leiqu[j][k-1] == -1 ? 1:0) + (leiqu[j+1][k-1] == -1?1:0) + (leiqu[j+1][k]==-1 ? 1:0)); 
}
if(j>0 && j<19)
{
if(k == 0)
a = ( (leiqu[j-1][k] == -1 ? 1:0) + (leiqu[j-1][k+1] == -1?1:0) + (leiqu[j][k+1] == -1 ? 1:0) +
       (leiqu[j+1][k+1]==-1 ? 1:0) + (leiqu[j+1][k] == -1?1:0));
if(k>0 && k<19)
a = ( (leiqu[j-1][k-1]==-1 ? 1:0) + (leiqu[j-1][k] == -1?1:0) + (leiqu[j-1][k+1] == -1 ? 1:0) + (leiqu[j][k+1] == -1 ? 1:0) +
       (leiqu[j+1][k+1]== -1? 1:0) + (leiqu[j+1][k] == -1?1:0) + (leiqu[j+1][k-1] == -1 ? 1:0) + (leiqu[j][k-1] == -1 ? 1:0));
if(k == 19)
a = ( (leiqu[j-1][k] == -1 ? 1:0) + (leiqu[j-1][k-1] == -1?1:0)+ (leiqu[j][k-1] == -1 ? 1:0) +
       (leiqu[j+1][k-1]==-1 ? 1:0) + (leiqu[j+1][k] == -1 ?1:0));
}
if(j == 19)
{
if(k == 0)
a = ( (leiqu[j-1][k] == -1 ? 1:0) + (leiqu[j-1][k+1] == -1? 1:0) + (leiqu[j][k+1] == -1 ?1:0));
if(k>0 && k<19)
a = ( (leiqu[j][k-1] == -1 ? 1:0) + (leiqu[j-1][k-1] == -1? 1:0) + (leiqu[j-1][k] == -1 ?1:0) +
       (leiqu[j-1][k+1] == -1 ?1:0)+ (leiqu[j][k+1] == -1? 1:0));
if(k == 19)
a = ( (leiqu[j][k-1] == -1 ? 1:0) + (leiqu[j-1][k-1] == -1?1:0) + (leiqu[j-1][k] == -1 ?1:0));
}
leiqu[j][k] = a;
}
else 
continue;
}
}
}

//确定所指位置文本的颜色
void colorOfposition(int posX,int posY)
{
switch(leiquOpened[posX][posY])
{
case 0:attrset(COLOR_PAIR(3));break;
case 1:attrset(COLOR_PAIR(2));break;
case 2:attrset(COLOR_PAIR(1));break;
case 3:attrset(COLOR_PAIR(5));break;
}
}

//显示雷区
void showLeiqu()
{
for(int i = 0 ; i < 20 ; i++)
for(int j = 0 ; j < 20 ; j++)
{
colorOfposition(i,j);
mvprintw(i,j,leiquOpened[i][j] != 1?" ":"%d",leiqu[i][j]);
}
}

//显示光标位置
void showCursor()
{
static int twinkle_cursor = 1;
switch(twinkle_cursor)
{
case 1:attrset(COLOR_PAIR(4));break;
case 2:colorOfposition(pos_cursor_X,pos_cursor_Y);break;
}
mvprintw(pos_cursor_X,pos_cursor_Y,leiquOpened[pos_cursor_X][pos_cursor_Y] != 1?" ":"%d",leiqu[pos_cursor_X][pos_cursor_Y]);
twinkle_cursor = twinkle_cursor % 2 +1;
}

//若所打开的位置周围有0个雷,则打开其周围的8个位置,否则只打开自身
void OpenAllAroundZero(int posX,int posY)
{
        if(leiqu[posX][posY] == 0 && leiquOpened[posX][posY] != 1)
        {
                leiquOpened[posX][posY] = 1;
                OpenAllAroundZero((posX - 1 < 0 ? 0:posX-1),(posY - 1 < 0 ? 0:posY-1));
                OpenAllAroundZero((posX - 1 < 0 ? 0:posX-1),posY);
                OpenAllAroundZero((posX - 1 < 0 ? 0:posX-1),(posY + 1 >19 ?19:posY+1));
                OpenAllAroundZero( posX,(posY + 1 > 19 ? 19:posY+1));
                OpenAllAroundZero((posX + 1 >19 ?19:posX+1),(posY + 1 >19 ?19:posY+1));
                OpenAllAroundZero((posX + 1 >19 ?19:posX+1),posY);
                OpenAllAroundZero((posX + 1 >19 ?19:posX+1),(posY - 1 < 0 ? 0:posY-1));
                OpenAllAroundZero(posX,(posY - 1 < 0 ? 0:posY-1));
        }
        else if(leiqu[posX][posY] != -1)
                leiquOpened[posX][posY] = 1;
}

//打开光标位置,若为雷,则扫雷失败,游戏结束,否则打开光标位置
void OpenPosition()
{
if(leiqu[pos_cursor_X][pos_cursor_Y] == -1)
{
Isalive = 0;
attrset(COLOR_PAIR(2));
mvprintw(25,0,"What a pity, All Dileis are bomb. Press any key to exit...");
}
else 
//leiquOpened[pos_cursor_X][pos_cursor_Y] = 1;
OpenAllAroundZero(pos_cursor_X,pos_cursor_Y);
}

//把光标位置标记为地雷
void markDilei()
{
if(leiquOpened[pos_cursor_X][pos_cursor_Y] != 1)
leiquOpened[pos_cursor_X][pos_cursor_Y] = (leiquOpened[pos_cursor_X][pos_cursor_Y] == 2?0:2);
}

//把光标位置标记为不确定是否安全
void markNotSure()
{
if(leiquOpened[pos_cursor_X][pos_cursor_Y] != 1)
leiquOpened[pos_cursor_X][pos_cursor_Y] = (leiquOpened[pos_cursor_X][pos_cursor_Y] == 3 ? 0:3);
}

//线程入口函数,用于接收用户输入
void *Controler(void *arg)
{
sem_wait(&bin_sem);
while(Isalive)
{
switch((char)getchar())
{
case 'a':pos_cursor_Y = (pos_cursor_Y -1 < 0? 0 :pos_cursor_Y - 1);break;    //左
case 's':pos_cursor_X = (pos_cursor_X +1 >19? 19:pos_cursor_X + 1);break;  //下
case 'w':pos_cursor_X = (pos_cursor_X -1 < 0? 0 :pos_cursor_X - 1);break;  //上
case 'd':pos_cursor_Y = (pos_cursor_Y +1 >19? 19:pos_cursor_Y + 1);break;//右
case 'j':OpenPosition();break;             //打开光标位置
case 'k':markDilei();break;                 // 光标位置标记为地雷
case 'l':markNotSure();break;            // 光标位置标记为不确定是否安全
}
sem_wait(&bin_sem);
}
}

//判断是否扫掉所有的雷
bool IsSuccess()
{
bool temp = 1;
for(int i = 0;i<20;i++)
for(int j = 0;j<20;j++)
{
if(leiqu[i][j] == -1)
{
if(leiquOpened[i][j] == 2)
continue;
else 
temp = 0;
}
else 
continue;
}
return temp;
}

int main()
{
void *temptr;
srand(getpid());
pthread_t p_Controler;
initleiqu();
printf("please use A to move the cursor left,use S to move the cursor down ,\n");
printf("       use W to move the cursor up,  use D to move the cursor right,\n");
printf("       use J to open the place of the cursor,use K to mark the bomb and use L to mark not sure.\n");
printf("Please Press ENTER to start the game....");
getchar();
initscr();
if(!has_colors())
{
endwin();
fprintf(stderr,"Error!\n");
return 1;
}
if(start_color() != OK)
{
endwin();
fprintf(stderr,"Error-Could not start\n");
return 1;
}
init_pair(1,COLOR_RED,COLOR_RED);
init_pair(2,COLOR_BLACK,COLOR_WHITE);
init_pair(3,COLOR_WHITE,COLOR_WHITE);
init_pair(4,COLOR_BLACK,COLOR_BLACK);
init_pair(5,COLOR_YELLOW,COLOR_YELLOW);
clear();

for(int i = 0;i<20;i++)
        for(int j = 0;j<20;j++)
        {
        attrset(COLOR_PAIR(leiqu[i][j] == -1?1:2));
        mvprintw(i+25,j+25,leiqu[i][j] == -1 ? " ":"%d",leiqu[i][j]);
                        //printf("%d,",leiqu[i][j]);
                        //if(j == 19)
                        //printf("\n"); 
                        //else continue;
                        //refresh();
                        //sleep(1);
                }

refresh();
sem_init(&bin_sem,0,0);
pthread_create(&p_Controler,NULL,Controler,NULL);
while(Isalive)
{
/*
for(int i = 0;i<20;i++)
for(int j = 0;j<20;j++)
{
attrset(COLOR_PAIR(leiqu[i][j] == -1?1:2));
mvprintw(i,j,leiqu[i][j] == -1 ? " ":"%d",leiqu[i][j]);
//printf("%d,",leiqu[i][j]);
//if(j == 19)
//printf("\n");
//else continue;
//refresh();
//sleep(1);
}
*/
if(IsSuccess())
{ Isalive = 0;
mvprintw(25,0,"You are great! All Dileis are found.Press any key to exit...");
}
showLeiqu();
showCursor();
refresh();
//sleep(1);
sem_post(&bin_sem);
}

pthread_join(p_Controler,&temptr);
getch();
endwin();
exit(EXIT_SUCCESS);
//return 0;
}


使用:把程序拷贝到程序文件,然后执行 g++ -o saolei saolei.c -lncurses -lpthread 就可以了

缺点:1、使用的是文字界面,软件没有图形界面美观和直观
           2、光标闪烁不够美观
           3、每个雷坑之间没有边框,无法直观看出行列 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值