如何在if-than语句中处理大量条件?

时间:2015-09-28 13:42:54

标签: objective-c if-statement

我最近在Objective-C中构建了一个Tic Tac Toe游戏,同时专注于尽可能地使我的代码尽可能简洁(因为我对编程相对较新,这是我第一次专注于提高效率) /可读而不是让它不惜任何代价工作)

在大多数情况下,我能够使我的代码简短而有效,以至于我对它感到满意 - 除了检查X或O是否赢得游戏的checkWin函数部分

我有一个名为“BoardState”的NSArray对象,索引0-8对应板上的9个点,如此

0 1 2
3 4 5
6 7 8

当索引设置为0时,它被视为空白。 1是X,2是O.

但是,我能弄清楚如何检查X或O是否赢了的唯一方法是用if语句手动检查整个板子并检查所有可能性,如此

if  (
    ([_boardState[0] isEqual:@1]  &&
     [_boardState[1] isEqual:@1]  &&
     [_boardState[2] isEqual:@1]) ||

    ([_boardState[3] isEqual:@1]  &&
     [_boardState[4] isEqual:@1]  &&
     [_boardState[5] isEqual:@1]) ||

    ([_boardState[6] isEqual:@1]  &&
     [_boardState[7] isEqual:@1]  &&
     [_boardState[8] isEqual:@1]) ||

    ([_boardState[0] isEqual:@1]  &&
     [_boardState[3] isEqual:@1]  &&
     [_boardState[6] isEqual:@1]) ||

    ([_boardState[1] isEqual:@1]  &&
     [_boardState[4] isEqual:@1]  &&
     [_boardState[7] isEqual:@1]) ||

    ([_boardState[2] isEqual:@1]  &&
     [_boardState[5] isEqual:@1]  &&
     [_boardState[8] isEqual:@1]) ||

    ([_boardState[0] isEqual:@1]  &&
     [_boardState[4] isEqual:@1]  &&
     [_boardState[8] isEqual:@1]) ||

    ([_boardState[2] isEqual:@1]  &&
     [_boardState[4] isEqual:@1]  &&
     [_boardState[6] isEqual:@1])
     ){
    [xWins show];
    [self overWriteBoardState];
}
然后再次,与O,几乎完全相同的事情。

if  (
     ([_boardState[0] isEqual:@2]  &&
      [_boardState[1] isEqual:@2]  &&
      [_boardState[2] isEqual:@2]) ||

     ([_boardState[3] isEqual:@2]  &&
      [_boardState[4] isEqual:@2]  &&
      [_boardState[5] isEqual:@2]) ||

     ([_boardState[6] isEqual:@2]  &&
      [_boardState[7] isEqual:@2]  &&
      [_boardState[8] isEqual:@2]) ||

     ([_boardState[0] isEqual:@2]  &&
      [_boardState[3] isEqual:@2]  &&
      [_boardState[6] isEqual:@2]) ||

     ([_boardState[1] isEqual:@2]  &&
      [_boardState[4] isEqual:@2]  &&
      [_boardState[7] isEqual:@2]) ||

     ([_boardState[2] isEqual:@2]  &&
      [_boardState[5] isEqual:@2]  &&
      [_boardState[8] isEqual:@2]) ||

     ([_boardState[0] isEqual:@2]  &&
      [_boardState[4] isEqual:@2]  &&
      [_boardState[8] isEqual:@2]) ||

     ([_boardState[2] isEqual:@2]  &&
      [_boardState[4] isEqual:@2]  &&
      [_boardState[6] isEqual:@2])
     ){
    [oWins show];
    [self overWriteBoardState];
}

作为奖励,我的overWriteBoardState函数将电路板重置为无法再修改的空白平板。这也可以更有效率

