Skip to content

Commit

Permalink
fixed PuzzleMaker infinite loop bug, removed debug code, and moved so…
Browse files Browse the repository at this point in the history
…me stuff around
  • Loading branch information
noitsjocelyn committed Nov 3, 2013
1 parent bf813ad commit ccd8c14
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 83 deletions.
4 changes: 2 additions & 2 deletions PuzzleTutor/PuzzleMaker.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

- (void)givePuzzle:(short *)thePuzzle;
- (short *)getWorkingPuzzle:(short *)outputArray;
- (short *)buildEasyPuzzle:(short *)outputArray;
- (short *)buildMediumPuzzle:(short *)outputArray;
- (void)buildEasyPuzzle;
- (void)buildMediumPuzzle;

@end
92 changes: 29 additions & 63 deletions PuzzleTutor/PuzzleMaker.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,6 @@ - (short *)getWorkingPuzzle:(short *)outputArray
return outputArray;
}

- (short *)buildEasyPuzzle:(short *)outputArray
{
[self makeEasyPuzzle];
return [self getWorkingPuzzle:outputArray];
}

- (short *)buildMediumPuzzle:(short *)outputArray
{
[self makeMediumPuzzle];
return [self getWorkingPuzzle:outputArray];
}

/* The makeEasyPuzzle function. It uses count to track how many locations have
* been filled, either by deduciton or by displaying the value. Inside of a
* loop, it first looks to deduce a location's value by the
Expand All @@ -56,14 +44,11 @@ - (short *)buildMediumPuzzle:(short *)outputArray
* minus that location are both unfilled. It then makes those squares' values
* part of the initial puzzle displayed to the user.
*/
- (void)makeEasyPuzzle
- (void)buildEasyPuzzle
{
short count = 0;
short previousCount = 0;
short consecutiveFails = 0;
while (count < 81)
{
previousCount = count;
short *results = calloc(4, sizeof(short));
results = [basePuzzle findSquareWithOneAvailableValue:results];
if (results[0] != 0)
Expand All @@ -74,51 +59,43 @@ - (void)makeEasyPuzzle
else
{
// Random number from 0-40
int r = arc4random() % 41;
// That number's mirror
int r2 = 80 - r;
BOOL alreadyCounted = NO;
BOOL alreadyCounted2 = NO;
if ([basePuzzle getPuzzleValueAtIndex: r] != 0)
int r1 = arc4random() % 41;
BOOL alreadyCounted1 = NO;
if ([basePuzzle getPuzzleValueAtIndex:r1] != 0)
{
alreadyCounted = YES;
alreadyCounted1 = YES;
}
[basePuzzle putInValue:(givenPuzzle[r] + r * 9)];
if (workingPuzzle[r] != givenPuzzle[r])
[basePuzzle putInValue:(givenPuzzle[r1] + r1 * 9)];
if (workingPuzzle[r1] != givenPuzzle[r1])
{
workingPuzzle[r] = givenPuzzle[r];
if (alreadyCounted == NO)
workingPuzzle[r1] = givenPuzzle[r1];
if (alreadyCounted1 == NO)
{
++count;
}
}
// The mirror of the 40th square is itself, so don't do this
if (r != 40)
if (r1 != 40)
{
if ([basePuzzle getPuzzleValueAtIndex: r2] != 0)
// r1's mirror
int r2 = 80 - r1;
BOOL alreadyCounted2 = NO;
if ([basePuzzle getPuzzleValueAtIndex:r2] != 0)
{
alreadyCounted2 = YES;
}
[basePuzzle putInValue:(givenPuzzle[r2] + r2 * 9)];
if (workingPuzzle[r2] != givenPuzzle[r2])
{
workingPuzzle[r2] = givenPuzzle[r2];
if (alreadyCounted == NO)
if (alreadyCounted2 == NO)
{
++count;
}
}
}
}
free(results);
if (previousCount == count)
{
++consecutiveFails;
}
if (consecutiveFails > CONSECUTIVE_FAIL_THRESHOLD)
{
break;
}
}
}

