## CS 596 OODP Board Assignment

[To Lecture Notes Index]
San Diego State University -- This page last updated November 14, 1995

## Solutions and Issues on Board Class

The Traps

Don't imbed numbers in your program
Make each square 10 by 10

Programs do need some documentation
What is a label?

Avoid repeating code - look for common abstraction
Two functions required same knowledge
map pixel location to square on board

## Solution 1 to Assignment

Board class does all the work

### Simple Board Class

```#ifndef	_SimpleBoard_HH
#define	_SimpleBoard_HH

enum Color { Dark = 0, Light = 1 };
const int Even = 0;

#include "Point.h"

class SimpleBoard {
public:
SimpleBoard (int SquaresPerSide = 8,
int PixelsPerSquare = 10,
Color FirstSquareColor = Light);

Color ColorAt (const LPoint PixelLocation ) const;
LPoint LabelAt (const LPoint PixelLocation ) const;

private:
int BoardSize;			// squares per row and column
int SquareSize;			// Pixels per side of square

Color	EvenSquareColor;	// Row Index + Column index
Color 	OddSquareColor;	// gives parity of square

LPoint SquareIndexAt (const LPoint PixelLocation ) const;

};
#endif
#include "SimpleBoard.h"
#include <assert.h>

SimpleBoard :: SimpleBoard (int SquaresPerSide,
int PixelsPerSquare ,
Color FirstSquareColor) {

assert ( (SquaresPerSide % 2) == Even );

BoardSize = SquaresPerSide;
SquareSize = PixelsPerSquare;
EvenSquareColor = FirstSquareColor;

if (FirstSquareColor == Dark)
OddSquareColor = Light;
else
OddSquareColor = Dark;
}

LPoint SimpleBoard :: SquareIndexAt (const LPoint PixelLocation ) const{

assert( (PixelLocation.x() >= 0) && (PixelLocation.y() >= 0) );
assert( (PixelLocation.x() <=  BoardSize * SquareSize ) &&
(PixelLocation.y() <=  BoardSize * SquareSize ) );

return PixelLocation / SquareSize;
}

Color SimpleBoard :: ColorAt (const LPoint PixelLocation ) const {

LPoint SquareIndex = SquareIndexAt( PixelLocation );

int IndexSum = SquareIndex.x() + SquareIndex.y();
int SquareParity = IndexSum % 2;

if ( SquareParity == Even )
return EvenSquareColor;
else
return OddSquareColor;
}

LPoint SimpleBoard :: LabelAt (const LPoint PixelLocation ) const {
return SquareIndexAt( PixelLocation );
}
class LPoint {

public:
LPoint( int x = 0, int y = 0 );
~LPoint() { cout << "destroy point\n";};

friend ostream& operator << ( ostream& output,
LPoint print );
void  print ( ostream& output ) const;

int operator >= ( const LPoint&  a ) const;
int operator <= ( const LPoint&  a ) const;

float distance ( const LPoint& a ) const;
LPoint operator + ( const LPoint& a ) const;
LPoint operator - ( const LPoint& a ) const;
LPoint operator / ( int scalar ) const;

int x() const;
int y() const;

private:
int xCoordinate;
int yCoordinate;
};

LPoint  LPoint ::  operator / ( int scalar ) const {
return LPoint ( xCoordinate / scalar, yCoordinate / scalar);
}

```

## Solution 2 to Assignment

Board class contains n*n square things, which do some work

### Issues

How to store and access the n*n square things?

What is a square thing?

#### Storing and Accessing

Simple Array, Direct Access
```class Board {
public:
Board( int Size )
{ Squares = new SquareThing[Size* Size];
BoardSize = Size;};

private:
SquareThing* Squares;
int BoardSize;
};

```
Access square in row R and column C by:
```

(Squares[ R * BoardSize + C ]).color()

```

Simple Array, Indirect Access
```class Board {
public:
Board( int Size )
{ Squares = new SquareThing[Size* Size];
BoardSize = Size;};

private:
SquareThing* Squares;
int BoardSize;

SquareThing& squareAt( int Row, int Column ) {
return Squares[  Row * BoardSize + Column  ];
};

SquareThing& operator [] ( int Row ) {
return Squares + (Row * BoardSize);
};
};

```
Access square in row R and column C by either:
```
squareAt( R, C).color()

```
or
```	(this->[ R ][ C ]).color();

```

