First off, here's the code:

main.m

#import &lt;Foundation/Foundation.h&gt;
#import "PSBoard.h"
#import "PSPlayer.h"
#import "PSInputHandler.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        NSLog(@"Enter Player 1 Name:");
        NSString *playerOneName = [PSInputHandler getString];
        NSLog(@"Enter Player 2 Name:");
        NSString *playerTwoName = [PSInputHandler getString];

        NSLog(@"How many rows and columns will you play with?");
        NSUInteger numberOfRowsAndColumns = [PSInputHandler getInteger];

        PSPlayer *playerOne = [[PSPlayer alloc] initWithSymbol:PSBoardSymbolX name:playerOneName];
        PSPlayer *playerTwo = [[PSPlayer alloc] initWithSymbol:PSBoardSymbolO name:playerTwoName];
        PSBoard  *board = [[PSBoard alloc] initWithRows:numberOfRowsAndColumns columns:numberOfRowsAndColumns players:@[playerOne, playerTwo]];

        do {
            PSPlayer *currentPlayer = [board playerUp];
            BOOL validInputEntered = NO;

            //Loop until valid input is entered
            while(!validInputEntered) {
                //Get input coordinates
                NSLog(@"%@, enter a row (1-%lu).", currentPlayer.name, (unsigned long)numberOfRowsAndColumns);
                NSUInteger row = [PSInputHandler getInteger];
                NSLog(@"Now enter a column (1-%lu).", (unsigned long)numberOfRowsAndColumns);
                NSUInteger column = [PSInputHandler getInteger];

                //Verify that nothing is already placed there
                PSBoardSymbol symbolOfPlayerAtCoordinates = [board playerAtRow:row-1 column:column-1].symbol;

                if((symbolOfPlayerAtCoordinates != PSBoardSymbolX &amp;&amp; symbolOfPlayerAtCoordinates != PSBoardSymbolO) &amp;&amp;
                   row &gt; 0 &amp;&amp; row &lt;= numberOfRowsAndColumns &amp;&amp; column &gt; 0 &amp;&amp; column &lt;= numberOfRowsAndColumns) {
                    [board setPlayer:currentPlayer atRow:(row-1) column:(column-1)];
                    validInputEntered = YES;
                }
            }

            //Show the board
            [board display];

        } while(!board.winner);

        NSLog(@"Congrats %@! You won.", [board winner].name);
    }

    return 0;
}


PSBoard.h

#import &lt;Foundation/Foundation.h&gt;

@class PSPlayer;

@interface PSBoard : NSObject

@property (nonatomic) NSUInteger        rows;
@property (nonatomic) NSUInteger        columns;
@property (nonatomic, strong) PSPlayer *winner;

-(instancetype)initWithRows:(NSUInteger)rows columns:(NSUInteger)columns players:(NSArray *)players;
-(PSPlayer *)playerAtRow:(NSUInteger)row column:(NSUInteger)column;
-(void)setPlayer:(PSPlayer *)player atRow:(NSUInteger)row column:(NSUInteger)column;
-(void)display;
-(PSPlayer *)playerUp;

@end


PSBoard.m

#import "PSBoard.h"
#import "PSPlayer.h"

@interface PSBoard ()

@property (nonatomic, strong) NSMutableArray *internalBoardRepresentation;
@property (nonatomic, strong) NSArray *players;
@property (nonatomic, strong) PSPlayer *oldPlayerUp;

@end

@implementation PSBoard