Expand All @@ -132,14 +109,11 @@ - (void)makeEasyPuzzle
* unfilled. It then makes those squares' values part of the initial puzzle
* displayed to the user.
*/
- (void)makeMediumPuzzle
- (void)buildMediumPuzzle
{
short count = 0;
short previousCount = 0;
short consecutiveFails = 0;
while (count < 81)
{
previousCount = count;
short *results = calloc(4, sizeof(short));
results = [basePuzzle findSquareWithOneAvailableValue:results];
if (results[0] != 0)
Expand All @@ -158,30 +132,30 @@ - (void)makeMediumPuzzle
else
{
// Random number from 0-40
int r = arc4random() % 41;
// That number's mirror
int r2 = 80 - r;
BOOL alreadyCounted = NO;
BOOL alreadyCounted2 = NO;
if ([basePuzzle getPuzzleValueAtIndex:r] != 0)
int r1 = arc4random() % 41;
BOOL alreadyCounted1 = NO;
if ([basePuzzle getPuzzleValueAtIndex:r1] != 0)
{
alreadyCounted = YES;
alreadyCounted1 = YES;
}
[basePuzzle putInValue:(givenPuzzle[r] + r * 9)];
if (workingPuzzle[r] != givenPuzzle[r])
[basePuzzle putInValue:(givenPuzzle[r1] + r1 * 9)];
if (workingPuzzle[r1] != givenPuzzle[r1])
{
workingPuzzle[r] = givenPuzzle[r];
if (alreadyCounted == NO)
workingPuzzle[r1] = givenPuzzle[r1];
if (alreadyCounted1 == NO)
{
++count;
}
}
// The mirror of the 40th square is itself, so don't do this
if (r != 40)
if (r1 != 40)
{
// r1's mirror
int r2 = 80 - r1;
BOOL alreadyCounted2 = NO;
if ([basePuzzle getPuzzleValueAtIndex:r2] != 0)
{
alreadyCounted = YES;
alreadyCounted2 = YES;
}
[basePuzzle putInValue:(givenPuzzle[r2] + r2 * 9)];
if (workingPuzzle[r2] != givenPuzzle[r2])
Expand All @@ -196,14 +170,6 @@ - (void)makeMediumPuzzle
}
}
free(results);
if (previousCount == count)
{
++consecutiveFails;
}
if (consecutiveFails > CONSECUTIVE_FAIL_THRESHOLD)
{
break;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions PuzzleTutor/PuzzleMakerUnitTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
{
PuzzleMaker *testPuzzleMaker;
Puzzle *testHelper;
short *puzzleArray;
}

- (int)runAllTests;
Expand Down
35 changes: 19 additions & 16 deletions PuzzleTutor/PuzzleMakerUnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ @implementation PuzzleMakerUnitTests
- (id)init
{
testPuzzleMaker = nil;
const char *puzzleString = "672145398145983672389762451263574819958621743714398526597236184426817935831459267";
puzzleArray = calloc(81, sizeof(short));
for (short i = 0; i < 81; i++)
{
short numValue = (short)(puzzleString[i] - '0');
puzzleArray[i] = numValue;
}
return self;
}

- (void)dealloc
{
#if !(__has_feature(objc_arc))
[testPuzzleMaker release];
[super dealloc];
[testPuzzleMaker release];
#endif
free(puzzleArray);
}

/* Method which runs all of the tests. If any fail, it returns a failure
Expand Down Expand Up @@ -48,27 +56,16 @@ - (int)runAllTests
- (BOOL)testGivePuzzle
{
NSLog(@"Testing givePuzzle...");
short *inputPuz = calloc(81, sizeof(short));
const char *cString = "672145398145983672389762451263574819958621743714398526597236184426817935831459267";
BOOL didTestPass = YES;
@try {
for (short i = 0; i < 81; i++)
{
short numValue = (short)(cString[i] - '0');
inputPuz[i] = numValue;
}
testPuzzleMaker = [[PuzzleMaker alloc] init];
[testPuzzleMaker givePuzzle:inputPuz];
[testPuzzleMaker givePuzzle:puzzleArray];
}
@catch (NSException *e)
{
NSLog(@"Failure:\n%@", e);
didTestPass = NO;
}
@finally
{
free(inputPuz);
}
NSLog(@"Success.");
return didTestPass;
}
Expand All @@ -82,8 +79,11 @@ - (BOOL)testGivePuzzle
- (BOOL)testBuildEasyPuzzle
{
NSLog(@"Testing buildEasyPuzzle...");
testPuzzleMaker = [[PuzzleMaker alloc] init];
[testPuzzleMaker givePuzzle:puzzleArray];
[testPuzzleMaker buildEasyPuzzle];
short *aPuzzle = calloc(81, sizeof(short));
aPuzzle = [testPuzzleMaker buildEasyPuzzle:aPuzzle];
aPuzzle = [testPuzzleMaker getWorkingPuzzle:aPuzzle];
NSLog(@" Puzzle built.");
testHelper = [[Puzzle alloc] initWithShortArray:aPuzzle];
free(aPuzzle);
Expand All @@ -104,16 +104,19 @@ - (BOOL)testBuildEasyPuzzle
return didTestPass;
}

/* Tests the buildMediumPuzzle method. It does this by creating an medium puzzle, and feeding the workingPuzzle member
/* Tests the buildMediumPuzzle method. It does this by creating a medium puzzle, and feeding the workingPuzzle member
* to a new Puzzle object for initilization. From there, the medium tutor algorithm is run. If this algorithm isn't successful,
* the easy tutor algorithm is run. The test is successful if at least one of the tutor algorithms was successful.
* A more strict test may be written in the future.
*/
- (BOOL)testBuildMediumPuzzle
{
NSLog(@"Testing buildMediumPuzzle...");
testPuzzleMaker = [[PuzzleMaker alloc] init];
[testPuzzleMaker givePuzzle:puzzleArray];
[testPuzzleMaker buildMediumPuzzle];
short *aPuzzle = calloc(81, sizeof(short));
aPuzzle = [testPuzzleMaker buildMediumPuzzle:aPuzzle];
aPuzzle = [testPuzzleMaker getWorkingPuzzle:aPuzzle];
NSLog(@" Puzzle built.");
testHelper = [[Puzzle alloc] initWithShortArray:aPuzzle];
free(aPuzzle);
Expand Down
6 changes: 4 additions & 2 deletions Sudoku Teacher/Sudoku Teacher/PPSudokuGameViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,13 @@ - (void)generateAndDisplayBoard:(id)sender
short *puzzleArray = calloc(81, sizeof(short));
if (self.difficulty == 0)
{
puzzleArray = [aMaker buildEasyPuzzle:puzzleArray];
[aMaker buildEasyPuzzle];
puzzleArray = [aMaker getWorkingPuzzle:puzzleArray];
}
else
{
puzzleArray = [aMaker buildMediumPuzzle:puzzleArray];
[aMaker buildEasyPuzzle];
puzzleArray = [aMaker getWorkingPuzzle:puzzleArray];
}
Puzzle *newPuzzleData = [[Puzzle alloc] initWithShortArray:puzzleArray];
// Setup the board
Expand Down

0 comments on commit ccd8c14

Please sign in to comment.