Use Matrix
```template <class Type>
class Matrix
{	public :
Matrix(int NumOfRows, int NumOfColumns);
~Matrix();
Type* operator[](int whichRow);

int NumberOfRows()	{ return ColumnSize; } const;
int NumberOfColumns() { return RowSize; } const;

private:
Type* elements;
int RowSize;
int ColumnSize;
};

template <class Type>
Matrix<Type> :: Matrix(int NumOfRows, int NumOfColumns) {

elements = new Type[ NumOfRows * NumOfColumns];
RowSize = NumOfColumns;
ColumnSize = NumOfRows;
};

template <class Type>
Type* Matrix<Type> :: operator[](int whichRow) {
return elements + ( whichRow * RowSize);
};

template <class Type>
Matrix<Type>  :: ~Matrix() {
delete [] elements;
};

class Board {
public:
Board( int Size )

private:
Matrix<SquareThing> Squares;
};

Board :: Board( int Size ) : Squares( Size, Size ) {};

```
Access square in row R and column C by:
```

Squares[ R ] [ C ]. color();
```

#### How to call SquareThing Constructors?

```class Board {
public:
Board( int Size )

private:
Matrix< SquareThing > Squares;
};

```
Set values of data members
```Board :: Board( int Size ) : Squares( Size, Size ) {

for (int R = 0; R < Squares.NumberOfRows(); R++ )
for (int C = 0; C < Squares.NumberOfColumns(); C++ )

Squares[ R ][ C ].setDataMember( value );
};
```
Copy Objects
```Board :: Board( int Size ) : Squares( Size, Size ) {

for (int R = 0; R < Squares.NumberOfRows(); R++ )
for (int C = 0; C < Squares.NumberOfColumns(); C++ )

Squares[ R ][ C ] = SquareThing( values );
};

```
Use Pointers
```
class Board {
public:
Board( int Size )

private:
Matrix< SquareThing* > Squares;
};

```
```Board :: Board( int Size ) : Squares( Size, Size ) {

for (int R = 0; R < Squares.NumberOfRows(); R++ )
for (int C = 0; C < Squares.NumberOfColumns(); C++ )

Squares[ R ][ C ] = new SquareThing( values );
};
```

#### What is a square thing?

Square thing is square with color and may have a checker on it
```class LRectangle {
public:
LRectangle ( const LPoint& UpperLeftCorner,
const LPoint& LowerLeftCorner ,
Color interior);

void print ( ostream& output ) const;
void draw() const;

LPoint getUpperLeftCorner() const;
LPoint getUpperRightCorner() const;
LPoint getLowerLeftCorner() const;
LPoint getLowerRightCorner() const;
LPoint* getCorners() const;

int contains( const LPoint& a ) const;
int intersects( const LRectangle a ) const;

void setColor( Color NewColor);
void setUpperLeftCorner( LPoint NewCorner );

protected:
LPoint	UpperLeft;
int	width;
int	height;
Color	interiorColor;

int containsCornerOf( const LRectangle a ) const;
};
```

#### Inheritance vs. Composition

Inheritance
```class BoardSquare : public LRectangle {
public:
BoardSquare( int Row, int Column,
const LPoint& UpperLeftCorner,
const LPoint& LowerLeftCorner ,
Color interior)
: LRectangle(UpperLeftCorner,
LowerLeftCorner ,
interior) {

code to construct BoardSquare
};

void draw() const;

private:
Checker* piece;

};
```
```int BoardSquare :: draw( ) const {

LRectangle :: draw();
if ( piece != 0 )
piece->draw();
}
```

Composition
```class BoardSquare  {
public:
BoardSquare( int Row, int Column,
const LPoint& UpperLeftCorner,
const LPoint& LowerLeftCorner ,
Color interior)
: mySquare(UpperLeftCorner,
LowerLeftCorner ,
interior) {

code to construct BoardSquare
};

int contains( const LPoint& a ) const;
void draw() const;

private:
Checker* piece;
LRectangle mySquare;
};
```