-(instancetype)initWithRows:(NSUInteger)rows columns:(NSUInteger)columns players:(NSArray *)players {

    if(self = [super init]) {

        self.rows = rows;
        self.columns = columns;
        self.players = players;
        self.internalBoardRepresentation = [[NSMutableArray alloc] initWithCapacity:rows];

        PSPlayer *null = [[PSPlayer alloc] initWithSymbol:PSBoardSymbolNone name:nil];

        for(NSUInteger row = 0; row &lt; rows; row++) {

            NSMutableArray *currentColumn = [NSMutableArray array];
            for(NSUInteger column = 0; column &lt; columns; column++) {
                [currentColumn addObject:null];
            }
            [self.internalBoardRepresentation addObject:currentColumn];
        }

        self.oldPlayerUp = players[0];
    }

    return self;
}
-(PSPlayer *)playerAtRow:(NSUInteger)row column:(NSUInteger)column {
    return self.internalBoardRepresentation[row][column];
}
-(void)setPlayer:(PSPlayer *)player atRow:(NSUInteger)row column:(NSUInteger)column {
    self.internalBoardRepresentation[row][column] = player;
    [self checkForWinner];
}
-(void)checkForWinner {

    NSUInteger numberOfPiecesInARowToWin = MAX(self.rows, self.columns);

    //Check horizontal lines
    for(NSUInteger row = 0; row &lt; self.rows; row++) {

        PSPlayer *playerInFirstColumn = [self playerAtRow:row column:0];
        NSUInteger playerPiecesInRow = 0;

        for(NSUInteger column = 0; column &lt; self.columns; column++) {
            if([[self playerAtRow:row column:column] isEqualTo:playerInFirstColumn]) {
                playerPiecesInRow++;
            }
        }

        if(playerPiecesInRow &gt;= numberOfPiecesInARowToWin &amp;&amp; playerInFirstColumn.symbol != PSBoardSymbolNone) {
            self.winner = playerInFirstColumn;
            return;
        }
    }

    //Check vertical lines
    for(NSUInteger column = 0; column &lt; self.columns; column++) {

        PSPlayer *playerInFirstRow = [self playerAtRow:0 column:column];
        NSUInteger playerPiecesInColumn = 0;

        for(NSUInteger row = 0; row &lt; self.rows; row++) {
            if([[self playerAtRow:row column:column] isEqualTo:playerInFirstRow]) {
                playerPiecesInColumn++;
            }
        }

        if(playerPiecesInColumn &gt;= numberOfPiecesInARowToWin &amp;&amp; playerInFirstRow.symbol != PSBoardSymbolNone) {
            self.winner = playerInFirstRow;
            return;
        }
    }

    //Check top left to bottom right diagonal
    PSPlayer *playerInFirstSlotOfLeftDiagonal = [self playerAtRow:0 column:0];
    NSUInteger playerPiecesInLeftDiagonal = 0;

    for(NSUInteger row = 0, column = 0; row &lt; self.rows; column++, row++) {
        if([[self playerAtRow:row column:column] isEqualTo:playerInFirstSlotOfLeftDiagonal]) {
            playerPiecesInLeftDiagonal++;
        }
    }

    if(playerPiecesInLeftDiagonal &gt;= numberOfPiecesInARowToWin &amp;&amp; playerInFirstSlotOfLeftDiagonal.symbol != PSBoardSymbolNone) {
        self.winner = playerInFirstSlotOfLeftDiagonal;
        return;
    }

    //Check bottom left to top right diagonal
    PSPlayer *playerInFirstSlotOfRightDiagonal = [self playerAtRow:self.rows-1 column:0];
    NSUInteger playerPiecesInRightDiagonal = 0;

    for(NSInteger row = self.rows-1, column = 0; row &gt;= 0; row--, column++) {
        if([[self playerAtRow:row column:column] isEqualTo:playerInFirstSlotOfRightDiagonal]) {
            playerPiecesInRightDiagonal++;
        }
    }

    if(playerPiecesInRightDiagonal &gt;= numberOfPiecesInARowToWin &amp;&amp; playerInFirstSlotOfRightDiagonal.symbol != PSBoardSymbolNone) {
        self.winner = playerInFirstSlotOfRightDiagonal;
        return;
    }
}
-(void)display {

    NSMutableString *displayString = [NSMutableString stringWithFormat:@"\n"];

    for(NSUInteger row = 0; row &lt; self.rows; row++) {

        NSMutableString *rowDisplayString = [[NSMutableString alloc] init];
        NSString *innerFillerString = (row == self.rows-1) ? @" " : @"_";

        for(NSUInteger column = 0; column &lt; self.columns; column++) {
            NSString *columnSeparator = (column == self.columns-1) ? @" " : @"|";
            NSString *playerSymbol = ([self playerAtRow:row column:column].symbolStringRepresentation);

            if(playerSymbol.length == 0) {
                playerSymbol = innerFillerString;
            }

            [rowDisplayString appendString:[NSString stringWithFormat:@"%@%@%@%@", innerFillerString, playerSymbol, innerFillerString, columnSeparator]];
        }

        [displayString appendString:[NSString stringWithFormat:@"%@\n", rowDisplayString]];
        [rowDisplayString setString:@""];
    }

    NSLog(@"%@", displayString);
}
-(PSPlayer *)playerUp {

    PSPlayer *nextPlayerUp = self.players[1-([self.players indexOfObjectIdenticalTo:self.oldPlayerUp])];
    PSPlayer *previousPlayerUp = self.oldPlayerUp;
    self.oldPlayerUp = nextPlayerUp;
    return previousPlayerUp;
}

