iOS实现苏拉卡尔塔吃子算法

代码我开源在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组的路径即可

你可能感兴趣的:(iOS实现苏拉卡尔塔吃子算法)