```int BoardSquare :: contains( const LPoint& a ) const {
return mySquare.contains( a );
};

int BoardSquare :: draw( ) const {

mySquare.draw();
if ( piece != 0 )
piece->draw();
}
```

Inheritance vs. Composition
Inheritance

May inherit unneeded operations
void setColor( Color NewColor);
BoardSquare has no control over who sets color

Need to understand base and derive class

Composition

More work - must implement all require operations
int BoardSquare :: contains( const LPoint& a ) const {
return mySquare.contains( a );
};

Don't inherit unneeded operations

Base class has more code, but is easier to understand

More flexibility in changing implementation
What about board games with round squares?

Round Squares with Composition
```class BoardSquare  {			// so the name is not very good
public:
BoardSquare( int Row, int Column,
const LPoint& UpperLeftCorner,
const LPoint& LowerLeftCorner ,
Color interior)   {
code to construct BoardSquare
};

int contains( const LPoint& a ) const;
void draw() const;

private:
Checker* piece;
Shape* myShape;
};
```

```class Shape {
// stuff not shown
};

class Rectangle : public Shape{
// stuff not shown
};

class Circle : public Shape{
// stuff not shown
};

```

Round Squares with Inheritance
```class BoardThing  {
public:
BoardSquare( int Row, int Column,
const LPoint& UpperLeftCorner,
const LPoint& LowerLeftCorner ,
Color interior)   {
code to construct BoardSquare
};

private:
Checker* piece;
};
```
```class Shape {
// stuff not shown
};

class Rectangle : public Shape{
// stuff not shown
};

class Circle : public Shape{
// stuff not shown
};

class BoardSquare : public BoardThing, public Rectangle {}

class BoardCircle : public BoardThing, public Circle {}
```

### ComplexBoard Class

```
#ifndef	_ComplexBoard_HH
#define	_ComplexBoard_HH

#include "Point.h"
#include "BoardSquare.h"
#include "Matrix.h"
#include "BoardTypes.h"

class ComplexBoard {
public:

ComplexBoard (LPoint UpperLeftCorner,
int SquaresPerSide = 8,
int PixelsPerSide = 80,
Color FirstSquareColor = Light);

LPoint SquareIndexAt (const LPoint PixelLocation ) ;
Color ColorOf (const LPoint RowColumn );

private:
Matrix< BoardSquare* >	TheBoard;

LPoint	Offset;		// in pixels, is actual coordinate of
//	upperleft corner
};

#endif
#include "ComplexBoard.h"
#include <assert.h>

ComplexBoard :: ComplexBoard (LPoint UpperLeftCorner,
int SquaresPerSide,
int PixelsPerSide ,
Color FirstSquareColor) :
TheBoard( SquaresPerSide, SquaresPerSide){

assert ( (SquaresPerSide % 2) == Even );

Offset = UpperLeftCorner;

int PixelsPerSquare = PixelsPerSide / SquaresPerSide;

for ( int Row = 0; Row < SquaresPerSide; Row++ )
for ( int Column = 0; Column < SquaresPerSide; Column++ )
TheBoard[ Row ][ Column ] =
new BoardSquare( Row, Column,
PixelsPerSquare,
FirstSquareColor);
}

LPoint ComplexBoard :: SquareIndexAt (const LPoint PixelLocation ) {
LPoint LocalPixelLocation = PixelLocation - Offset;

for ( int Row = 0; Row < TheBoard.NumberOfRows(); Row++ )
for ( int C = 0; C < TheBoard.NumberOfColumns(); C++ )
if ( TheBoard[ Row ][ C ] ->
contains( LocalPixelLocation ) )
return LPoint( Column, Row );

assert( 1 == 0);
return LPoint(0 , 0 );
}
Color ComplexBoard :: ColorOf (const LPoint PixelLocation )  {

LPoint SquareIndex = SquareIndexAt( PixelLocation );
return TheBoard[ SquareIndex.y()][ SquareIndex.x() ] -> color();
}

```

## Which Solution is Better?

### SimpleBoard Responsibilities

Translate between the physical (screen) and logical representation of the board
What about pieces - they need this service

Draw the board