-(void)overWriteBoardState {
    self.boardState[0] = @3;
    self.boardState[1] = @3;
    self.boardState[2] = @3;
    self.boardState[3] = @3;
    self.boardState[4] = @3;
    self.boardState[5] = @3;
    self.boardState[6] = @3;
    self.boardState[7] = @3;
    self.boardState[8] = @3;
}

我还能如何构建这个以避免这些大量的重复行?任何帮助或提示表示赞赏 - 谢谢!

4 个答案:

答案 0 :(得分:2)

首先是数据存储。鉴于您正在处理一个小的固定大小的三态值数组,我建议使用uint8_t01使用2的简单C数组。您已经提到的编码,而不是NSArray,因为Objective-C集合类只能存储对象。

然后,你需要研究每个索引模式中关于行和行的关系,并迭代基值。

例如:

//
// Keep this in your comments, as it's invaluable:
//
// 0 1 2
// 3 4 5
// 6 7 8
//

BOOL didWinAcross(const uint8_t *board, uint8_t side)
{
    BOOL didWin = NO;
    for (unsigned row = 0; row < 3 && !didWin; row++) {
        didWin =
            board[row * 3 + 0] == side &&
            board[row * 3 + 1] == side &&
            board[row * 3 + 2] == side;
    }
    return didWin;
}

BOOL didWinDown(const uint8_t *board, uint8_t side)
{
    BOOL didWin = NO;
    for (unsigned column = 0; column < 3 && !didWin; column++) {
        didWin =
            board[column + 0] == side &&
            board[column + 3] == side &&
            board[column + 6] == side;
    }
    return didWin;
}

BOOL didWinDiagonal(const uint8_t *board, uint8_t side)
{
    return (
        board[0] == side &&
        board[4] == side &&
        board[8] == side) || (
        board[2] == side &&
        board[4] == side &&
        board[6] == side);
}

然后使用这样的函数:

uint8_t board[9] = ...;
uint8_t sideThatJustMoved = 1;
if (didWinAcross(board, sideThatJustMoved) ||
    didWinDown(board, sideThatJustMoved) ||
    didWinDiagonal(board, sideThatJustMoved)) {
    someoneWon(sideThatJustMoved);
}

答案 1 :(得分:1)

首先,我建议使用0作为空方格,因为它会简化条件。

但基本上,不是经历每一个组合,而是经历组合模式。

- (NSUInteger) winnerStartingAt:(NSUInteger)index withStride:(NSUInteger)stride {
    NSUInteger a = self.boardState[index] ;
    NSUInteger b = self.boardState[index+stride] ;
    NSUInteger c = self.boardState[index+2*stride] ;
    if ( a && a==b && b==c ) // if they're all the same and they're all not empty
        return a ;
    return 0 ; // no winner (non-homogeneous list)
}

- (void) checkBoard {
    NSUInteger winner = 0 ; // assume there's no winner
    // check all the rows, which have a stride of 1
    if(!winner) winner = [self winnerStartAt:0 withStride:1] ;
    if(!winner) winner = [self winnerStartAt:3 withStride:1] ;
    if(!winner) winner = [self winnerStartAt:6 withStride:1] ;
    // check all the columns, which have a stride of 3 (they go downward)
    if(!winner) winner = [self winnerStartAt:0 withStride:3] ;
    if(!winner) winner = [self winnerStartAt:1 withStride:3] ;
    if(!winner) winner = [self winnerStartAt:2 withStride:3] ;
    // check the diagonals
    if(!winner) winner = [self winnerStartAt:0 withStride:4] ;
    if(!winner) winner = [self winnerStartAt:2 withStride:2] ;
    if ( winner )
        // whatever you want to do
}

我建议遵循一些其他建议,即使用2D整数数组而不是一维对象数组。这将带来性能优势。在你的水平和Tic Tac Toe,差异可以忽略不计,但我建议你学习下一件事,这样你就知道它是如何完成的,并且知道它们的性能差异。

答案 2 :(得分:0)

使用循环。 overWriteBoardState方法可以写成:

