Skip to content

Instantly share code, notes, and snippets.

@zbowling
Created August 16, 2023 06:30
Show Gist options
  • Save zbowling/1834eab638693566298677444521d832 to your computer and use it in GitHub Desktop.
Save zbowling/1834eab638693566298677444521d832 to your computer and use it in GitHub Desktop.
//
// HCLevelModel.h
// HamsterCrunch
//
// Created by Zac Bowling on 2/25/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
@class HCActorModel;
@class HCFinishLineModel;
@interface HCLevelModel : NSObject
#pragma mark View building property
- (id)initWithLevelSize:(CGSize)size columnCount:(NSInteger)columnCount;
@property (strong, nonatomic) NSMutableSet *wordModels;
@property (strong, nonatomic) NSMutableSet *rockModels;
@property (strong, nonatomic) HCActorModel *actorModel;
@property (assign, nonatomic) HCFinishLineModel *finishLineModel;
@property (assign, nonatomic) CGSize size;
@property (assign, nonatomic) CGFloat crunchLevel;
@end
//
// HCLevelModel.m
// HamsterCrunch
//
// Created by Zac Bowling on 2/25/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "HCLevelModel.h"
#import "HCWordModel.h"
#import "HCActorModel.h"
#import "HCWordBuilder.h"
#import "HCRockModel.h"
static BOOL shouldShowTutorial = YES;
#define NUM_SAFE_ROWS 5
#define TUTORIAL_PADDING 3
@interface HCLevelModel()
- (void)_populateWords;
@end
@implementation HCLevelModel {
HCWordBuilder* wordProvider;
NSUInteger cellDimension;
NSInteger _columnCount;
}
@synthesize actorModel=_actorModel;
@synthesize crunchLevel=_crunchLevel;
@synthesize finishLineModel=_finishLineModel;
@synthesize wordModels=_wordModels;
@synthesize size=_size;
@synthesize rockModels=_rockModels;
- (id)initWithLevelSize:(CGSize)size columnCount:(NSInteger)columnCount {
self = [super init];
if (self) {
_columnCount = columnCount;
_size = size;
cellDimension = size.width / columnCount;
wordProvider = [HCWordBuilder defaultWordBuilder];
_wordModels = [[NSMutableSet alloc] init];
_rockModels = [[NSMutableSet alloc] init];
self.actorModel = [[HCActorModel alloc] init];
[self _populateWords];
}
return self;
}
- (NSUInteger)_pickWordLength
{
return 3 + arc4random() % 5;
}
- (CGRect)_frameForPosition:(CGPoint)pt
withLength:(NSUInteger)numCells
isVertical:(BOOL)vertical
{
return CGRectMake(pt.x * cellDimension,
pt.y * cellDimension,
vertical ? cellDimension : cellDimension * numCells,
vertical ? cellDimension * numCells : cellDimension);
}
- (void)_populateWords
{
NSUInteger numSafeRows = NUM_SAFE_ROWS + (shouldShowTutorial ? TUTORIAL_PADDING : 0);
NSUInteger rowCount = _size.height / cellDimension;
NSMutableArray *wordList = [NSMutableArray array];
NSMutableArray *rockList = [NSMutableArray array];
NSInteger i=0,j=0,x=0,y=0;
__block int **cells = malloc(sizeof(int *)*_columnCount);
for(i = 0; i < _columnCount; i++) {
cells[i] = malloc(sizeof(int)*rowCount);
for (int j = 0; j < rowCount; j++){
cells[i][j] = -1;
}
}
NSUInteger totalCellCount = rowCount * _columnCount;
NSUInteger remainderCellCount = totalCellCount;
NSUInteger wordLen;
NSUInteger numCells;
HCWordModel * word;
BOOL (^isPointSafe)(NSUInteger, NSUInteger, NSUInteger, BOOL) = ^(NSUInteger x, NSUInteger y, NSUInteger numCells, BOOL vertical){
NSUInteger i = x, j = y, k = 0;
for (k = 0; k < numCells; k++){
if (i >= _columnCount || j >= rowCount || cells[i][j] != -1){
return NO;
}
if (vertical){
j++;
} else {
i++;
}
}
return YES;
};
__block NSUInteger (^longestSafeSequence)(NSUInteger, NSUInteger, BOOL *) = ^(NSUInteger x, NSUInteger y, BOOL *vertical){
NSUInteger i = x, j = y, k = 0, numCells = 0;
NSLog(@"Longest Safe Sequence");
for (k = 0; k < 6; k++){
if (i >= _columnCount || j >= rowCount || cells[i][j] != -1){
if (*vertical || numCells > 1){
return numCells;
} else {
*vertical = YES;
return longestSafeSequence(x,y,vertical);
}
}
numCells++;
if (*vertical){
j++;
} else {
i++;
}
}
return numCells;
};
void (^markSpotTaken)(NSUInteger,NSUInteger, NSUInteger, BOOL, NSUInteger) = ^(NSUInteger x, NSUInteger y, NSUInteger wordLen, BOOL vertical, NSUInteger wordIndex){
NSUInteger i = x, j = y, k = 0;
//NSLog(@"Starting To Mark Spot Taken! %d %d %d [Range: %d %d]",i,j,wordIndex, cells.size(), cells[i].size());
for (k = 0; k < wordLen; k++){
//NSLog(@"Marking Spot Taken! %d %d %d",i,j,wordIndex);
cells[i][j] = wordIndex;
if (vertical){
j++;
} else {
i++;
}
}
};
NSUInteger (^numCellsForLength)(NSUInteger wordLen) = ^(NSUInteger wordLen){
return (NSUInteger)ceil(wordLen / 2.5);
};
if (shouldShowTutorial){
//shouldShowTutorial = NO;
#define Say(word,len)\
markSpotTaken(curCol,curRow,len,NO,[wordList count]);\
[wordList addObject:[[HCWordModel alloc] initWithWord: @"" #word \
frame: [self _frameForPosition: CGPointMake(curCol,curRow)\
withLength: len\
isVertical: NO]\
isVertical: NO]];\
curCol += len;
#define Space \
markSpotTaken(curCol,curRow,1,NO,[wordList count]);\
(curCol++)
NSUInteger curCol = 0, curRow = NUM_SAFE_ROWS;
Say(Type, 2);
Space;
Say(these, 2);
Space;
Say(words, 2);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
curRow++;
curCol = 1;
} else {
Space;
}
Say(to,1);
Space;
Say(start,1);
Space;
Say(playing,3);
}
#define ShouldBeVertical (numCells > 1 && isVertical)
BOOL isVertical = YES;
NSUInteger failures = 0;
NSUInteger numVerticals = totalCellCount * .30;
for (i = 0; i < numVerticals; ) {
wordLen = [self _pickWordLength];
numCells = numCellsForLength(wordLen);
x = arc4random() % _columnCount;
y = arc4random() % (rowCount - numCells - numSafeRows) + numSafeRows;
if (!isPointSafe(x,y,numCells,isVertical)){
NSLog(@"Failed to pack vertical block, trying again");
if (++failures < 40){
continue;
} else {
NSLog(@"Failed to pack too many vertical blocks, aborting");
failures = 0;
break;
}
}
markSpotTaken(x,y,numCells,isVertical,[wordList count]);
i += numCells;
if (arc4random()%7 == 0) {
HCRockModel *rock = [[HCRockModel alloc] initWithFrame:[self _frameForPosition: CGPointMake(x,y)
withLength: numCells
isVertical: ShouldBeVertical]];
[rockList addObject:rock];
}
else {
NSLog(@"%@ word length %d number of cells: %d",isVertical?@"Vertical":@"Horizontal",wordLen,numCells);
word = [[HCWordModel alloc] initWithWord: [wordProvider wordForLength:wordLen+1]
frame: [self _frameForPosition: CGPointMake(x,y)
withLength: numCells
isVertical: ShouldBeVertical]
isVertical: ShouldBeVertical];
[wordList addObject:word];
}
}
remainderCellCount -= i;
isVertical = NO;
NSUInteger numHorizontals = remainderCellCount * .40;
for (i = 0; i < numHorizontals; ) {
wordLen = [self _pickWordLength];
numCells = numCellsForLength(wordLen);
x = arc4random() % (_columnCount - numCells);
y = arc4random() % (rowCount - numCells - numSafeRows) + numSafeRows;
if (!isPointSafe(x,y,numCells,isVertical)){
NSLog(@"Failed to pack horizontal block, trying again");
if (++failures < 40){
continue;
} else {
NSLog(@"Failed to pack too many vertical blocks, aborting");
failures = 0;
break;
}
}
markSpotTaken(x,y,numCells,isVertical,[wordList count]);
i += numCells;
if (arc4random()%6 == 0) {
HCRockModel *rock = [[HCRockModel alloc] initWithFrame:[self _frameForPosition: CGPointMake(x,y)
withLength: numCells
isVertical: ShouldBeVertical]];
[rockList addObject:rock];
}
else {
NSLog(@"%@ word length %d number of cells: %d",isVertical?@"Vertical":@"Horizontal",wordLen,numCells);
word = [[HCWordModel alloc] initWithWord: [wordProvider wordForLength:wordLen]
frame: [self _frameForPosition: CGPointMake(x,y)
withLength: numCells
isVertical: ShouldBeVertical]
isVertical: ShouldBeVertical];
[wordList addObject:word];
}
}
remainderCellCount -= i;
isVertical = NO;
NSLog(@"Taken Map");
NSMutableString *rowStr;
/**
* Now iteratively search for open cells, and then figure out if they have an
* open cell next to them, and accumulate word sizes that way.
*/
for (j = numSafeRows; j < rowCount; j++) {
rowStr = [[NSMutableString alloc] init];
for (i = 0; i < _columnCount; i++) {
[rowStr appendFormat:@"%d ",cells[i][j]];
isVertical = NO;
if (cells[i][j] == -1) {
wordLen = longestSafeSequence(i,j,&isVertical);
numCells = numCellsForLength(wordLen);
markSpotTaken(i,j,numCells,isVertical,[wordList count]);
//NSLog(@"%d",cells[i][j]);
if (arc4random()%5 == 0) {
HCRockModel *rock = [[HCRockModel alloc] initWithFrame:[self _frameForPosition: CGPointMake(i,j)
withLength: numCells
isVertical: ShouldBeVertical]];
[rockList addObject:rock];
}
else {
//NSLog(@"%@ word length %d number of cells: %d",isVertical?@"Vertical":@"Horizontal",wordLen,numCells);
word = [[HCWordModel alloc] initWithWord: [wordProvider wordForLength:wordLen]
frame: [self _frameForPosition: CGPointMake(i,j)
withLength: numCells
isVertical: ShouldBeVertical]
isVertical: ShouldBeVertical];
[wordList addObject:word];
}
}
}
NSLog(@"%d:\t%@",j,rowStr);
}
for(i = 0; i < _columnCount; i++) {
free(cells[i]);
}
free(cells);
self.rockModels = [NSMutableSet setWithArray:rockList];
self.wordModels = [NSMutableSet setWithArray:wordList];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment