zoukankan      html  css  js  c++  java
  • Perl看完这个,再不敢说自己会玩贪吃蛇

      某天闲逛时看见一副动图:

        

      真的是非常贪吃,各种拐弯各种吃,感觉十分有趣。

      用Perl来实现自动吃满,蓄谋已久,之前的字符贪吃蛇、深度优先算法、A*算法,都是为此篇做铺垫。

      

      那么,怎样让蛇不吃到自己呢?

      1、让蛇按照我们设计好的路线行进,在一个N*M(N、M均为偶数,奇数不讨论)的游戏区域,设计好路线如下:

        

        当花儿谢了,果子熟透,春夏秋冬一个轮回后,蛇终于吃满了。。。

      2、假设蛇总是追着自己的尾巴跑,那么永远不会死;然而,这没什么鸟用,我们需要的是一条“贪吃”的蛇。

      3、在2上稍稍改进,吃完食物后再追着尾巴,嗯,已经很接近了。但是问题来了:怎么吃到食物?吃到食物后被围死怎么办?

      其实我的想法就是解决3中的问题:

      1、使用A*算法计算到食物的最短路径

      2、模拟吃到食物后的场景,能否回到蛇尾;能--吃食物,不能--继续追着尾巴,重复1、2

      3、如果无法回到尾巴,保持当前移动方向(认命吧,要挂的节奏)

      伪码如下:

    #    while( 存活 && 未吃满){
    #        计算蛇头到食物的路径
    #        if( 有蛇头到食物的路径 ){
    #            模拟吃到食物后的场景
    #            计算是否有路径到达蛇尾
    #            if( 有路径 ){        
    #                执行蛇头到食物的路径
    #            }
    #            else{  # 没有到蛇尾的路径
    #                next
    #            }
    #        }
    #       找出当前可行方向追逐蛇尾
    #    }
    #    if(吃满){
    #        显示:祝贺
    #    }
    #    else{
    #        显示:wtf ?
    #    }

      模拟吃到食物后的场景:使用A*计算路径,并创建一条“影子蛇”用来模拟吃到食物后的状态

      计算是否有路径到达蛇尾:和“追逐蛇尾”方法类似,也可使用A*

      找出当前可行方向追逐蛇尾:

        由于移动时尾巴会变动,未尝试A*,使用指定方向深度优先搜索算法

        伪码如下:

    sub trace_tail{
        @moves=grep{可行};
        foreach(@moves){
            next if(下一步越界 || 吃到自己)
            unshift @feasible,$_ if(远离食物)
            其他方向 push @feasible
        }
        foreach(@feasible){
            next_move=cur_move+$_
            指定方向优先探索
            next_move的反向上一步设为不可通过
            每走一步,从蛇尾开始设未经过;每原路返回一次,当前位置的蛇身设不可通过
            if(有路径)return next_move
        }
        执行完毕无路径,return cur_move
    }

      

      运行如下:

        

      实际上还是会被困死,虽然追逐尾巴时避开食物优先,但唯一路径可能会出现食物,不吃也得吃了,如下:

        

      代码较乱,准备加好注释后贴上来。

      有很大的优化空间,等有时间再慢慢搞,代码:

    use strict;
    use 5.01;
    use Time::HiRes qw/sleep/;
    use Term::ReadKey;
    use constant {WIDTH=>12,HEIGHT=>8,DEBUG=>0};
    my @bg=();
    my @snake=();
    my @head2food=();
    my @food_coordinate=();  # 保存食物坐标
    my ($score,$food,$speed,$alive,$head2tail,$head_move)=(0,0,1,1,0,4); # 得分、食物、速度、存活、能否回到尾巴的标志、初始移动方向
    my $full=(WIDTH-2)*(HEIGHT-2);
    my %opposite=( 1=>3,
                  2=>4,
                  3=>1,
                  4=>2, );  # 对立的移动方向,禁止反向移动
    my @uldr=( 0,[-1,0],[0,-1],[1,0],[0,1], ); # 上、左、下、右
    ############################################################################################
    &init;
    #my $move=&manual_move(4);  # 开始向右移动
    my $move=&smart_move($head_move);$speed=9;
    while( $alive && @snake < $full ){        
        @head2food=&head_to_food($head_move,@snake);  # 计算蛇头到食物的路径
        if( $head2food[0] != 0 ){                      # 有路径
            $head2tail=&head_to_tail(@snake,@head2food);    # 判断吃到食物后是否能回到尾巴
            if($head2tail){        # 能回到尾巴,吃食物
                foreach( @head2food ){
                    $head_move=$_;
                    $move->($head_move);
                    &check_head;
                    if($alive){
                        &show;
                        sleep (1-$speed*0.1);
                    }
                }
            }
        } 
        $head_move=&trace_tail($head_move,@snake);        # 找出当前可行方向追逐蛇尾
        $move->($head_move);
        &check_head;
        if($alive){
            &show;
            sleep (1-$speed*0.1);
        }
    }
    if(@snake==$full){
        print "
    congratulations!
    ";  # 蛇占满游戏区时显示
    }
    else{
        print "
    WTF?
    ";
    }
    ############################################################################################
    sub init{
        my $y=int(HEIGHT/2);
        for(my $y=0;$y<HEIGHT;$y++){
            for( my $x=0 ; $x<WIDTH ; $x++ ){
                if( $y == 0 || $y == HEIGHT-1 ||
                    $x == 0 || $x == WIDTH-1  ){
                    $bg[$y][$x] = '*';
                }
                else{
                    $bg[$y][$x] = ' ';
                }
            }
        }
        @{$bg[$y]}[1,2]=('#','@'); # 初始蛇身位置
        @snake=( [$y,2],[$y,1], ); # 保存蛇身坐标
        &make_food;  # 产生食物
    }
    ############################################################################################
    sub show{
        system("cls") unless(DEBUG);
        print "your score : $score
    ";
        print "current speed : ",$speed,"
    
    ";
        print @$_,"
    " foreach(@bg);
    }
    ############################################################################################
    sub smart_move{
        my $move_direct=shift;
        sub{  # 闭包,传入初始移动方向
            $move_direct=shift;
            unshift @snake,[$snake[0][0]+$uldr[$move_direct][0],$snake[0][1]+$uldr[$move_direct][1]];
        }
    }
    ############################################################################################
    sub head_to_food{  # 蛇头到食物
        my $head_shadow=shift;
        my @snake_ghost=@_; 
        my @bg_ghost=@bg;
        my @path=&a_star( [ $snake_ghost[0][0],$snake_ghost[0][1] ],
                          [ $food_coordinate[0],$food_coordinate[1] ],@bg_ghost ); # A*算法,传递起点、终点、蛇当前坐标指针
        return @path;
    }
    ############################################################################################
    # 追逐尾巴,传递当前移动方向、蛇身所有坐标
    sub trace_tail{
        print "call trace_tail
    " if DEBUG;
        my $cur_move=shift;  # 当前移动方向
        my @snake_ghost=@_;
        my @path=();
        my $cur_position=[ $snake_ghost[0][0],$snake_ghost[0][1] ];  # 起点
        print "    cur_position:",$snake_ghost[0][0],",",$snake_ghost[0][1],"
    " if DEBUG;    
        my $end=[ $snake_ghost[-1][0],$snake_ghost[-1][1] ];  # 终点
        my $tail=$#snake_ghost;  # 蛇长度
            
        my @bg_ghost=map{ [ split('','0'x WIDTH) ] }0..(HEIGHT-1);  # 0--未经过 1--已走 2--不可通过
        map{ my $y=$_;map { $bg_ghost[$y][$_] = ( $bg[$y][$_] eq '*' )?2:0 }0..$#{$bg[0]} }0..$#bg;
        map{ $bg_ghost[ $snake_ghost[$_][0] ][ $snake_ghost[$_][1] ] = 2 } 1..$#snake_ghost;  # 蛇身不可通过
        my @feasible=();
        my @next_moves=grep{ ! /$opposite{$cur_move}/ }values %opposite;  # 取出除反方向的可行方向
        my $weight=0;
        foreach(@next_moves){
            $weight=1;
            my $next_move=$_;
            my ($y,$x)=( $snake_ghost[0][0]+$uldr[$next_move][0],$snake_ghost[0][1]+$uldr[$next_move][1] );
            # 防止越界
            if( $y < 1 || $y > HEIGHT-2 || $x < 1 || $x > WIDTH-2){
                $weight=0;
                next;
            }
            
            # 防止吃到自己
            foreach(0..$#snake_ghost){
                if( $y == $snake_ghost[$_][0] && $x == $snake_ghost[$_][1]  ){
                    $weight=0;
                    last;
                }
            }
            if($weight){
                if( abs($y - $food_coordinate[0]) > abs($snake_ghost[0][0] - $food_coordinate[0]) ||
                    abs($x - $food_coordinate[1]) > abs($snake_ghost[0][1] - $food_coordinate[1]) ){
                        unshift @feasible,$next_move;  # 远离食物放到数组头
                }
                else{
                    push @feasible,$next_move;  # 其他路径放在末尾
                }
            }
        }
        print "    feasible:@feasible
    " if DEBUG;
        foreach(@feasible){
            @path=();
            $cur_move=$_;
            print "    cur_move:$cur_move
    " if DEBUG;
        my @one234 = ();  # 将当前移动方向设置为初始方向
        given($cur_move){
            when(1){ @one234 = @uldr;}
            when(2){ @one234 = @uldr[0,2,3,4,1]; }
            when(3){ @one234 = @uldr[0,3,4,1,2]; }
            when(4){ @one234 = @uldr[0,4,1,2,3]; }
        }
    #################################################################
    # 指定方向深度搜索
        my ($step,$p_step)=(0,'');    
        do{
            if($bg_ghost[ $cur_position->[0] ][ $cur_position->[1] ] == 0 ){
                $bg_ghost[ $cur_position->[0] ][ $cur_position->[1] ]=1;
                 # 当前移动方向的反方向点不可经过,即禁止回退
                $bg_ghost[ $snake_ghost[0][0]+$uldr[$opposite{$cur_move}]->[0] ][ $snake_ghost[0][1]+$uldr[$opposite{$cur_move}]->[1] ] = 2;
                $bg_ghost[ $snake_ghost[0][0] ][ $snake_ghost[0][1] ] = 2;  # 当前点不可返回
                if( $cur_position->[0] == $food_coordinate[0] && $cur_position->[1] == $food_coordinate[1] ){
                    push @snake_ghost,[ $snake_ghost[-1][0],$snake_ghost[-1][0] ];
                }
                $path[$step]={step=>$step,
                              coordinate=>[$cur_position->[0],$cur_position->[1]],
                              direct=>1,
                             };
                $path[$step]->{direct}=4 if($step == 0);  # 起点不可再做起点
                print "    path[$step]:$path[$step]:",$path[$step]->{step},"
    " if DEBUG;
                if(DEBUG){
                            print @$_,"
    " foreach(@bg_ghost);
                        }
                if( $cur_position->[0]==$end->[0] && $cur_position->[1]==$end->[1]){
                    my @arr=('A'..'Z','a'..'z');
                    foreach(0..$#path){
                        $bg_ghost[ $path[$_]->{coordinate}->[0] ][ $path[$_]->{coordinate}->[1] ] = $arr[$_];
                    }
                    print "    trace_tail: return $cur_move
    " if DEBUG;
                    return $cur_move;  # 有可行方向,返回
                }
                $step++;
                if($step>1 && $step<=$#snake_ghost){
                $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] = 0 
                    if ( $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] == 2 );  # 每移动一次,将蛇尾所在坐标设未经过
                $tail=($tail>0)?($tail-1):1;
                }  
                $cur_position=[ $path[$step-1]->{coordinate}->[0]+$one234[1]->[0],
                                $path[$step-1]->{coordinate}->[1]+$one234[1]->[1] ];
                print "    (y,x):(",$cur_position->[0],",",$cur_position->[1],")
    " if DEBUG;
            }
            else{
                if(@path){
                    $p_step=pop(@path);
                    while($p_step->{direct}==4 && (@path)){
                        $bg_ghost[ $p_step->{coordinate}->[0] ][ $p_step->{coordinate}->[1] ] = 2;
                        $p_step=pop(@path);
                        $step--;
    
                        $tail=($tail<$#snake_ghost-1)?($tail+1):$#snake_ghost-1; 
                        $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] = 2 
                    if ( $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] == 0 );  # 每回退一次,将蛇尾所在坐标设为不可通过
    
                    }
                    if($p_step->{direct}<4){
                        $p_step->{direct}++;
                        print "        ",$p_step->{step},":p_step->{direct}:",$p_step->{direct},"
    " if DEBUG;
                        push @path,$p_step;
                        my @temp=@{$p_step->{coordinate}}[0,1];
                        $cur_position = [ $temp[0]+$one234[$p_step->{direct}]->[0],
                                          $temp[1]+$one234[$p_step->{direct}]->[1] ];
                        print "        (y,x):(",$cur_position->[0],",",$cur_position->[1],")
    " if DEBUG;
                    }
                }
            }
        }while(@path);
    # 指定方向深度搜索结束
    #################################################################
    }
        print "    cur_move:$cur_move  trace_tail:return fail
    " if DEBUG;
        return $cur_move;  # 没有到尾巴的可行方向了,准备认命
    }
    #######################################################################################
    # 能否到尾巴位置,能返回1,否则返回0
    # 算法大致与 trace_tail 相同
    sub head_to_tail{
        print "call head_to_tail
    " if DEBUG;
        my ($p_snake,$p_path)=@_;
        my @snake_ghost=@$p_snake;
        my @path=@$p_path;
        my $cur_move=$path[-1];
        my @arr=();
        foreach(0..$#path){
            my ($y,$x)=( $snake_ghost[0][0]+$uldr[ $path[$_] ]->[0],$snake_ghost[0][1]+$uldr[ $path[$_] ]->[1] );
            unshift @snake_ghost,[$y,$x];
            pop @snake_ghost if($_ < $#path);
        }  # 影子蛇先行,吃到食物后的状态
        @path=();
        my $cur_position=[ $snake_ghost[0][0],$snake_ghost[0][1] ];
        print "    cur_position:",$snake_ghost[0][0],",",$snake_ghost[0][1],"
    " if DEBUG;    
        my $end=[ $snake_ghost[-1][0],$snake_ghost[-1][1] ];
        my $tail=$#snake_ghost;
            
        my @bg_ghost=map{ [ split('','0'x WIDTH) ] }0..(HEIGHT-1);  # 0--未经过 1--已走 2--不可通过
        map{ my $y=$_;map { $bg_ghost[$y][$_] = ( $bg[$y][$_] eq '*' )?2:0 }0..$#{$bg[0]} }0..$#bg;
        map{ $bg_ghost[ $snake_ghost[$_][0] ][ $snake_ghost[$_][1] ] = 2 } 1..$#snake_ghost;  # 蛇身不可通过
            my @feasible=();
        my @next_moves=grep{ ! /$opposite{$cur_move}/ }values %opposite;
        my $weight=0;
        foreach(@next_moves){
            $weight=1;
            my $next_move=$_;
            my ($y,$x)=( $snake_ghost[0][0]+$uldr[$next_move][0],$snake_ghost[0][1]+$uldr[$next_move][1] );
            # 防止越界
            if( $y < 1 || $y > HEIGHT-2 || $x < 1 || $x > WIDTH-2){
                $weight=0;
                next;
            }
            
            # 防止吃到自己
            foreach(0..$#snake_ghost){
                if( $y == $snake_ghost[$_][0] && $x == $snake_ghost[$_][1] ){
                    $weight=0;
                    last;
                }
            }
            if($weight){
                push @feasible,$next_move;  # 路径随意放
            }
        }
        print "    feasible:@feasible
    " if DEBUG;
        foreach(@feasible){
            @path=();
            $cur_move=$_;
        my @one234 = ();  # 将当前移动方向设置为初始方向
        given($cur_move){
            when(1){ @one234 = @uldr;}
            when(2){ @one234 = @uldr[0,2,3,4,1]; }
            when(3){ @one234 = @uldr[0,3,4,1,2]; }
            when(4){ @one234 = @uldr[0,4,1,2,3]; }
        }
    #################################################################
    # 指定方向深度搜索
        my ($step,$p_step)=(0,'');    
        do{
            if($bg_ghost[ $cur_position->[0] ][ $cur_position->[1] ] == 0 ){
                $bg_ghost[ $cur_position->[0] ][ $cur_position->[1] ]=1;
                $bg_ghost[ $snake_ghost[0][0]+$uldr[$opposite{$cur_move}]->[0] ][ $snake_ghost[0][1]+$uldr[$opposite{$cur_move}]->[1] ] = 2;
                $bg_ghost[ $snake_ghost[0][0] ][ $snake_ghost[0][1] ] = 2;  # 当前点不可返回
                $path[$step]={step=>$step,
                              coordinate=>[$cur_position->[0],$cur_position->[1]],
                              direct=>1,
                             };
                $path[$step]->{direct}=4 if($step == 0);  # 起点不可再做起点
                print "    path[$step]:$path[$step]:",$path[$step]->{step},"
    " if DEBUG;
                if( $cur_position->[0]==$end->[0] && $cur_position->[1]==$end->[1]){
                    my @arr=('A'..'Z','a'..'z');
                    foreach(0..$#path){
                        $bg_ghost[ $path[$_]->{coordinate}->[0] ][ $path[$_]->{coordinate}->[1] ] = $arr[$_];
                    }
                    print "    head_to_tail: return 1
    " if DEBUG;
                    return 1;
                }
                $step++;
                if($step>1 && $step<=$#snake_ghost){
                $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] = 0 
                    if ( $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] == 2 );  # 每移动一次,将蛇尾所在坐标设未经过
                $tail=($tail>0)?($tail-1):1;
                }  
                $cur_position=[ $path[$step-1]->{coordinate}->[0]+$one234[1]->[0],
                                $path[$step-1]->{coordinate}->[1]+$one234[1]->[1] ];
                print "    (y,x):(",$cur_position->[0],",",$cur_position->[1],")
    " if DEBUG;
            }
            else{
                if(@path){
                    $p_step=pop(@path);
                    while($p_step->{direct}==4 && (@path)){
                        $bg_ghost[ $p_step->{coordinate}->[0] ][ $p_step->{coordinate}->[1] ] = 2;
                        $p_step=pop(@path);
                        $step--;
                        $tail=($tail<$#snake_ghost)?($tail+1):$#snake_ghost; 
                        $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] = 2 
                    if ( $bg_ghost[ $snake_ghost[$tail][0] ][ $snake_ghost[$tail][1] ] == 0 );  # 每回退一次,将蛇尾所在坐标设为不可通过
                        if(DEBUG){
                            print @$_,"
    " foreach(@bg_ghost);
                        }                        
                    }
                    if($p_step->{direct}<4){
                        $p_step->{direct}++;
                        print "        ",$p_step->{step},":p_step->{direct}:",$p_step->{direct},"
    " if DEBUG;
                        push @path,$p_step;
                        my @temp=@{$p_step->{coordinate}}[0,1];
                        $cur_position = [ $temp[0]+$one234[$p_step->{direct}]->[0],
                                          $temp[1]+$one234[$p_step->{direct}]->[1] ];
                        print "        (y,x):(",$cur_position->[0],",",$cur_position->[1],")
    " if DEBUG;
                    }
                }
            }
        }while(@path);
    # 指定方向深度搜索结束
    #################################################################
        }
        print "    head_to_tail:return 0
    " if DEBUG;
        return 0;    
    }
    #######################################################################################
    sub caclulate_cost{
        my ($sp,$ep)=@_;
        return abs($sp->[0] - $ep->[0]) + abs($sp->[1] - $ep->[1]);
    }
    #######################################################################################
    # A*算法
    sub a_star{
        print "call a_star
    " if DEBUG;
        my $start=shift;  # 起点
        my $end=shift;  # 终点
        my $p_arr=shift;
        my @bg_ghost=@{$p_arr};
        
        my @path=();  # 存放步数的数组    
        my @open_close=();
        my ($step,$p_step,$p_gh)=(0,'','');  # 步数、指向数组元素的指针、指向open_close元素的指针
        map{ my $y=$_;map { $open_close[$y][$_]->{flag} = ( $bg_ghost[$y][$_] eq '#' || $bg_ghost[$y][$_] eq '*')?2:0 }0..$#{$bg_ghost[0]} }0..$#bg;  # 障碍物设置不可通过
        
        $path[$step]={ coordinate=>[$start->[0],$start->[1]],
                       cost=>0,
                       next_cost=>&caclulate_cost( $start,$end ),
                       previous=>0,
                      };
        $path[$step]->{actual_cost}=$path[$step]->{cost} + $path[$step]->{next_cost};
        $open_close[ $start->[0] ][ $start->[1] ]->{point}='';
        while(@path){
            $p_step=pop(@path);
            print "  step:$step,p_step:$p_step
    " if DEBUG;
            if( $p_step->{coordinate}->[0] == $end->[0] &&
                $p_step->{coordinate}->[1] == $end->[1] ){
                my @arr=();
                my @temp=();
                while($p_step){
                    push @temp,$p_step->{coordinate};
                    $p_step=$p_step->{previous};
                }
                @temp=reverse(@temp);
                foreach(0..$#temp-1){
                    my $line=($temp[$_+1][0]-$temp[$_][0])."a".($temp[$_+1][1]-$temp[$_][1]);
                    given($line){
                        when('-1a0'){ push @arr,1 ;}
                        when('0a-1'){ push @arr,2 ;}
                        when('1a0') { push @arr,3 ;}
                        when('0a1') { push @arr,4 ;}
                    }  # 从父节点回溯,获取每一步移动方向
                }
                return @arr;
            }
            $step++;
            for(my $cnt=1;$cnt<=4;$cnt++){
                my $y= $p_step->{coordinate}->[0]+$uldr[$cnt][0] ;
                my $x= $p_step->{coordinate}->[1]+$uldr[$cnt][1] ;
                print "    ($p_step->{coordinate}->[0],$p_step->{coordinate}->[1])+($uldr[$cnt][0],$uldr[$cnt][1]),(y,x)=($y,$x)
    " if DEBUG;
                next if( $open_close[$y][$x]->{flag} == 2 ||
                         $y < 1 || $y > HEIGHT-2 || $x < 1 || $x > WIDTH-2 );
                
                if( $open_close[$y][$x]->{flag} == 0 ){                
                    $open_close[$y][$x]->{flag}=1;
                    $open_close[$y][$x]->{point}=$p_step;
                    my $px={  coordinate=>[$y,$x],
                                       cost=>$p_step->{cost}+1,
                                       next_cost=>&caclulate_cost( [$y,$x],$end ),
                                       previous=>$p_step,
                                   };
                    $px->{actual_cost}=$px->{cost} + $px->{next_cost};
                    push @path,$px;
                }
                else{
                    $p_gh=$open_close[$y][$x]->{point};
                    print "      p_gh:$p_gh
    " if DEBUG;
                    if($p_gh && $p_step->{cost}+1 < $p_gh->{cost} ){
                        print "      $p_step->{cost},$p_gh->{cost}
    " if DEBUG;
                        $p_gh->{cost}=$p_step->{cost}+1;
                        $p_gh->{previous}=$p_step;
                        $p_gh->{actual_cost}=$p_gh->{cost}+$p_gh->{next_cost};
                    }
                }
            }    
            $open_close[ $p_step->{coordinate}->[0] ][ $p_step->{coordinate}->[1] ]->{flag}=1;
            @path=sort{$b->{actual_cost}<=>$a->{actual_cost}}@path;
        }
        print "    a_star: return 0
    " if DEBUG;
        return 0;
    }
    #######################################################################################
    sub manual_move{
        # 闭包,为了传入初始移动方向
        my $move_direct=shift;
        sub{
            ReadMode 2;
            my $key=ReadKey(-1);
            $key=~tr/a-z/A-Z/ if $key;
            given($key){
                # 不允许反向移动
                when('W'){ $move_direct = ( 3 == $move_direct )? 3 : 1 ; }
                when('A'){ $move_direct = ( 4 == $move_direct )? 4 : 2 ; }
                when('S'){ $move_direct = ( 1 == $move_direct )? 1 : 3 ; }
                when('D'){ $move_direct = ( 2 == $move_direct )? 2 : 4 ; }
                default { $move_direct; }
            }
            unshift @snake,[$snake[0][0]+$uldr[$move_direct][0],$snake[0][1]+$uldr[$move_direct][1]];
        }
    }
    #######################################################################################
    sub make_food{
        if(@snake < $full){
            my @empty_points=();
            foreach(1..$#bg-1){  
                my $y=$_;
                foreach(1..$#{$bg[0]}-1){
                    push @empty_points,[$y,$_] if($bg[$y][$_] eq ' ');
                }
            }  # 找出所有空的坐标点,存入@empty_points数组
            my $num=int( rand( scalar(@empty_points) ) );  # 随机取出@empty_points下标
            my ($y,$x)=@{ $empty_points[$num] }[0,1];
            $bg[$y][$x]='O';
            @food_coordinate=($y,$x);
            $food=1;
        }
    }
    #######################################################################################
    sub check_head{
        # 蛇身超出范围
        if($snake[0][0] < 1 || $snake[0][0] > HEIGHT-2 || 
           $snake[0][1] < 1 || $snake[0][1] > WIDTH-2 ){
                $alive=0;
        }
        # 蛇吃到自己
        if(@snake>3){
            foreach(1..$#snake){
                if($snake[0][0] == $snake[$_][0] &&  $snake[0][1] == $snake[$_][1]){
                    $alive=0;
                }
            }
        }
        # 移动
        if($bg[$snake[0][0]][$snake[0][1]] eq ' '){
            $bg[$snake[0][0]][$snake[0][1]]='@';
        }
        # 吃到食物
        if($bg[$snake[0][0]][$snake[0][1]] eq 'O'){
            $bg[$snake[0][0]][$snake[0][1]]='@';
            $score++;
            $food=0;
            &make_food;
            push @snake,[$snake[-1][0],$snake[-1][1]];  # 新的蛇身放在尾部
        }
        $bg[$snake[-1][0]][$snake[-1][1]]=' ';  # 先清除尾巴显示
        pop @snake;  # 去掉尾巴
        map{$bg[$snake[$_][0]][$snake[$_][1]]='#'}1..$#snake;  # 其他蛇身显示
    }
    View Code

      

  • 相关阅读:
    windows下python开发环境搭建
    看看两年前的我
    网络函数[00]函数总述
    网络函数[04]connect解析
    网络函数[08]网络读取函数解析
    网络函数[01]套接口地址图解
    网络函数[13]
    网络函数[07]accept解析
    网络函数[10]shutdown解析
    网络函数[14]
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/4595074.html
Copyright © 2011-2022 走看看