| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3231 人关注过本帖
标题:说说你见过哪些拍案叫绝的C代码?
只看楼主 加入收藏
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9007
专家分:53942
注 册:2011-1-18
收藏
得分:0 
回复 10楼 lin5161678
赞同!
但迷信的人多了,现在的编译器不得不加入了一段优化,就是将这些“利用异或交换变量”的代码片段更换为正常方法。
2021-05-28 10:35
请输入密码
Rank: 2
等 级:论坛游民
威 望:5
帖 子:35
专家分:84
注 册:2020-11-19
收藏
得分:0 
最近我们这边看到有人在聊推箱子的游戏制作,于是我自己做了个出来。参考过各个版本不同的代码,这个版本的代码主要有两个特点。

第一个是“箱子”和“人”都是用同一套移动判定逻辑,可以人推箱子可以理解成“箱子自己独立移动”和“人自己独立移动”,就省略多种情况了。

这是把箱子代入移动逻辑函数里面的代码。
    if ( m[new_self[0]][new_self[1]] & 0b010 )
             move(m,com,new_self);


第二是用位运算的形式,通俗理解箱子和目的地的逻辑关系。

第一位是主角,第二位是箱子,第三位是目的地。

核心移动逻辑就move函数里面的两句:

*t2 |= ( (*t1) & 0b011 );
*t1 &= 0b100;



附上完整代码,仅供参考(手机党没用电脑测试,不敢保证大环境下能运行正常)

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define W 15
#define H 15

enum COMD
{
    EMPTY,
    UP,
    DOWN,
    LEFT,
    RIGHT
};

unsigned g_f = 0;
unsigned g_nf = 0;
char M[H][W] =
{
    {8,8,8,8,8,8,8,8,8},
    {8,8,0,0,8,8,8,8,8},
    {8,8,2,0,0,0,2,0,8},
    {8,8,0,4,8,4,0,0,8},
    {8,8,0,8,8,8,0,8,8},
    {8,0,1,4,8,4,0,8,8},
    {8,0,2,0,0,0,2,8,8},
    {8,8,0,8,8,0,0,8,8},
    {8,8,8,8,8,8,8,8,8}
};

void find_id( char[][],int[] );
void fun( char[][], int[] );
int get_com( char[][],int[] );
int move( char[][],int[],int[] );
int judge_move (char[][],int[],int[] );
int check_win( char[][] );
void print( char[][] );

int main( void )
{
    int point[2] = {0,0};
    
    find_id(M,point);
    print(M);
    
    if (!check_win(M))
        while ( !fun(M,point));
    
    puts("恭喜过关!");

    return 0;
}

void fun( char m[H][W], int self[2] )
{
    int com[2] = {0,0};
    int new_self[2] = {0,0};
    
    if (get_com(M,com) == 0 )
        return ;
    
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];
    
    if ( m[new_self[0]][new_self[1]] & 0b010 )
             move(m,com,new_self);
    
    if ( !move(m,com,self))
        return ;
        
     self[0] = new_self[0];
     self[1] = new_self[1];
     
     print(M);
     
     return check_win(M);
}

int get_com( char m[H][W],int re_com[] )
{
    static char C[256] = {0};
    
    C['w'] = UP;
    C['s'] = DOWN;
    C['a'] = LEFT;
    C['d'] = RIGHT;
    C['W'] = UP;
    C['S'] = DOWN;
    C['A'] = LEFT;
    C['D'] = RIGHT;
    C[72] = UP;
    C[80] = DOWN;
    C[75] = LEFT;
    C[77] = RIGHT;
    
    int com[2] =
    {0,0};
    
    char ch = 0;

        ch= getch();
    
    unsigned flag = 1;
    
    switch (C[ch])
    {
        case UP:
            com[0] = -1;break;
        case DOWN:
            com[0] = 1;break;
        case LEFT:
            com[1] = -1;break;
        case RIGHT:
            com[1] = 1;break;
        default: flag = 0;
            break;
    }
    
    re_com[0] = com[0];
    re_com[1] = com[1];
    
    return flag;
}

int move( char m[H][W],int com[],int self[] )
{
    int new_self[2] ={0,0};
    
    char* t1 = NULL;
    char* t2 = NULL;
    
    if (!judge_move(m,com,self))
        return 0;
        
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];
    
    t1=&m[self[0]][self[1]];
    t2=&m[new_self[0]][new_self[1]];
    
     *t2 |= ( (*t1) & 0b011 );
     
    if ( *t2 == 0b110 )
        ++g_nf;
        
    if ( *t1 == 0b110 )
        --g_nf;
        
     *t1 &= 0b100;
    
    return 1;
}

int judge_move ( char m[H][W],int com[],int self[] )
{
    static int j_c[20] = {1,0,0,0,1,0,0,0,0,0,0};
    
    int new_self[2];
    
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];

    return  j_c[m[new_self[0]][new_self[1]]];
}
void find_id( char m[H][W],int self[] )
{
    
    size_t i;
    size_t j;
    
    unsigned flag = 0;
    
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W; ++ j )
            if ( ( m[i][j] & 0b001 ) && flag <=1 )
              {
                  self[0] = i;
                  self[1] = j;
                  ++flag;
              }
              else if ( m[i][j]& 0b100 )
                  ++g_f;
      
      if ( flag == 1 )
          return ;
      else if (flag == 0 )
          puts("没有起点!");
        else
            puts("起点不止一个");
      
      exit(EXIT_FAILURE);
          
}

