2015-09-28 113 views
2

我最近在Objective-C中构建了一个Tic Tac Toe游戏,同时重点努力让我的代码尽可能简短和干净(因为我对编程相对陌生,这是我第一次专注于使某些东西高效/可读性,而不仅仅是使其工作在任何成本)如何处理if-than语句中的大量条件?

大部分,我能够使我的代码简短和高效,我很满意 - 除了checkWin函数的一部分,检查是否X或O的赢得了比赛

我有一个NSArray对象叫“BoardState”,以对应于9点在黑板上,像这样

索引0-

当索引设置为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; 
} 

我怎么能这样构造,以避免这些大量的重复行?任何帮助或提示表示赞赏 - 谢谢!

+0

不要重新发明轮子:有一种算法叫做Minimax https://github.com/mattrajca/TTT – vadian

回答

0

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

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

两个大if报表,看看X或O的使用循环赢得了可以做成一个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语句实际上可能更简单明了。

+0

感谢您的帮助!下一次,我可能会尝试简化大量的if语句,但现在你可能是正确的,这是最简单的解决方案 – Hstuart

2

首先是数据存储。鉴于你正在处理一个小的固定大小的三态值数组,我建议使用一个简单的C数组uint8_t使用0,12编码你已经提到,而不是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); 
} 
+0

谢谢!所有人都给出的建议都很好,我很欣赏这个建议! – Hstuart

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 
} 

我建议以下给出,即使用整数,而不是对象的一维数组的二维数组一些其他建议。这会给性能带来好处。在你的水平上,对于Tic Tac Toe来说,差别可以忽略不计,但我建议你接下来要学习的东西,以便你知道它是如何完成的,并且知道它们的性能差异。

+0

这很聪明,但是按照书面的说法,这很难表明X或O是否赢了。 – rmaddy

+0

是的。今天早上我想不出一种特别优雅的方式,但我已经编辑它来添加一个。 – iAdjunct

+0

谢谢!这是一个非常聪明的解决方案 - 让我以不同的方式看待整个事物! – Hstuart

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这样你就不会每次都重新创建它。