【游戏之乐】中国象棋 让你学会位运算

来源:互联网 发布:淘宝优惠券转手机端 编辑:程序博客网 时间:2024/05/21 09:27

任务难度:3

任务说明:

在中国象棋里,当只剩下将帅(A和B代指将和帅)两个棋子时  将帅不能处于同一列  要求输出将帅的所有合法位置(将帅所在的九宫格从上到下从左至右编号为1~9)
例如:
    合法位置:
    A=1,B=2
    不合法位置:
    A=1,B=1
要求:只能使用一个变量

 

乍一看问题并不难,但是最后的要求是只能使用一个变量,这也是好玩之处~~

先让我们思考一下A和B的状态共有多少种,九宫格的9个位置,即各有9种状态,9需要用4bit来存储,储存AB两种状态则至少需要8bit,即一个BYTE

那么主体思想就是我们通过某种循环方式,分别枚举AB状态的所有值(1~9)当两个状态的%3即为两个状态的列数相同时,则不能输出,否则输出

 

接下来介绍三种方法,让你学会位运算:

方法一:

假设我们开一个BYTE型的变量b,用左边的4bit存储B的状态,用右边的4bit存储A的状态,我们需要实现4种操作,即取出该变量的左边四位或右边四位,将该变量的左边四位或右边四位设置为n值(n取1~9)

 

取出右边的值只需要将变量b与00001111(RMASK)相与即可,取出左边四位的值只需要先将b与11110000(LMASK)相与,再右移四位即可

而将右边的值改为n 就需要将左边的值先保留下来 即将变量b与11110000相与,然后再和n异或即可

而将左边的值改为n 就需要将右边的值先保留下来,即将变量b与00001111相与,然后再和右移四位后的n异或即可

 

我们用四个宏定义的函数实现上述功能,循环枚举的时候只需要先将b的左右置为1,然后每次多置1即可,代码如下:

#include <cstdio>#include <windows.h>/*解法一*/#define HALF_BIT_LENGTH 4//因为要频繁使用左右移4位的操作,这里把4宏定义出来#define FULLMASK 255//即11111111 用于得出LMASK和RMASK#define LMASK (FULLMASK<<HALF_BIT_LENGTH)//将11111111左移4位 即得到11110000#define RMASK (FULLMASK>>HALF_BIT_LENGTH)//即00001111#define RGET(b) (b & RMASK)//得到右4位#define LGET(b) ((b& LMASK)>>HALF_BIT_LENGTH)//得到左4位#define RSET(b,n) (b= (b & LMASK)^n)//将右四位置为n#define LSET(b,n) (b= (b & RMASK)^(n<<HALF_BIT_LENGTH))//将左四位置为n#define GRIDW 3//由于求列数时需要对3取余,这里也宏定义出来int main(){unsigned char b;for (RSET(b,1);RGET(b)<=GRIDW*GRIDW;RSET(b,(RGET(b)+1))){//枚举右四位从1到9的情况,即枚举A的9种状态for (LSET(b,1);LGET(b)<=GRIDW*GRIDW;LSET(b,(LGET(b)+1))){//枚举左四位1到9的情况,即枚举B的9种状态if (RGET(b)%GRIDW!=LGET(b)%GRIDW)//列数不同则表示AB位置合法{printf("A=%d, B=%d\n",RGET(b),LGET(b));}}}return 0;}


 

是不是感觉很奇妙呢?这就是位运算的妙用,接下来介绍两种更为简便的方法

 

方法二:我们将AB的所有状态排列组合,其实只有81种组合方式,我们直接定义一个BYTE变量i表示AB位置的排列方式,i=1表示A为1 B为1

用i/9+1表示A i%9+1表示B i的取值范围为1~81  想一想这样是不是涵盖了A与B分别取1~9的81种情况

代码如下:

#include <cstdio>#include <windows.h>BYTE i=0;int main(){for (;i<=81;i++){if ( i/9%3 != i%9%3){printf("A=%d, B=%d\n",i/9+1,i%9+1);}}return 0;


 

接下来介绍最后一种方法 最简单也最容易理解 直接创建一个大小为BYTE的struct变量 将BYTE的前4位和后4位分开直接设为两个成员变量

代码如下:

#include <cstdio>#include <windows.h>struct  {unsigned char a:4;unsigned char b:4;}i;int main(){for (i.a=1;i.a<=9;i.a++){for (i.b=1;i.b<=9;i.b++){if (i.a%3!=i.b%3){printf("A=%d, B=%d\n",i.a,i.b);}}}return 0;


 

怎么样 是不是很有意思呢?
0 0
原创粉丝点击