Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Friday, 13 February 2009

Tetris : the implementation of a classical game in Objective-C/Cocoa

First of all the source code of the game can be found here. Background for the game can be found on wikipedia.

This implementation is a first attempt to implement it, in this version I was more intrested to get it to work than in the nice graphical aspects.
As you can see in the picture , it surely won't win a prize as the most sexy application :-).



This game again is an implementation of the classical MVC design pattern, with the difference that their are 2 views.

The model is a TetrisBoard (subclass of Board) on which you can move a piece (the so-called Tetrominoe (superclass of a set of pieces)).
The tetrominoe is the abstract superclass of all the tetrominoe's. It's very handy to model the pieces as a class, later on I can add things like a skin, or a another way of rotating. 

There are 2 views, the TetrisView and the TetrominoeView. The first one is the graphical representation of the  TetrisBoard; the second shows the next tetrominoe.

The model and the view(s) are connected via the TetrisController.

Tuesday, 3 February 2009

The Game of Life, the implementation

My own implementation of John Conways Game Of Life can be downloaded here.
Note that this implementation is far from ready, it shows the base concepts used but still need some polish to be really userfriendly and graphical attractive.

Screenshot :

The main concepts I used here are the following :

First of all I need a Model, in my case I created a class LifeBoard (a subclass of Board) . The abstract class Board just implements a basic gameboard with a variable number of cells. 
The LifeBoard class is the implementation of a gameboard for the Game Of Life, it implements the Conway algorithm. 
Note that we could use a strategy (design pattern) to delegate the algorithm to it. For the sake of simplicity this is not done.

The underlying datastructure used is a Matrix. (see previous blog messages for an explanation).

The next thing we need is a View,  in this case I created a custom view : LifeView (subclass of NSView).
This view just implements a simple visual representation of the LifeBoard. (a rectangle with a grid and the 'active' cells are yellow rectangles).

And the last concept we need is a Controller, here implemented as GameOfLifeController.
This class just glues together the model and the view.

So far my Game Of Life. The extra classes I've developed are used now in other board games that I'm developing.

Rules of the game :

Click on a gray rectangle to activate a cell, click on a yellow rectangle to deactivate it.

Press start to start the game

Saturday, 10 January 2009

SimpleCalculator

