代码我开源在GitHub上了
GitHub
iOS实现苏拉卡尔塔棋盘
在查阅资料以及参考了别人的吃子算法后,我写出了自己的吃子算法
属性
这里需要用到五个属性
@property(assign,nonatomic)NSInteger flyX;
@property(assign,nonatomic)NSInteger flyY;
@property(strong,nonatomic)NSMutableArray *flyPath;
@property(strong,nonatomic)NSMutableArray *finishFlyPath;
@property(strong,nonatomic)NSMutableArray *placeArray;
因为吃子算法需要拿到飞行的路径好做飞行的动画,所以传出来的最终是一个二维数组,因为有可能有好几条路径吃不同的棋子,这里分别是飞行x,y坐标,飞行的子数组,飞行的传出数组还有棋盘,其中finishFlyPath数组里包含着flyPath数组
方法
先放上第一个方法的代码
- (void)beginFlyWithX:(NSInteger)x Y:(NSInteger)y Camp:(NSInteger)camp placeArray:(NSMutableArray*)plaArray{
_flyPath = [[NSMutableArray alloc]init];
_finishFlyPath = [[NSMutableArray alloc]init];
_placeArray = plaArray;
for (int i = UP_TO_FLY; i<=LEFT_TO_FLY; i++) {
_flyX = x;
_flyY = y;
[self flyEngine:x Y:y Direction:i Camp:camp CanFly:false];
}
}
这里在for循环里调了第二个方法,其中的宏是
#define UP_TO_FLY 0 // 上飞行
#define RIGHT_TO_FLY 1 // 右飞行
#define DOWN_TO_FLY 2 // 下飞行
#define LEFT_TO_FLY 3 // 左飞行
可以看出来这个for循环的意思就是向四个可以飞行的方向做运算
在说flyEngine这个方法之前先说一个方法
- (BOOL)canFlyWtihDircetion:(NSInteger)dircetion{
switch (dircetion) {
case UP_TO_FLY:{
_flyX -= 1;
if (_flyX < 0) {
_flyX += 1;
return false;
}else{
return true;
}
}
case RIGHT_TO_FLY:{
_flyY += 1;
if (_flyY > 5) {
_flyY -= 1;
return false;
}else{
return true;
}
}
case DOWN_TO_FLY:{
_flyX += 1;
if (_flyX > 5) {
_flyX -= 1;
return false;
}else{
return true;
}
}
case LEFT_TO_FLY:{
_flyY -= 1;
if (_flyY < 0) {
_flyY += 1;
return false;
}else{
return true;
}
}
default:
break;
}
return false;
}
这个方法的作用就是往传进来的方向(上下左右)向前走一步看看有没有棋子,没有棋子就说明可以向那个方向飞,通过不断调用这个方法就可以判断出飞行路线上有没有棋子了
- (void)flyEngine:(NSInteger)x Y:(NSInteger)y Direction:(NSInteger) dircetion Camp:(NSInteger)camp CanFly:(BOOL)alreadyFly{
if ((_flyX == 0 && _flyY == 0) || (_flyX == 5 && _flyY == 0) || (_flyX == 0 && _flyY == 5) || (_flyX == 5 && _flyY == 5)) {
return;
}
while ([self canFlyWtihDircetion:dircetion]) {
YZChessPlace *p = _placeArray[_flyX][_flyY];
if (p.camp != 0) {
if (p.camp + camp == 0) {
//敌方棋子
if (alreadyFly) {
[_flyPath addObject:p];
//可以飞行了
if (_flyPath.count > 5) {
//飞行溢出情况
NSMutableArray *bugArray = [self bugArrayWithFlyArray:_flyPath];
[_finishFlyPath addObject:bugArray.copy];
[bugArray removeAllObjects];
[_flyPath removeAllObjects];
}else {
[_finishFlyPath addObject:_flyPath.copy];
[_flyPath removeAllObjects];
}
return;
}else{
[_flyPath removeAllObjects];
return;
}
}else{
//自己棋子
if (_flyX == x && _flyY == y) {
if (_flyPath.count < 6) {
continue;
}else{
return;
}
}else{
//和起点不同
[_flyPath removeAllObjects];
return;
}
}
}
}
if ((_flyX == 0 && _flyY == 0) || (_flyX == 5 && _flyY == 0) || (_flyX == 0 && _flyY == 5) || (_flyX == 5 && _flyY == 5)) {
return;
}
YZChessPlace *pp = _placeArray[_flyX][_flyY];
[_flyPath addObject:pp];
NSArray *pathwayArray = [YZChessPlace pathwayTable:_flyX Y:_flyY];
if (pathwayArray.count > 0) {
NSNumber *nX = pathwayArray[0];
NSNumber *nY = pathwayArray[1];
_flyX = [nX integerValue];
_flyY = [nY integerValue];
}
YZChessPlace *ppp = _placeArray[_flyX][_flyY];
if (ppp.camp != 0) {
if (ppp.camp + camp == 0) {
[_flyPath addObject:ppp];
//可以飞行了
if (_flyPath.count > 5) {
//飞行溢出情况
NSMutableArray *bugArray = [self bugArrayWithFlyArray:_flyPath];
[_finishFlyPath addObject:bugArray.copy];
[bugArray removeAllObjects];
[_flyPath removeAllObjects];
}else {
[_finishFlyPath addObject:_flyPath.copy];
[_flyPath removeAllObjects];
}
return;
}else{
[_flyPath removeAllObjects];
return;
}
}else{
dircetion = [YZChessPlace directionTable:_flyX Y:_flyY];
[self flyEngine:x Y:y Direction:dircetion Camp:camp CanFly:true];
}
}
第一个if语句其实就是那四个角落是不可以飞行的,直接return就好了,这个while语句里面判断了具体的敌我关系以及能不能飞行
if ((_flyX == 0 && _flyY == 0) || (_flyX == 5 && _flyY == 0) || (_flyX == 0 && _flyY == 5) || (_flyX == 5 && _flyY == 5)) {
return;
}
在while之后,其实是已经在一个方向上走到尽头了,需要绕圈了。考虑到需要做动画,所以要把走到尽头的那个点放进数组
YZChessPlace *pp = _placeArray[_flyX][_flyY];
[_flyPath addObject:pp];
接下来就是绕圈之后可不可以吃子的判断了,如果还不可以吃子就递归调用这个方法,直到发现不能吃子或者拿到全部的吃子位置return掉
dircetion = [YZChessPlace directionTable:_flyX Y:_flyY];
[self flyEngine:x Y:y Direction:dircetion Camp:camp CanFly:true];
其中directionTable是
+ (NSInteger)directionTable:(NSInteger)x Y:(NSInteger)y{
switch (x) {
case 0:{
if (y == 1 || y == 2 || y == 3 || y ==4) {
return DOWN_TO_FLY;
}
break;
}
case 1:{
if (y == 0) {
return RIGHT_TO_FLY;
}
if (y == 5) {
return LEFT_TO_FLY;
}
break;
}
case 2:{
if (y == 0) {
return RIGHT_TO_FLY;
}
if (y == 5) {
return LEFT_TO_FLY;
}
break;
}
case 3:{
if (y == 0) {
return RIGHT_TO_FLY;
}
if (y == 5) {
return LEFT_TO_FLY;
}
break;
}
case 4:{
if (y == 0) {
return RIGHT_TO_FLY;
}
if (y == 5) {
return LEFT_TO_FLY;
}
break;
}
case 5:{
if (y == 1 || y == 2 || y == 3 || y ==4) {
return UP_TO_FLY;
}
break;
}
default:
break;
}
return -1;
}
可以看出来这个是为绕圈指明方向用的
最后是在做动画的过程中发现有一种可能是绕4个圈才吃到,然后就会发生把所有的可以走的路线都放进去的情况。实际上flyPath这个数组最后一个元素(可以吃的子)是正确的。为了解决这个问题,我写了一个方法用来处理飞行溢出,能让动画顺利的进行
- (NSMutableArray*)bugArrayWithFlyArray:(NSMutableArray*)flyArray{
NSMutableArray *bugArray = [[NSMutableArray alloc]init];
if (flyArray.count == 8 || flyArray.count == 12) {
[bugArray addObject:flyArray[flyArray.count-4]];
[bugArray addObject:flyArray[flyArray.count-3]];
[bugArray addObject:flyArray[flyArray.count-2]];
[bugArray addObject:flyArray[flyArray.count-1]];
}else {
for (int i=(int)flyArray.count / 4 * 4; i
实际上目的就是把后面4个元素取出来用,因为刚才说了是绕了4个圈才会出现的特殊bug,所以这里面的数组出问题的就是4个4个一组的元素太多了,一个数组里面包含的路径不止一条,最后会导致动画绕来绕去才飞到吃子的地方。我们这里因为有很多条路径可以选,所以选最简单的最后一条4组的路径即可