@end


PSPlayer.h

#import &lt;Foundation/Foundation.h&gt;

typedef NS_ENUM(NSInteger, PSBoardSymbol) {

    PSBoardSymbolX = 0,
    PSBoardSymbolO,
    PSBoardSymbolNone
};

@interface PSPlayer : NSObject

-(instancetype)initWithSymbol:(PSBoardSymbol)symbol name:(NSString *)name;

@property (nonatomic)  PSBoardSymbol    symbol;
@property (nonatomic)  NSString        *symbolStringRepresentation;
@property (nonatomic, strong) NSString *name;

@end


PSPlayer.m

#import "PSPlayer.h"

@implementation PSPlayer

-(instancetype)initWithSymbol:(PSBoardSymbol)symbol name:(NSString *)name{

    if(self = [super init]) {

        self.symbol = symbol;
        self.symbolStringRepresentation = (symbol == PSBoardSymbolO) ? @"O" : ((symbol == PSBoardSymbolX) ? @"X" : @"");
        self.name = name;
    }

    return self;
}

@end


PSInputHandler.h

#import &lt;Foundation/Foundation.h&gt;

@interface PSInputHandler : NSObject

+(NSString *)getString;
+(NSInteger)getInteger;

@end


PSInputHandler.m

#import "PSInputHandler.h"

@implementation PSInputHandler

+(NSInteger)getInteger {
    int temp;
    scanf("%i", &amp;temp);
    return (NSInteger)temp;
}
+(NSString *)getString {
    char input[256];
    scanf("%s", input);
    return [NSString stringWithUTF8String:input];
}

@end


So my questions are:


In the PSInputHandler.m class, I wasn't so sure about how to get input from the command line. I read that fgets() is a potential alternative to scanf(), but is there any reason for me to use one over the other?
The method in PSBoard.m that checks for a winner, checkForWinner, is very long. Is there a simplified design I can use to shorten it?
I struggled to name the playerUp method, which returns the player whose turn it is. Is there a more suitable name?
When the user inputs which row and column to place an X or O in, I made it so that the coordinates they enter are from 1 to the number of rows and not 0 to the number of rows minus one (like with zero-based array indexing). Is this more user-friendly, or should I change it to zero-based indexing?
In PSPlayer.m, I use nested ternary operators. Is this too hard to understand? Should I change it to if statements?

When getting the user's input for how many rows and columns to use, which I expect to be an integer, how can I sanitize the input so that the program doesn't crash when a string (for example) is inputted?



Any other critique welcome!


Question: What are the possible cryptographic implications of Zhang's proof of the Twin Prime Conjecture?
Answer: There are no known applications or implications to cryptography of that mathematical machinery.  I've not seen any suggestion that the machinery would plausibly have implications for cryptography.  The twin primes problem doesn't have any obvious connection to any hardness assumption or problem in cryptography.

(Yes, both Zhang's proof and cryptography have something to do with prime numbers, but that is extremely thin. Much of number theory can say it is somehow related to prime numbers, but only a small fraction of number theory has had applications to cryptography. It'd be like assuming that recent improvements in building fast sailboats for the America's Cup has implications for the possible future availability of an immortality potion, since they both involve fluids.)

In other words, this is about as close to a "No" answer as one is likely to be able to give, given the nature of the question (which makes it very unlikely that you are going to get a definite, resounding no).

Here are some surveys of the mathematics of this result and related results, if you want to take a look for yourself:


https://gilkalai.wordpress.com/2013/09/20/polymath-8-a-success/
http://arxiv.org/pdf/math/0605696v1
https://terrytao.wordpress.com/2013/06/30/bounded-gaps-between-primes-polymath8-a-progress-report/