- (void)overWriteBoardState {
    for (NSInteger i = 0; i < 9; i++) {
        self.boardState[i] = @3;
    }
}

使用循环可以将X或O赢得的两个大if语句转换为一个if语句:

for (NSInteger p = 1; p <= 2; p++) {
    if (
         ([_boardState[0] isEqual:@(p)]  &&
          [_boardState[1] isEqual:@(p)]  &&
          [_boardState[2] isEqual:@(p)]) ||

         ([_boardState[3] isEqual:@(p)]  &&
          [_boardState[4] isEqual:@(p)]  &&
          [_boardState[5] isEqual:@(p)]) ||

         ([_boardState[6] isEqual:@(p)]  &&
          [_boardState[7] isEqual:@(p)]  &&
          [_boardState[8] isEqual:@(p)]) ||

         ([_boardState[0] isEqual:@(p)]  &&
          [_boardState[3] isEqual:@(p)]  &&
          [_boardState[6] isEqual:@(p)]) ||

         ([_boardState[1] isEqual:@(p)]  &&
          [_boardState[4] isEqual:@(p)]  &&
          [_boardState[7] isEqual:@(p)]) ||

         ([_boardState[2] isEqual:@(p)]  &&
          [_boardState[5] isEqual:@(p)]  &&
          [_boardState[8] isEqual:@(p)]) ||

         ([_boardState[0] isEqual:@(p)]  &&
          [_boardState[4] isEqual:@(p)]  &&
          [_boardState[8] isEqual:@(p)]) ||

         ([_boardState[2] isEqual:@(p)]  &&
          [_boardState[4] isEqual:@(p)]  &&
          [_boardState[6] isEqual:@(p)])
         ) {
        if (p == 1) {
            [xWinds show];
        } else {
            [oWins show];
        }
        [self overWriteBoardState];
    }
}

通过一些循环和一些其他表示匹配的数组数据,可以将大if语句转换为更简单的形式,但是大if语句实际上可能更简单,更清晰。

答案 3 :(得分:0)

列出获胜组合,浏览列表以返回获胜者(1或2)。

- (int)checkWinnerForBoard:(NSArray*)_boardState
{
    NSArray *tests = @[@[@0, @1, @2], @[@3, @4, @5], @[@6, @7, @8], @[@0, @3, @6], @[@1, @4, @7], @[@2, @5, @8], @[@0, @4, @8], @[@2, @4, @6]];
    for (NSArray *test in tests) {
        int value = [_boardState[[test[0] intValue]] intValue];
        if (value && value == [_boardState[[test[1] intValue]] intValue] && value == [_boardState[[test[2] intValue]] intValue])
            return value;
    }
    return 0;
}

您可以将组合数组存储在-init中,这样您就不会每次都重新创建它。

或者,您可能只想测试最后一个位置。

- (int)checkWinnerForBoard:(NSArray*)_boardState lastposition:(int)lastPosition
{
    NSArray *tests = @[@[@[@1, @2], @[@3, @6], @[@4, @8]], @[@[@0, @2], @[@4, @7]], @[@[@0, @1], @[@5, @8], @[@4, @6]], @[@[@0, @6], @[@4, @5]], @[@[@3, @5], @[@1, @7], @[@0, @8], @[@2, @6]], @[@[@3, @4], @[@2, @8]], @[@[@0, @3], @[@2, @4], @[@7, @8]], @[@[@1, @4], @[@6, @8]], @[@[@2, @5], @[@6, @7], @[@0, @4]]];
    for (NSArray *test in tests[lastPosition]) {
        int value = [_boardState[lastPosition] intValue];
        if (value == [_boardState[[test[0] intValue]] intValue] && value == [_boardState[[test[1] intValue]] intValue])
            return value;
    }
    return 0;
}

同样,您可以将组合数组存储在-init中,这样您就不会每次都重新创建它。