CS 596 OODP
Board Assignment
[To Lecture Notes Index]
San Diego State University -- This page last updated November 14, 1995

Contents of Board Assignment Lecture
- Solutions and Issues on Board Class
- Solution 1 to Assignment
- Simple Board Class
- Solution 2 to Assignment
- Issues
- Storing and Accessing
- How to call SquareThing Constructors?
- What is a square thing?
- Inheritance vs. Composition
- ComplexBoard Class
- Which Solution is Better?
- SimpleBoard Responsibilities
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
Board class does all the work
#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;
float radiusVector() const;
private:
int xCoordinate;
int yCoordinate;
};
LPoint LPoint :: operator / ( int scalar ) const {
return LPoint ( xCoordinate / scalar, yCoordinate / scalar);
}
Board class contains n*n square things, which do some work
How to store and access the n*n square things?
What is a square thing?
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();
Answer - You cant
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 );
};
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
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
Less work - get operations for free
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 {}
#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();
}
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 ) )
}