linux中完成贪吃蛇的运行(用nucrses实现)

<h1>一    课程目的</h1>
<p>主要检验C语言的应用,其中包括</p>
<p>1.常规编程</p>
<p>2.指针的用法</p>
<p>3.关键词的用法</p>
<p>4.结构体的用法</p>
<p>5.链表的用法</p>
<h1>二    贪吃蛇项目的实现</h1>
<h2>一丶搭建项目环境:</h2>
<h3>1.环境配置</h3>
<p>这是在linux系统环境下进行的项目,由于项目需要动态显示,我们可以在linux系统下进行ncurse环境的配置;然后可以开始项目编程,在编程过程中进行环境优化;</p>
<h2>二丶贪吃蛇运动范围</h2>
<p>首先要通过for循环嵌套的方式打出贪吃蛇的运动范围:</p>
<pre><code class='language-c' lang='c'>#include &lt;curses.h&gt;

void gamepic()
{
        int hang;
        int lie;
        move(0,0);
        for(hang=0;hang&lt;22;hang++){
                for(lie=0;lie&lt;22;lie++){
                        if(hang == 0 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(hang==21 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(lie == 0 || lie == 21 &amp;&amp; hang !=0 &amp;&amp; hang !=21){
                                printw(&quot;|&quot;);
                        }else{
                                printw(&quot;  &quot;);
                        }

                }
                printw(&quot;\n&quot;);
        }
}
int main()
{
        initscr();
        gamepic();
        getch();
        endwin();
        return 0;
}
</code></pre>
<p>这是一个显示20*20方格的代码;</p>
<h2>三丶显示贪吃蛇</h2>
<p>给贪吃蛇头数据</p>
<pre><code class='language-c' lang='c'>void initsnake()
{
        head=(struct snake*)malloc(sizeof(struct snake));
        head-&gt;hang=4;
        head-&gt;lie=4;
        head-&gt;next=NULL;
}
</code></pre>
<p>将数据加到界面中</p>
<pre><code class='language-c' lang='c'>for(hang=0;hang&lt;22;hang++){
                for(lie=0;lie&lt;22;lie++){
                        if(hang == 0 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(hang==21 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(lie == 0 || lie == 21 &amp;&amp; hang !=0 &amp;&amp; hang !=21){
                                printw(&quot;|&quot;);
                        }else if(head-&gt;hang == hang &amp;&amp; head-&gt;lie == lie){
                                printw(&quot;[]&quot;);//加贪吃蛇数据
                        }else{
                                printw(&quot;  &quot;);
                        }

                }
                printw(&quot;\n&quot;);
        }
</code></pre>
<p>显示贪吃蛇蛇身,通过遍历的方式将蛇身输出(“在这里不小心用if替代了while,导致只输出一个蛇身,因为if只循环一次,而while会不断循环直至p指到NULL”)</p>
<pre><code class='language-c' lang='c'>void snakemove()
{
        struct snake* new=(struct snake*)malloc(sizeof(struct snake));
        new-&gt;next=NULL;
        new-&gt;hang=tail-&gt;hang;
        new-&gt;lie=tail-&gt;lie+1;
        tail-&gt;next=new;

        tail=new;

}

void initsnake()
{
        head=(struct snake*)malloc(sizeof(struct snake));
        head-&gt;hang=4;
        head-&gt;lie=4;
        head-&gt;next=NULL;
        tail=head;

        snakemove();
        snakemove();
}
int snakeon(int x,int y)
{
        struct snake* p;
        p=head;
        while(p != NULL){
                if(p-&gt;hang==x &amp;&amp; p-&gt;lie==y){
                        return 1;
                }
                p=p-&gt;next;
        }
        return 0;
}
</code></pre>
<h2>四丶贪吃蛇移动</h2>
<p>先实现贪吃蛇的单向向右移动,贪吃蛇的移动是tail向右移动一格,同时head要移动到head-&gt;next,然后free掉之前的head,原理是增加1个蛇身然后减去1蛇身,保持蛇的长度不变。</p>
<p>以下代码是控制蛇的方向(每往其方向走一格,就增加一个蛇身)</p>
<pre><code class='language-c' lang='c'>void snakemove()
{
        struct snake* new=(struct snake*)malloc(sizeof(struct snake));
        new-&gt;next=NULL;

         switch(dir){
                case UP:
                        new-&gt;hang=tail-&gt;hang-1;
                        new-&gt;lie=tail-&gt;lie;
                break;
                case DOWN:
                        new-&gt;hang=tail-&gt;hang+1;
                        new-&gt;lie=tail-&gt;lie;
                break;
                case LEFT:
                        new-&gt;hang=tail-&gt;hang;
                        new-&gt;lie=tail-&gt;lie-1;
                break;
                case RIGHT:
                        new-&gt;hang=tail-&gt;hang;
                        new-&gt;lie=tail-&gt;lie+1;
                break;
        }

        tail-&gt;next=new;

        tail=new;

}
</code></pre>
<p>然后是移动后对应的head会移动到head-&gt;next,然后free掉之前的head,释放空间;</p>
<pre><code class='language-c' lang='c'>void delesnake()
{
        struct snake* p;
        p=head;
        head=head-&gt;next;

        free(p);
}
</code></pre>
<p>最后让其移动时不会直接回头,这里采用的是绝对值的方式,先进行宏定义,这里前后和左右相反,只要其绝对值相等,则不执行command</p>
<pre><code class='language-c' lang='c'>#define UP     1
#define DOWN  -1
#define LEFT   2
#define RIGHT -2


void notturn(int direction)
{
        while(abs(dir)!=abs(direction)){//abs是绝对值的意思
                dir=direction;
        }

}
</code></pre>
<p>以下是按键封装的函数</p>
<pre><code class='language-c' lang='c'>void* t2()
{
        while(1){
                key=getch();
                switch(key){
                        case KEY_DOWN:
                                notturn(DOWN);
                        break;
                        case KEY_UP:
                                notturn(UP);;
                        break;
                        case KEY_LEFT:
                                notturn(LEFT);;
                        break;
                        case KEY_RIGHT:
                                notturn(RIGHT);;
                        break;
        }


        }

}
</code></pre>
<p>由于这是一个while函数,需要和主程序同时进行,这里需要用到Linux的多线程模式,运用的语句为</p>
<pre><code class='language-c' lang='c'>        pthread_t th1;//定义增加一个线程
        pthread_create(&amp;th1,NULL,t2,NULL);//线程进行的是t2函数(注意,这里的t2是一个指针函数)
</code></pre>
<h2>五丶设置贪吃蛇死亡条件</h2>
<p>当贪吃蛇撞到墙或者自己的时候,进行初始化,重新开始游戏;</p>
<pre><code class='language-c' lang='c'>void snakeover()
{
        struct snake *p;
        snakemove();
        delesnake();
        p=head;
        while(p-&gt;next != NULL){
        if(p-&gt;hang==tail-&gt;hang &amp;&amp; p-&gt;lie==tail-&gt;lie){
                        initsnake();
                }
                p=p-&gt;next;
        }

        if(tail-&gt;hang==0 || tail-&gt;hang==21 || tail-&gt;lie==0 || tail-&gt;lie==21){
                initsnake();
        }

}
</code></pre>
<h2>六丶设置食物</h2>
<p>这里需要定义一个全局的结构体作为食物,同时需要把数据给到结构体,用rand随机数求余来给到结构体数值,这里不需要设置一个结构体指针,其不用链表链接,而且每次用完一个食物就要给他free掉,过于麻烦,这里直接使用结构体就行</p>
<pre><code class='language-c' lang='c'>void snakefood()
{
        int x;
        int y;
        x=rand()%21;
        y=rand()%21;
        if(x==0){
                x=x+1;
        }
        if(y==0)
        {
                y=y+1;
        }
        food.hang=x;
        food.lie=y;
}
//将位置在地图中输出
void gamepic()
{
        int hang;
        int lie;
        move(0,0);
        for(hang=0;hang&lt;22;hang++){
                for(lie=0;lie&lt;22;lie++){
                        if(hang == 0 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(hang==21 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(lie == 0 || lie == 21 &amp;&amp; hang !=0 &amp;&amp; hang !=21){
                                printw(&quot;|&quot;);
                        }else if(snakeon(hang,lie)){
                                printw(&quot;[]&quot;);
                        }else if(food.hang==hang &amp;&amp; food.lie==lie){
                                printw(&quot;$$&quot;);//贪吃蛇食物在这里
                        }else{
                                printw(&quot;  &quot;);
                        }

                }
                printw(&quot;\n&quot;);
        }
}
</code></pre>
<p>食物被吃掉后随机出现:</p>
<p>由于是结构体,每次与tail值相同时直接再调用一次函数改变其结构体内容即可</p>
<pre><code class='language-c' lang='c'>void snakeover()
{
        struct snake *p;
        snakemove();
        if(food.hang == tail-&gt;hang &amp;&amp; food.lie == tail-&gt;lie){
                snakefood();
        }else{
        delesnake();
        }
        p=head;
        while(p-&gt;next != NULL){
        if(p-&gt;hang==tail-&gt;hang &amp;&amp; p-&gt;lie==tail-&gt;lie){
                        initsnake();
                }
                p=p-&gt;next;
        }

        if(tail-&gt;hang==0 || tail-&gt;hang==21 || tail-&gt;lie==0 || tail-&gt;lie==21){
                initsnake();
        }

}
//但初始化的时候也需要将食物运行,防止第一次进入地图的时候没有食物出现
void initsnake()
{
        struct snake* p;
        snakefood();
        dir=RIGHT;
        while(head != NULL)
        {
                p=head;
                head=head-&gt;next;
                free(p);
        }
        head=(struct snake*)malloc(sizeof(struct snake));
        head-&gt;hang=4;
        head-&gt;lie=4;
        head-&gt;next=NULL;
        tail=head;

        snakemove();
        snakemove();
        snakemove();
}
//这是每一次初始化都需要进行的操作
</code></pre>
<h1>三丶所有贪吃蛇代码</h1>
<pre><code class='language-c' lang='c'>#include &lt;curses.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;pthread.h&gt;  //多线程

#define UP     1        //宏定义按键
#define DOWN  -1
#define LEFT   2
#define RIGHT -2


struct snake
{
        int hang;
        int lie;
        struct snake* next;
};

void initncurses()//ncurses界面初始化
{
        initscr();
        keypad(stdscr,1);
        noecho();
}

struct snake food;
struct snake* head;
struct snake* tail;
int dir;
int key;

void notturn(int direction)//拿到方向,判断方向是否符合要求
{
        while(abs(dir)!=abs(direction)){//abs时绝对值
                dir=direction;
        }

}

void* t2()//多线程需要用到指针,这里用多线程处理按键
{
        while(1){
                key=getch();
                switch(key){
                        case KEY_DOWN:
                                notturn(DOWN);
                        break;
                        case KEY_UP:
                                notturn(UP);;
                        break;
                        case KEY_LEFT:
                                notturn(LEFT);;
                        break;
                        case KEY_RIGHT:
                                notturn(RIGHT);;
                        break;
        }


        }

}

int snakeon(int x,int y)//这里是对蛇的身体进行遍历,输出蛇身
{
        struct snake* p;
        p=head;
        while(p != NULL){
                if(p-&gt;hang==x &amp;&amp; p-&gt;lie==y){
                        return 1;
                }
                p=p-&gt;next;
        }
        return 0;
}


void gamepic()//所有的界面显示都在这里进行显示
{
        int hang;
        int lie;
        move(0,0);
        for(hang=0;hang&lt;22;hang++){
                for(lie=0;lie&lt;22;lie++){
                        if(hang == 0 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(hang==21 &amp;&amp; lie !=21){
                                printw(&quot;--&quot;);
                        }else if(lie == 0 || lie == 21 &amp;&amp; hang !=0 &amp;&amp; hang !=21){
                                printw(&quot;|&quot;);
                        }else if(snakeon(hang,lie)){
                                printw(&quot;[]&quot;);
                        }else if(food.hang==hang &amp;&amp; food.lie==lie){
                                printw(&quot;$$&quot;);
                        }else{
                                printw(&quot;  &quot;);
                        }

                }
                printw(&quot;\n&quot;);
        }
}

void snakefood()//蛇的食物以及食物随机出现
{
        int x;
        int y;
        x=rand()%21;//rand()是随机数
        y=rand()%21;
        if(x==0){
                x=x+1;
        }
        if(y==0)
        {
                y=y+1;
        }
        food.hang=x;
        food.lie=y;
}


void snakemove()//蛇身的移动,tail为移动的方向,这里每移动一次就是加一个格子给蛇身,后面会调用函数去把尾巴相应的剪掉,做到没吃食物的时候蛇身长度不变
{
        struct snake* new=(struct snake*)malloc(sizeof(struct snake));
        new-&gt;next=NULL;

         switch(dir){
                case UP:
                        new-&gt;hang=tail-&gt;hang-1;
                        new-&gt;lie=tail-&gt;lie;
                break;
                case DOWN:
                        new-&gt;hang=tail-&gt;hang+1;
                        new-&gt;lie=tail-&gt;lie;
                break;
                case LEFT:
                        new-&gt;hang=tail-&gt;hang;
                        new-&gt;lie=tail-&gt;lie-1;
                break;
                case RIGHT:
                        new-&gt;hang=tail-&gt;hang;
                        new-&gt;lie=tail-&gt;lie+1;
                break;
        }

        tail-&gt;next=new;

        tail=new;

}

void initsnake()//整个地图和蛇的初始化,再游戏结束和重新开始时调用
{
        struct snake* p;
        snakefood();
        dir=RIGHT;
        while(head != NULL)
        {
                p=head;
                head=head-&gt;next;
                free(p);
        }
        head=(struct snake*)malloc(sizeof(struct snake));
        head-&gt;hang=4;
        head-&gt;lie=4;
        head-&gt;next=NULL;
        tail=head;

        snakemove();
        snakemove();
        snakemove();
}

void delesnake()//这里就是将蛇尾去掉
{
        struct snake* p;
        p=head;
        head=head-&gt;next;

        free(p);
}
void snakeover()//蛇死亡的条件
{
        struct snake *p;
        snakemove();
        if(food.hang == tail-&gt;hang &amp;&amp; food.lie == tail-&gt;lie){
                snakefood();
        }else{
        delesnake();
        }
        p=head;
        while(p-&gt;next != NULL){
        if(p-&gt;hang==tail-&gt;hang &amp;&amp; p-&gt;lie==tail-&gt;lie){
                        initsnake();
                }
                p=p-&gt;next;
        }

        if(tail-&gt;hang==0 || tail-&gt;hang==21 || tail-&gt;lie==0 || tail-&gt;lie==21){
                initsnake();
        }

}

int main()
{
        pthread_t th1;
        initncurses();

        initsnake();
        pthread_create(&amp;th1,NULL,t2,NULL);
        while(1){
                usleep(100000);//这里就相当于51中的延时
                snakeover();
                gamepic();
                refresh();//刷新界面

        }
        getch();
        endwin();
        return 0;
}
</code></pre>
<h1>四丶关键词</h1>
<p>malloc:</p>
<p>在指针直接给数据时需要开辟一个空间给指针,但如果直接给相同类型就不需要开辟额外空间。</p>
<p>开辟空间用malloc</p>
<p>这里举一个结构体用法的例子:</p>
<pre><code class='language-c' lang='c'>(struct snake*)malloc(sizeof(snake struct))
</code></pre>
<p>用完之后不用的malloc开辟的空间需要用free给释放掉,防止内存占用。</p>
 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值