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

任务难度: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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值