```const int Even = 0;
enum Color { Dark = 0, Light = 1 };

#include "Point.h"

class SimpleBoard {
public:

SimpleBoard (LPoint UpperLeftCorner,
int SquaresPerSide = 8,
int PixelsPerSide = 80,
Color FirstSquareColor = Light);

LPoint SquareIndexAt (const LPoint PixelLocation ) const;
LPoint CenterOfSquare (const LPoint RowColumn ) const;
int SizeOfSquare() { return SquareSize; } const;
void draw() const;

private:
int BoardSize;			// squares per row and column
int SquareSize;			// Pixels per side of square

Color	EvenSquareColor;
Color 	OddSquareColor;

LPoint	Offset;

void drawSquare( const LPoint RowColumn ) const;
Color ColorOf (const LPoint RowColumn ) const;
LPoint SquareOriginOf (const LPoint RowColumn ) const;
};

#include "SimpleBoard.h"
#include <assert.h>

SimpleBoard :: SimpleBoard (LPoint UpperLeftCorner,
int SquaresPerSide,
int PixelsPerSide ,
Color FirstSquareColor) {

assert ( (SquaresPerSide % 2) == Even );

BoardSize = SquaresPerSide;
SquareSize = PixelsPerSide / SquaresPerSide;
EvenSquareColor = FirstSquareColor;
Offset = UpperLeftCorner;

if (FirstSquareColor == Dark)
OddSquareColor = Light;
else
OddSquareColor = Dark;
}

LPoint SimpleBoard :: SquareIndexAt (const LPoint PixelLocation ) const{

LPoint LocalPixelLocation = PixelLocation - Offset;

assert( (LocalPixelLocation.x() >= 0) &&
(LocalPixelLocation.y() >= 0) );
assert( (LocalPixelLocation.x() <=  BoardSize * SquareSize )
&& (LocalPixelLocation.y() <=  BoardSize * SquareSize ) 		);

return LocalPixelLocation / SquareSize;
}

Color SimpleBoard :: ColorOf (const LPoint RowColumn ) const {

LPoint SquareIndex = RowColumn;

int IndexSum = SquareIndex.x() + SquareIndex.y();
int SquareParity = IndexSum % 2;

if ( SquareParity == Even )
return EvenSquareColor;
else
return OddSquareColor;
}

LPoint SimpleBoard ::
SquareOriginOf (const LPoint RowColumn ) const {
int LocalX = RowColumn.x() * SquareSize;
int LocalY = RowColumn.y() * SquareSize;

LPoint SquareOriginLocalCoordinates( LocalX, LocalY );
return SquareOriginLocalCoordinates + Offset;
}

LPoint SimpleBoard ::
CenterOfSquare (const LPoint RowColumn ) const {

return SquareOriginOf( RowColumn ) +
LPoint( SquareSize/2 , SquareSize/2);
}

void  SimpleBoard :: drawSquare( const LPoint RowColumn ) const {

LPoint SquareOriginGlobal = SquareOriginOf( RowColumn );

fl_rectf( SquareOriginGlobal.x(), SquareOriginGlobal.y(),
SquareSize , SquareSize, ColorOf(RowColumn)  );
}

void SimpleBoard :: draw() const{

for (int Row = 0; Row < BoardSize; Row++)
for (int Column = 0; Column < BoardSize; Column++)
drawSquare( LPoint(  Column, Row ));
}
```

How Do Pieces Know When SimpleBoard Changes Size?
They Don't
```class CheckerPiece {
public:
void draw();

static Board* MyBoard;

private:

int RowLocation;
int ColumnLocation;
Color MyColor;
}

void CheckerPiece :: draw() {

int Center = MyBoard->CenterOfSquare(
LPoint (RowLocation, ColumnLocation) );

int Radius = MyBoard->SizeOfSquare() - 8;

fl_circ( Center.x(), Center.y(), Radius , MyColor );
}

```
What Happens when there are 2 games?

This can be fixed.

How Do Peices Know When ComplexBoard Changes Size?

```void ComplexBoard :: ChangeSize (int NewSize ) {

for ( int R = 0; R < TheBoard.NumberOfRows(); Row++ )
for ( int C = 0; C < TheBoard.NumberOfColumns(); C++ )
if ( TheBoard[ R ][ C ] ->
ChangeSize ( NewSize ) )
}
```