Let's move on and implement a somewhat more complex application.
(for the impatients : you can download the source code here ; don't forget to change the project settings in XCode before you compile).

I will now implement a simple calculator (see image) which is in fact an implementation of the MVC design pattern.


Now first a few words on MVC, the Model -View-Controller design pattern is probably one of the oldest design pattern around and mostly used to develop GUI's.
The idea is that you seperate the representation (UI) from the domain model and the interactions of the GUI with the model is implemented in the controller.

This has the advantage that for example you can have several visual representations of the same model.

So step 1 is to define the model :

/* CalculatorModel */

#import

@interface CalculatorModel : NSObject
{

float value1 ;
float value2 ;
float result ;

float memory ;

int depth ;

}

- (void) push:(float) v ;
- (void) clear ;
- (float) result ;
- (void) plus ;
- (void) min ;
- (void) mul ;
- (void) div ;
- (void) memoryPlus ;
- (void) memoryMin ;
- (void) memoryClear ;
- (float) memory ;
@end


And the corresponding implementation

#import "CalculatorModel.h"

@implementation CalculatorModel

- init
{
[super init] ;
depth = 0 ;
value1 = 0 ;
value2 = 0 ;
memory = 0 ;
//NSLog(@"Init calculator model" ) ;

return self ;
}

- (void) memoryPlus
{
memory += result ;
}

- (void) memoryMin
{
memory -= result ;
}

- (void) memoryClear

{
memory = 0 ;
}

- (float) memory
{
return memory ;
}

- (void) push:(float) v
{

if ( depth == 0 )
{
depth = 1;
value1 = v ;
}
else
{
depth = 0 ;
value2 = v ;
}
}
- (void) clear ;
{
depth = 0 ;
value1 = 0.0 ;
value2 = 0.0 ;
}

- (float) result
{
return result ;
}

- (void) plus
{

result = value1 + value2 ;

}
- (void) min
{

result = value1 - value2 ;

}
- (void) mul
{
result = value1 * value2 ;


}
- (void) div ;
{
if (value2 > 0 )
{
result = value1 / value2 ;
}
else result = 9999999999.0 ;



}


@end


So now we have our CalculatorModel. As you can see a very basic calculator. You have the basic calculations and a memory . I already provided a stack (with depth 1) to extend it later to a complex calculator model.

The next step is to build the view. This view  (see picture above) is designed using the InterfaceBuilder, but before we can associate the actions we need to create the controller also.

As already explained : in the controller we define the actions and the outlets which are bound to UI objects in the view (the bindings is done via the InterfaceBuilder)

The definition of the controller looks like this :

/* SimpleCalculatorController */

#import
#import "CalculatorModel.h"

@interface SimpleCalculatorController : NSObject
{
IBOutlet NSTextField *display ;
CalculatorModel *calculator ;
bool hasDecimal ;
bool afterCalculation ;
int action ;

NSMutableString *value ;
}
- (void) genericPush:(int) digit ;
- init ;

- (IBAction) pushOne:(id) sender ;
- (IBAction) pushTwo:(id) sender ;
- (IBAction) pushThree:(id) sender ;
- (IBAction) pushFour:(id) sender ;
- (IBAction) pushFive:(id) sender ;
- (IBAction) pushSix:(id) sender ;
- (IBAction) pushSeven:(id) sender ;
- (IBAction) pushEight:(id) sender ;
- (IBAction) pushNine:(id) sender ;
- (IBAction) pushZero:(id) sender ;
- (IBAction) pushDecPoint:(id) sender ;

- (IBAction) pushPlus:(id) sender ;
- (IBAction) pushMin:(id) sender ;
- (IBAction) pushMul:(id) sender ;
- (IBAction) pushDiv:(id) sender ;


- (IBAction) pushResult:(id) sender ;

- (IBAction) pushMemoryAdd:(id) sender ;
- (IBAction) pushMemoryMin:(id) sender ;
- (IBAction) pushClearMemory:(id) sender ;
- (IBAction) pushRecallMemory:(id) sender ;

- (IBAction) pushClear:(id) sender ;
@end


The corresponding implementation is the following :

#import "SimpleCalculatorController.h"


@implementation SimpleCalculatorController

- init
{
[super init] ;



value = [ [NSMutableString alloc] init] ;
[value appendString: @"" ] ;
calculator = [ CalculatorModel alloc] ;
hasDecimal = false ;
afterCalculation = false ;

return self ;
}

- (void) pushToCalculator
{

NSNumber *number ;
number = [[[NSNumberFormatter alloc] init] numberFromString: value] ;
[calculator push: [number floatValue ]] ;

value = [ [NSMutableString alloc] init] ;

hasDecimal = false ;
}

- (void) genericPush:(int)digit
{



if ( afterCalculation )
{
afterCalculation = false ;
value = [ [NSMutableString alloc] init] ;
}

if ( value == nil ) NSLog( @"NIL") ;
[value appendString: [NSString stringWithFormat: @"%d", digit]] ;
[display setStringValue: value ] ;

}


- (IBAction) pushOne:(id) sender
{
[self genericPush:1] ;
}

- (IBAction) pushTwo:(id) sender
{
[self genericPush:2] ;
}

- (IBAction) pushThree:(id) sender
{
[self genericPush:3] ;
}

- (IBAction) pushFour:(id) sender
{
[self genericPush:4] ;
}

- (IBAction) pushFive:(id) sender
{
[self genericPush:5] ;
}

- (IBAction) pushSix:(id) sender
{
[self genericPush:6] ;
}

- (IBAction) pushSeven:(id) sender
{
[self genericPush:7] ;
}

- (IBAction) pushEight:(id) sender
{
[self genericPush:8] ;
}

- (IBAction) pushNine:(id) sender
{
[self genericPush:9] ;
}

- (IBAction) pushZero:(id) sender
{


[self genericPush:0] ;
}

- (IBAction) pushDecPoint:(id) sender
{
if (hasDecimal) return ;
hasDecimal = true ;
[value appendString: @"."] ;
[display setStringValue: value ] ;

}

- (IBAction) pushPlus:(id) sender

{
[self pushToCalculator] ;
action = 1 ;

}
- (IBAction) pushMin:(id) sender
{
[self pushToCalculator] ;
action = 2 ;
}
- (IBAction) pushMul:(id) sender
{
[self pushToCalculator] ;
action = 3 ;
}
- (IBAction) pushDiv:(id) sender
{
[self pushToCalculator] ;
action = 4 ;
}


- (IBAction) pushResult:(id) sender
{
NSNumber *number ;
number = [[[NSNumberFormatter alloc] init] numberFromString: value] ;

[calculator push: [number floatValue ]] ;
if ( action == 0 ) return ;
if ( action == 1 )
{
[calculator plus] ;
}
if ( action == 2 ) [calculator min] ;
if ( action == 3 ) [calculator mul] ;
if ( action == 4 ) [calculator div] ;


value = [ [NSMutableString alloc] init] ;
hasDecimal = false ;
afterCalculation = true ;
action = 0 ;
[value appendString: [NSString stringWithFormat: @"%f", [calculator result]]] ;
[display setStringValue: value ] ;

}

- (IBAction) pushMemoryAdd:(id) sender
{
[calculator memoryPlus] ;
}
- (IBAction) pushMemoryMin:(id) sender
{
[calculator memoryMin ] ;
}
- (IBAction) pushClearMemory:(id) sender
{
[calculator memoryClear] ;
}

- (IBAction) pushRecallMemory:(id) sender
{
value = [ [NSMutableString alloc] init] ;
[value appendString: [NSString stringWithFormat: @"%f", [calculator memory]]] ;
[display setStringValue: value ] ;
}
- (IBAction) pushClear:(id) sender
{
[self init] ;
[display setStringValue: value ] ;
}


@end


Now this controller has a simple implementation, later on I'll revisit this controller to make it more cleaner.
To show how the view is build and bound to the controller I would like to show that via video or something. But that I still need to create.

So far the simple calculator application, it was very easy to build using XCode (it took me no more than a half a day). The reader will see that I didn't take much attention to memory management and so.
I come back to this later on, because memory management is important with larger and more complex applications