【编程之美】妙用位域解中国象棋将帅问题

问题描述

  假设在中国象棋中只剩下将帅两个棋子,国人都知道基本规则:将帅不能出九宫格,只能上下左右移动,不能斜向移动,同时将帅不能照面。问在这样条件下,所有可能将帅位置。要求在代码中只能使用一个字节存储变量。

题目解答

  如果放弃只要一个字节存储变量的条件,这道题简直就是helloworld级别的题目,问题在于我们如何让两个for循环中的两个变量放在一个字节中,在开始的分析中,作者使用大量的位运算来使得两个变量存储在同一个字节中,程序变得就比较“臃肿”了。具体代码见下:

复制代码
 1 #include<stdio.h>
 2 #define HALF_BITS_LENGTH 4
 3 #define FULLMASK 255
 4 #define LMASK (FULLMASK << HALF_BITS_LENGTH)
 5 #define RMASK (FULLMASK >> HALF_BITS_LENGTH)
 6 #define RSET(b,n) (b = (b & LMASK) | (n))
 7 #define LSET(b,n) (b = ((b & RMASK) | ((n) << HALF_BITS_LENGTH)))
 8 #define RGET(b) (b & RMASK)
 9 #define LGET(b) ((b & LMASK)>>HALF_BITS_LENGTH)
10 #define GRIDW 3
11 
12 int main()
13 {
14     unsigned char b;
15     for(LSET(b,1);LGET(b) <= GRIDW * GRIDW;LSET(b,(LGET(b)+1)))
16     {
17         for(RSET(b,1);RGET(b) <= GRIDW * GRIDW;RSET(b,(RGET(b))+1))
18         {
19             if(LGET(b) % GRIDW != RGET(b) % GRIDW)
20             {
21                 printf("A=%d,B=%d\n",LGET(b),RGET(b));
22             }
23         }
24     }
25     return 0;
26 }
复制代码

   然而上面的方法是在是太繁琐了,在题目的最后,给出了使用“位”域实现该题目的简洁方法。

  位域在百度百科中的解释是:“位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。”

  位域的定义方式类似于结构体:

  struct  位域结构名 { 位域列表 };

    其中位域列表的形式为: 类型说明符 位域名:位域长度。
  例如: struct bs {int a:8;int b:2;int c:6;};
  
  有了位域这个好东西,我们可以直接指定一个位的前四位和后四位为一个位结构体的两个子成员,相当于我们有了定义两个变量的能力。问题迎刃而解,具体代码如下:
复制代码
 1 #include<stdio.h>
 2 struct {
 3     unsigned char a:4;
 4     unsigned char b:4;
 5 } i;
 6 int main()
 7 {
 8     for(i.a = 1; i.a <= 9;i.a++)
 9         for(i.b = 1;i.b <=9;i.b++)
10             if(i.a % 3 != i.b % 3)
11                 printf("A=%d,B=%d\n",i.a,i.b);
12     return 0;
13 }
复制代码

 

参考文献:

1. 《编程之美》P13-P15

2. 百度百科:位域 http://baike.baidu.com/view/1256879.htm

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值