您的位置:首页 > 编程语言

编程之美读书笔记-中国象棋将帅问题

2016-09-10 12:40 239 查看
题目:用A表示将,B表示帅,请写出一个程序,输出A,B所有的合法位置。要求在代码中只能使用一个字节存储变量。
解析:需要存储的是A,B的位置信息,并且每次循环都要更新。首先创建一个逻辑坐标系统,一个可行的办法是用1-9的数字,按照行优先的顺序来表示每个格点的位置。这样,只需要用模余运算就可以得到当前的列号,从而判断A,B是否互斥。



一个8位的byte类型能够表达2^8=256个值,所以用它来表示A,B的位置信息绰绰有余,因此可以把这个字节的变量(设为b)分成两部分。用前面的4bit表示A的位置,用后面的4bit表示B的位置,而4个bit可以表示16个数,这已经足够了。

#include <iostream>
#define FULLMASK 255
//Max value of type char
#define HALF_BITS_LENGTH 4
// 记忆存储单元长度的一般
#define LMASK (FULLMASK<<HALF_BITS_LENGTH)
//把max value左移4位,得到1111 0000
#define RMASK (FULLMASK>>HALF_BITS_LENGTH)
//把max value右移4位,得到0000 1111
#define LSET(b,n) (b=((RMASK & b) | ((n) << HALF_BITS_LENGTH)))
//把b的左边设置为N
#define RSET(b,n) (b=((LMASK & b) | (n)))
//把b的右边设置为N
#define RGET(b) (RMASK & b)
//得到b右边的值
#define LGET(b) ((LMASK & b) >> HALF_BITS_LENGTH)
//得到b右边的值
#define MOVE_WIDTH 3
//表示将帅移动范围的宽度
using namespace std;

int main()
{
unsigned char b;
for (LSET(b, 1); LGET(b) <= MOVE_WIDTH*MOVE_WIDTH; LSET(b, (LGET(b) + 1)))
{
for (RSET(b, 1); RGET(b) <= MOVE_WIDTH*MOVE_WIDTH; RSET(b, (RGET(b) + 1)))
{
if (LGET(b) % MOVE_WIDTH != RGET(b) % MOVE_WIDTH)
{
cout << "将:" << LGET(b) <<" "<<"帅:" << RGET(b) << endl;
}
}
}
return 0;
}
还有更简洁的办法。可以把变量i看成一个两位九进制的变量,i/9即是此九进制数的第二位,i%9即是此九进制数的第一位。本程序用此九进制数的第二位保存A的位置,第一位保存B的位置。然后进行遍历,将符合条件的位置全部输出。
#include <iostream>
#define BYTE unsigned char

int main()
{
BYTE i = 81;
while (i--)
{
if ((i / 9) % 3 == (i % 9) % 3)
continue;
printf("A = %d, B = %d\n", i / 9 + 1, i % 9 + 1);
}
return 0;
}
另外一个思路也差不多。其中unsigned char a:4表示结构体中a的位域只有4位,高位用作它用。这种表示方式只能在结构体里使用,建议尽量少用,会破坏程序的移植性。
#include <iostream>

int main()
{
struct
{
unsigned char a : 4;
unsigned char b : 4;
}i;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: