中国象棋将帅问题
问题提出:将和帅想个遥远,且不能照面。在象棋残局中,许多高手利用这一规则走出精妙的杀招。假设棋盘上只有将和帅,请写出一个程序,输出将和帅的所有合法位置。要求代码只能使用一个字节存储变量。(为方便A表示将B表示帅)
分析和解法:我们想到的应该使用遍历解决即:遍历A的位置
遍历B的位置
判断A、B是否合法
如果满足则输出
1、 存储A、B的位置信息,我们可以建立一个坐标系统, 如下图按从左到右从上到下标上1 2 3 …… 9。这样只需用模余运算就能得到当前的列号,从而判断A、B位置是否合法
2、 寻求单字节变量,我们可以用byte类型,一个byte类型变量8字节, 2^8 = 256 ,足以用来表示A、B位置信息。
3、如何使用bit级运算将数据从这一byte变量的左边和右边分别存入和读出?
①、将byte b(10100101) 的右边4bit(0101)设为n(0011)
首先清除b右边的bits,同时保持左边的bits
1111 0000 & 1010 0101 == 1010 0000(b)
然后将上一步得到的结果与n做或运算
1010 0000 | 0000 0011 == 1010 0011
②、 将byte b(10100101) 的左边4bit(1010)设为n(0011)
首先清除b左边的bits,同时保持右边的bits
0000 1111 & 1010 0101 == 0000 0101(b)
把n移动到byte数据的左边
n << 4 == 0011 0000
然后再或运算 0000 0101 | 0011 0000 == 0011 0101
三、 得到byte数据的右边4bits 或 左边4bits(eg. 1010 0101 中的1010 和 0101):
清除b左边的bits,同时保持右边的bits
0000 1111 & 1010 0101(b) = =0000 0101
清除b右边的bits,同时保持左边bits
1111 0000 & 1010 0101 (b) == 1010 0101
将结果右移4bits
1010 0000 >> 4 == 0000 1010
3 、 如何在不声明其他变量约束的前提下创建一个for循环。可以重复利用1byte的存储单元,把它作为循环计数器并用前面提到的存储和读出技术进行操作。
代码:
#include<stdio.h>
#define HALF_BITS_LENGTH 4
// 存储记忆单元长度的一半, 4bit
#define FULLMASK 255
//这个宏表示一个全部bit的mask,它是 1111 1111
#define LMASK (FULLMASK << HALF_BITS_LENGTH)
// 这个宏表示左bit, 它是1111 0000
#define RMASK (FULLMASK >> HALF_BITS_LENGTH)
// 这个宏表示右bit,它是0000 1111
#define RSET(b,n) (b = ( (LMASK & b) | n ) )
//将b的右边设置成n
#define LSET(b,n) (b = ( (RMASK & b) | ( n << HALF_BITS_LENGTH )) )
//将b的左边设置成n
#define RGET(b) (RMASK & b)
//得到b右边的值
#define LGET(b) ((LMASK & b)>>HALF_BITS_LENGTH)
//得到b左边的值
#define GRIDW 3
// 将和帅的移动范围
int mian()
{
unsigned char b;
for( LSET(b,1); LGET(b)<= GRIDW * GRIDW; LSET( b,( LSET(b)+1 )) )
for( RSET(b,1); RGET(b) <= GRIDW*GRIDW; RSET( b,(RSET(b)+1) ) )
if(LGET(b)%GRIDW != RGET(b)%GRIDW )
printf("A = %d, B = %d\n",LGET(b),RGET(b) );
return 0;
}