int check_win( char m[H][W] )
{        
      return g_f ==g_nf;
}

void print( char m[H][W] )
{
    
    static char s_c[] =
       { ' ','O','@','?','X','S','$','?','#','#','#','#','#','#'};
    
    size_t i;
    size_t j;
    
    system("cls");
    
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W + 1; ++ j )            putchar(j != W?s_c[m[i][j]]:'\n');
     
    puts("");
    
}


初接触推箱子代码往往看着要讨论的情况很多,其实核心逻辑两行代码就解决了,而且的确不难理解。

[此贴子已经被作者于2021-5-30 23:08编辑过]


Bug易改,码风难移。
有事离开,无事灌水。
2021-05-30 21:48
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9007
专家分:53942
注 册:2011-1-18
收藏
得分:0 
void find_id( char[][],int[] );
这能编译通过?
2021-05-31 08:36
请输入密码
Rank: 2
等 级:论坛游民
威 望:5
帖 子:35
专家分:84
注 册:2020-11-19
收藏
得分:0 
回复 13楼 rjsp
我这边C4driod没问题,说不能编译通过也不觉得太奇怪,毕竟测试环境十分有限。

Bug易改,码风难移。
有事离开,无事灌水。
2021-05-31 15:09
请输入密码
Rank: 2
等 级:论坛游民
威 望:5
帖 子:35
专家分:84
注 册:2020-11-19
收藏
得分:0 
找个时间又了解了各个版本的迷宫代码,勉强弄了个来凑合看。不过这个代码不作讲解了,只能勉强凑合。不考虑最短路径的情况下还是可以理解的。

不敢保证大环境下能正常运行,重点看实现方面的逻辑结构就行。

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define H 10
#define W 15

char M[H][W] =
{
    {8,8,8,8,8,8,8,8,8,8,8,8},
    {8,8,5,8,8,8,8,8,8,8,8,8},
    {8,5,5,5,5,5,5,5,5,8,8,8},
    {8,8,8,5,5,5,5,8,5,5,5,8},
    {8,8,8,5,5,7,8,8,8,8,5,8},
    {8,5,5,5,5,5,5,5,5,5,5,8},
    {8,5,8,8,8,5,5,8,5,5,8,8},
    {8,5,8,8,8,8,5,8,8,5,8,8},
    {8,5,5,5,6,8,5,5,5,5,5,8},
    {8,8,8,8,8,8,8,8,8,8,8,8}
};

void find_id( char[][],int*,int* );
void fun( char [][],int,int );
int judge_move( char[][],int,int,int );
void re_way( char[][],int[][],int,int );
void print( char[][] );

int main( void )
{
    
    int x;
    int y;
    
    find_id(M,&x,&y);
    
    fun(M,x,y);
    
    return 0;
}

void fun( char m[H][W],int x,int y )
{
    int com[4][2] =
    {
        {0,-1},{-1,0},{0,1},{1,0}
    };
    
    int t_x = x;
    int t_y = y;
    
    int div = 0;
    
    int mark = 0;
    int flag;
        
    while (1)
    {
        const int t_div = ( div + 3 ) % 4;        
        const int d_x = com[t_div][0];
        const int d_y = com[t_div][1];
        
        flag = judge_move( m,x + d_x, y + d_y,t_div );
    
       if ( flag == 0 )
        {
            m[x][y] = div = t_div;
            x += d_x;
            y += d_y;
        }
       else if ( flag == 1)
            div = (++div % 4);
        else if ( flag == 2)
        {
            m[x][y] = t_div;
            break;
        }
        
        if (  x == t_x && y == t_y &&  ( ++mark == 4 ) )
            break;
    }

    if ( flag == 2 )
         re_way(m,com,t_x,t_y);
     else
     {
         m[x][y] = 6;
         print(m);
         puts("没路!");
     }
}

int judge_move( char m[H][W],int x,int y,int t_div )
{     
    #define ABS(n) ((n) >= 0 ? (n) : (-(n)))
    
     if ( m[x][y] == 7 )
         return 2;
          
     if ( m[x][y] == 5 )
         return 0;
         
     return ( m[x][y] == 8 || ( ABS(m[x][y] - t_div) != 2 ));
             
    #undef ABS
}

void re_way( char m[H][W],int com[4][2],int x,int y )
{
    while ( m[x][y] != 7 )
    {
        const int t = m[x][y];
        
        m[x][y] +=10;
        x += com[t][0];
        y += com[t][1];
        
        print(m);
        
        getch();
    }
}

void print( char m[H][W] )
{
    static char s_c[] =
    { ' ',' ',' ',' ','*',' ','O','X','#','$','<','^','>','v'};
    
    size_t i;
    size_t j;
    
    system("cls");
    
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W + 1; ++ j )
                putchar(j != W?s_c[m[i][j]]:'\n');
}

void find_id( char m[H][W], int* x,int* y )
{
    
    size_t i;
    size_t j;
    
    unsigned flag = 0;
    
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W; ++ j )
            if ( ( m[i][j] ==6 ) && flag <=1 )
              {
                  *x = i;
                  *y = j;
                  ++flag;
              }
      
      if ( flag == 1 )
          return ;
      else if (flag == 0 )
          puts("没有起点!");
        else
            puts("起点不止一个");
      
      exit(EXIT_FAILURE);
}


逐步输出路径能更直观。

[此贴子已经被作者于2021-6-1 00:25编辑过]


Bug易改,码风难移。
有事离开,无事灌水。
2021-05-31 22:34
请输入密码
Rank: 2
等 级:论坛游民
威 望:5
帖 子:35
专家分:84
注 册:2020-11-19
收藏
得分:0 
回复 10楼 lin5161678
以下是引用lin5161678在2021-5-28 09:29:12的发言:


^异或交换是非常糟糕的做法 没有任何优点
可读性 没有优势
运行效率低于 第三变量交换


从可读性和运行效率上的确没有任何优势。虽然运行结果一样,但是,异或交换和第三变量交换的表述过程不同。前者是没有另外开辟空间交换,后者需要。如果需要表述你自己在地图上前进一格,地图上的数据相当于是“自己”和“空”的位置交换。如果用第三变量写,那“第三空间”含义是什么?“第三空间”的位置在哪?但如果用异或交换,表述含义就是两者位信息置叠加转换(原子操作)。这样反而更贴近于程序的表述过程本质。

当然如果实在需要通过或者需要展示第三者空间,含实义的空间,那就用第三变量交换,因为表述过程实实在在存在第三空间。

只是程序除了考虑运算结果,运算过程,运算过程的表述含义也是需要的,例如坐汽车和走路到达目的地,虽然最后结果相同都是到达目的地,但是他们的过程展现方式却是不同的,因此从“表述方式”层面上理解也是不相同的。

说到底,无论那种表述形式,也无多过意强求,看情况合适就行。只是想说,运算不仅除了运算过程和运算结果,过程表达形式也是程序运行的“灵魂”所在。

Bug易改,码风难移。
有事离开,无事灌水。
2021-06-03 14:27
小七同学
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2021-8-22
收藏
得分:0 
阿巴阿巴
2021-08-25 11:07
OWORD
Rank: 2
等 级:论坛游民
帖 子:2
专家分:10
注 册:2021-9-11
收藏
得分:0 
char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}


打印自身,忘了在哪看的了
2021-09-11 21:49
lin5161678
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:45
帖 子:1136
专家分:3729
注 册:2011-12-3
收藏
得分:0 
以下是引用请输入密码在2021-6-3 14:27:32的发言:



从可读性和运行效率上的确没有任何优势。虽然运行结果一样,但是,异或交换和第三变量交换的表述过程不同。前者是没有另外开辟空间交换,后者需要。如果需要表述你自己在地图上前进一格,地图上的数据相当于是“自己”和“空”的位置交换。如果用第三变量写,那“第三空间”含义是什么?“第三空间”的位置在哪?但如果用异或交换,表述含义就是两者位信息置叠加转换(原子操作)。这样反而更贴近于程序的表述过程本质。

当然如果实在需要通过或者需要展示第三者空间,含实义的空间,那就用第三变量交换,因为表述过程实实在在存在第三空间。

只是程序除了考虑运算结果,运算过程,运算过程的表述含义也是需要的,例如坐汽车和走路到达目的地,虽然最后结果相同都是到达目的地,但是他们的过程展现方式却是不同的,因此从“表述方式”层面上理解也是不相同的。

说到底,无论那种表述形式,也无多过意强求,看情况合适就行。只是想说,运算不仅除了运算过程和运算结果,过程表达形式也是程序运行的“灵魂”所在。

牵强附会
异或交换不需要第三变量 但是需要把计算结果暂存到变量1 请问 暂存结果的变量是什么含义? 空间重叠??虫洞算法吗

原子操作的含义是 不会被线程调度机制打断的操作
众所周知 异或并赋值 那是不同的汇编指令 并不是原子操作


https://zh.
2021-09-12 09:02
我善治鬼
Rank: 5Rank: 5
等 级:贵宾
威 望:17
帖 子:107
专家分:181
注 册:2015-2-16
收藏
得分:0 
我认为异或和直接赋值交换的速度是一样的,
因为它们都需要进行3次赋值操作, 3次赋值说明进行了3次内存复制操作, 所以开销是一样的,
Windows GDI使用 & | ^ 等运算符将位图复制到显示器, 实际上直接复制和异或复制速度是差不多的,
两者都是跟源变量进行复制操作, 或计算源变量跟新变量不同, 进行覆盖操作, 所以, 直接操作源变量变化和直接使用新变量复制速度是一样的.

图片附件: 游客没有浏览图片的权限,请 登录注册
2021-09-12 19:38
快速回复:说说你见过哪些拍案叫绝的C代码?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027056 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved