Console Player

A. Sixth Edition
These classes are all base classes for console displays and on this edition I finished a simple CPlayer and
a CBag class which has one card rack, one letter rack as its own component. 
B.The problem
How to display in console without using iostream class?
C.The idea of program
 
These classes are for our comp354 project which is going to make a little game like cross word.
D.The major functions
E.Further improvement
F.File listing
1. tile.h
2. tile.cpp
3. tiles.h
4. tiles.cpp
5. token.h
6. token.cpp
7. tokens.h
8. tokens.cpp
9. RoverType.h
10. board.h
11. board.cpp
12. cell.h
13. cell.cpp
14. block.h
15. block.cpp
16. rummy.h
17. rummy.cpp
18. dictionary.h
19. dictionary.cpp
20. listener.h
21. listener.cpp
22. rack.h
23. rack.cpp
24. background.h
25. background.cpp
26. deck.h
27. deck.cpp
28. player.h
29. player.cpp
30. bag.h
31. bag.cpp
32. main.cpp (main)

 

file name: tile.h

#ifndef TILE_H
#define TILE_H

#include "RoverType.h"

class CTile
{
protected:
	char ch;
	WORD ftColor;
	WORD bkColor;
public:
	void display(int x, int y);
	void setFontColor(WORD theColor){ftColor=theColor;}
	void setBKGroundColor(WORD theColor){ bkColor=theColor;}
	void setValue(char myCh) { ch=myCh;}
	char getValue(){ return ch;}
	CTile(char myCh=DefaultCharacter);
};

#endif
 

file name: tile.cpp

#include "Tile.h"

HANDLE hOutPut=0;

CTile::CTile(char myCh)
{
	ftColor=DefaultFontColor;
	bkColor=DefaultBKGroundColor;
	setValue(myCh);
	if (hOutPut==0)
	{
		hOutPut=GetStdHandle(STD_OUTPUT_HANDLE);
	}
}

void CTile::display(int x, int y)
{
	COORD coord;
	coord.X=x;
	coord.Y=y;
	FillConsoleOutputAttribute(hOutPut, ftColor|bkColor, 1, coord, NULL);
	FillConsoleOutputCharacter(hOutPut, ch, 1, coord, NULL);
}

file name: tiles.h
#ifndef TILES_H
#define TILES_H

#include "tile.h"

class CTiles
{
private:
	CTile* tiles;
	int len;
	WORD ftColor;
	WORD bkColor;
	bool isVertical;
	void initialize();	
public:
	CTiles(const char* str);
	CTiles();
	virtual	~CTiles();
	void setDirection(bool beVertical){ isVertical=beVertical;}
	CTile& operator[](int index){return tiles[index];}
	void setFontColor(WORD theColor){ftColor=theColor;}
	void setBKGroundColor(WORD theColor){bkColor=theColor;}
	int getLength(){return len;}
	void display(int x, int y);
	void setValue(const char* str);
	void setLength(int size);
	void setNumber(int num);
};

#endif
 
file name: tiles.cpp
#include "tiles.h"

CTiles::CTiles()
{
	initialize();
}

void CTiles::initialize()
{
	len=0;
	tiles=NULL;
	isVertical=false;
	ftColor=DefaultFontColor;
	bkColor=DefaultBKGroundColor;
}

void CTiles::setNumber(int num)
{
	char buffer[10];
	itoa(num, buffer, 10);
	setValue(buffer);
}


CTiles::~CTiles()
{
	delete[]tiles;
}

void CTiles::setValue(const char* str)
{	
	//len=;
	setLength(strlen(str));
	for (int i=0; i<len; i++)
	{
		tiles[i].setValue(str[i]);
	}
}

CTiles::CTiles(const char* str)
{
	initialize();
	setValue(str);
}


void CTiles::display(int x, int y)
{
	for (int i=0; i<len; i++)
	{
		tiles[i].setFontColor(ftColor);
		tiles[i].setBKGroundColor(bkColor);
		if (!isVertical)
		{
			tiles[i].display(x+i, y);
		}
		else
		{
			tiles[i].display(x, y+i);
		}
	}
}

void CTiles::setLength(int size)
{
	if (len!=size)
	{
		len=size;
		delete[]tiles;
		tiles=new CTile[len] ;
	}
}
 
 
file name: token.h
#ifndef TOKEN_H
#define TOKEN_H

#include "block.h"


class CToken : public CBlock
{
protected:

public:	
	CToken(int num);
	CToken(char ch=DefaultCharacter);
	const CToken& operator=(const CToken& theToken);
	int getNumber();
	void setNumber(int num);	
	void setSuit(int theSuit);
	int getSuit();
};

class CCardBack: public CToken
{
public:
	CCardBack();
};

#endif
 
file name: token.cpp
#include "token.h"
#include "tile.h"

const CToken& CToken::operator =(const CToken& theToken)
{	
	for (int i=0; i<3; i++)
	{
		for (int j=0; j<3; j++)
		{
			block[i][j].setValue(theToken.block[i][j].getValue());
		}
	}
	return *this;
}

void CToken::setSuit(int theSuit)
{
	block[0][0].setValue(theSuit);
	block[2][2].setValue(theSuit);
}

CToken::CToken(char ch):CBlock(3)
{
	block[1][1].setValue(ch);	
}

int CToken::getNumber()
{
	if (block[1][0].getValue()!=0)
	{
		return (block[1][0].getValue()-'0')*10+block[1][1].getValue()-'0';
	}
	if (block[1][1].getValue()>'9')
	{
		switch(block[1][1].getValue())
		{
			case 'J': return 11;
			case 'Q': return 12;
			case 'K': return 13;
			case 'A': return 14;
		}
	}
	return block[1][1].getValue()-'0';
}

void CToken::setNumber(int num)
{
	//in no condition, this would happen
	if (num>99)
	{
		return ;
	}
	if (num>9)
	{
		block[1][0].setValue(num/10+'0');
		block[1][1].setValue(num%10+'0');
	}
	else
	{
		block[1][1].setValue(num+'0');
	}
}

CToken::CToken(int num)
{
	initialize();
	setNumber(num);
}

int CToken::getSuit()
{
	return block[0][0].getValue();
}

CCardBack::CCardBack()
{
	block[0][0].setValue(Club);
	block[0][2].setValue(Diamond);
	block[2][0].setValue(Heart);
	block[2][2].setValue(Spade);
	for (int i=0; i<3; i++)
	{
		for (int j=0; j<3; j++)
		{
			block[i][j].setBKGroundColor(DefaultCardBackBKGroundColor);
			block[i][j].setFontColor(DefaultCardBackFontColor);
		}
	}
}
 
file name: tokens.h
#ifndef TOKENS_H
#define TOKENS_H

#include "token.h"


class CTokens
{
protected:
	CToken* tokens;
	int len;
	int pos;
	WORD ftColor;
	WORD bkColor;
	WORD frColor;
	bool isVertical;//default is false
	void initialize();	
	bool pushToken(const CToken& token);
	bool popToken(CToken& token);
public:
	CTokens(int theLen=DefaultTokenLength);
	CTokens(const char* str);
	CToken& operator[](unsigned short index){ return tokens[index];}
	void setDirection(bool beVertical){isVertical=beVertical;}
	void setLength(int size);
	void setValue(const char* str);
	void setFontColor(WORD theColor);
	void setBKGroundColor(WORD theColor);
	void setFrameColor(WORD theColor);
	virtual ~CTokens();
	void display(int x, int y);
	//initialize the position of starting stack pos
	void setStackPos(int startPos=0){ pos=startPos;}
	void shuffle();
};

#endif
file name: tokens.cpp
#include "tokens.h"

CTokens::CTokens(int theLen)
{
	initialize();
	setLength(theLen);
}

CTokens::CTokens(const char* str)
{
	initialize();
	setValue(str);
}

void CTokens::initialize()
{
	len=0;
	tokens=NULL;
	isVertical=false;
	ftColor=DefaultFontColor;
	bkColor=DefaultBKGroundColor;
	frColor=DefaultFrameColor;
}

void CTokens::setBKGroundColor(WORD theColor)
{
	for (int i=0; i<len; i++)
	{
		tokens[i].setBKGroundColor(theColor);
	}
}

void CTokens::setFontColor(WORD theColor)
{
	for (int i=0; i<len; i++)
	{
		tokens[i].setFontColor(theColor);
	}
}

void CTokens::setFrameColor(WORD theColor)
{
	for (int i=0; i<len; i++)
	{
		tokens[i].setFrameColor(theColor);
	}
}

void CTokens::setLength(int size)
{
	if (len!=size)
	{
		delete []tokens;
		len=size;
		tokens=new CToken[len];
	}
}


void CTokens::setValue(const char* str)
{
	len=strlen(str);
	//tokens=new CToken[len];
	setLength(len);
	for (int i=0; i<len; i++)
	{
		tokens[i].setValue(str[i]);
	}
}

void CTokens::display(int x, int y)
{
	for (int i=0; i<len; i++)
	{
		if (!isVertical)
		{
			tokens[i].display(x+i*4, y);
		}
		else
		{
			tokens[i].display(x, y+i*4);
		}
	}
}

CTokens::~CTokens()
{
	delete [] tokens;	
}
file name: RoverType.h
#include <windows.h>

/*****************************nick****************************/

extern HANDLE hOutPut;


//the font color
#define  FTBLUE        FOREGROUND_BLUE 
#define	 FTGREEN       FOREGROUND_GREEN 
#define	 FTRED         FOREGROUND_RED 
#define	 FTPURPLE      FOREGROUND_BLUE|FOREGROUND_RED
#define	 FTGREY        FOREGROUND_BLUE|FOREGROUND_GREEN
#define	 FTBROWN	   FOREGROUND_RED|FOREGROUND_GREEN
#define	 FTWHITE       FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED
#define	 FTINTENSITY   FOREGROUND_INTENSITY

//the background color
#define	 BKBLUE        BACKGROUND_BLUE 
#define  BKGREEN       BACKGROUND_GREEN 
#define	 BKRED         BACKGROUND_RED 
#define	 BKPURPLE      BACKGROUND_BLUE|BACKGROUND_RED
#define	 BKGREY        BACKGROUND_BLUE|BACKGROUND_GREEN
#define	 BKBROWN	   BACKGROUND_RED|BACKGROUND_GREEN
#define	 BKWHITE       BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED
#define	 BKINTENSITY   BACKGROUND_INTENSITY

#define DefaultFontColor           FTRED
#define DefaultBKGroundColor       BKWHITE
#define DefaultFrameColor          BKGREY
#define DefaultIndexFontColor      FTWHITE
#define DefaultIndexBKGroundColor  BKBLUE
#define DefaultIndexFrameColor     BKBLUE
#define DefaultHighLightFont	   FTINTENSITY


#define DefaultBoardSize		   15
#define MaxBoardSize			   20

#define DefaultCharacter           0
#define DefaultTokenLength         7
#define MinimumLengthOfWord		   2
#define MaxInputBufferLength	   20


#define DefaultScreenWidth        120
#define DefaultScreenHeight       60

#define LetterCount               26
#define MaxLengthOfWord			  20
#define DefaultInputPositionRow   30
#define DefaultInputPositionCol   30

//rack
#define DefaultSelectedBKGColor   BKINTENSITY
#define DefaultSelectedFontColor  FTBROWN

#define DefaultLetterRack_x             30
#define DefaultLetterRack_y             30
#define DefaultCardRack_x               30
#define DefaultCardRack_y               38


//card back color
#define DefaultCardBackBKGroundColor BKBROWN
#define DefaultCardBackFontColor     FTBLUE

//bag
#define BagTokenNumber    0
#define BagTokenPoints    1
#define DefaultNumberOfToken   100
#define DefaultBlankTokenValue  255

//coord of bag
#define DefaultBag_x      40
#define DefaultBag_y      40
/*
enum Suit
{Club=5, Diamond=4, Heart=3, Spade=6};
*/
#define Club           5
#define Diamond        4
#define Heart          3
#define Spade          6

/****************************nick*****************************/


file name: board.h
#ifndef BOARD_H
#define BOARD_H

#include "cell.h"

class CBoard
{
private:
	int curRow, curCol;
	int headRow, headCol;
	bool isVer;
	bool isFirst;
	char buffer[MaxBoardSize];
	bool doFindStr();
	void setStartPoint();
	void getFirstStr();
	int findHead(int startRow, int startCol, bool isVertical);
protected:
	CCell** board;
	int boardWidth;
	void initialize(int size);
public:
	CBoard(int size=DefaultBoardSize);
	void setSize(int size);
	void display(int x, int y);
	char getValue(int r, int c);
	void setValue(int r, int c, char ch);
	void setValue(char** matrix);
	bool placeWord(int r, int c, const char* str, bool isVertical=false);
	void update(bool rollBack=false);
	char* getNextStr();
};

#endif
 
 
 
file name: board.cpp
#include "board.h"

void CBoard::initialize(int size)
{
	boardWidth=0;
	board=NULL;
	isFirst=true;
	setSize(size);
	for (int i=0; i<=size; i++)
	{
		for (int j=0; j<=size; j++)
		{
			if (i==0||j==0)
			{
				board[i][j].setBKGAll(DefaultIndexFontColor, DefaultIndexBKGroundColor);
								
				if (i!=0)
				{
					board[i][j].setNumber(i-1, false);
				}
				if (j!=0)
				{
					board[i][j].setNumber(j-1, true);
				}
			}
		}
	}
}

void CBoard::setValue(char** matrix)
{
	for (int i=1; i<=boardWidth; i++)
	{
		for (int j=1; j<=boardWidth; j++)
		{
			board[i][j].setValue(matrix[i-1][j-1]);
		}
	}
}

void CBoard::setSize(int size)
{
	if (boardWidth!=size)
	{
		if (board!=NULL)
		{
			for (int i=0; i<=boardWidth; i++)
			{
				delete []board[i];			
			}
		}
		delete[] board;
		boardWidth=size;
		board=new CCell*[size+1];
		for (int i=0; i<=size; i++)
		{			
			board[i]=new CCell[size+1];
		}		
	}
}
		

CBoard::CBoard(int size)
{
	initialize(size);	
}

void CBoard::setValue(int r, int c, char ch)
{
	board[r+1][c+1].setValue(ch);
}

char CBoard::getValue(int r, int c)
{
	return board[r+1][c+1].getValue();
}

void CBoard::display(int x, int y)
{	
	for (int i=0; i<=boardWidth; i++)
	{
		for (int j=0; j<=boardWidth; j++)
		{
			board[i][j].display(x+2*j, y+i*2);
		}

	}
}

void CBoard::update(bool rollBack)
{
	int row=curRow, col=curCol;
	while (board[row][col].getValue()!=0)
	{
		if (rollBack)
		{
			if (!board[row][col].getStatus())
			{				
				board[row][col].setValue(DefaultCharacter);
			}
		}	
		board[row][col].setFontColor(DefaultFontColor);
		board[row][col].setStatus(true);
		if (isVer)
		{
			row++;
		}
		else
		{
			col++;
		}
		if (row>boardWidth||col>boardWidth)
		{
			break;
		}
	}
}

void CBoard::setStartPoint()
{
	headRow=curRow;
	headCol=curCol;
	if (isVer)
	{
		headRow=findHead(headRow, headCol, isVer);
	}
	else
	{
		headCol=findHead(headRow, headCol, isVer);
	}	
}



void CBoard::getFirstStr()
{
	int row=headRow, col=headCol, pos=0;
	while (board[row][col].getValue()!=0) 
	{
		buffer[pos]=board[row][col].getValue();
		pos++;
		if (isVer)
		{
			row++;
		}
		else
		{
			col++;
		}
		if (row==boardWidth||col==boardWidth)
		{
			break;
		}
	}
	buffer[pos]='\0';
}

char* CBoard::getNextStr()
{	
	if (isFirst)
	{
		setStartPoint();
		isFirst=false;
		getFirstStr();
		return buffer;//the original one will always return
	}
	if (doFindStr())
	{
		return buffer;
	}
	else
	{
		return NULL;
	}
}

bool CBoard::doFindStr()
{
	int row=headRow, col=headCol, pos=0;
	if (headRow>boardWidth||headCol>boardWidth)
	{
		return false;
	}
	if (board[row][col].getValue()==0)
	{
		return false;
	}
	if (isVer)
	{
		//skip the old word placed by others
		if (board[row][col].getStatus())
		{
			headRow++;
			return doFindStr();
		}
		col=findHead(row, col, !isVer);//the crossing direction
		do//the boardWidth is one more than the real size 
		{
			buffer[pos]=board[row][col].getValue();
			col++;
			pos++;
			if (col>boardWidth)
			{
				break;
			}
		} while (board[row][col].getValue()!=0);
		buffer[pos]='\0';
		headRow++;
		if (pos>MinimumLengthOfWord)
		{
			return true;
		}
		else
		{			
			return doFindStr();
		}
	}
	else
	{
		if (board[row][col].getStatus())
		{
			headCol++;
			return doFindStr();
		}
		row=findHead(row, col, !isVer);
		do
		{
			buffer[pos]=board[row][col].getValue();
			row++;
			pos++;
			if (row>boardWidth)
			{
				break;
			}
		}while (board[row][col].getValue()!=0);
		buffer[pos]='\0';
		headCol++;
		if (pos>MinimumLengthOfWord)
		{
			return true;
		}
		else
		{			
			return doFindStr();
		}
	}
}

//to do
int CBoard::findHead(int startRow, int startCol, bool isVertical)
{
	if (isVertical)
	{
		while (startRow>0) //because the coord is starting from 1
		{
			if (board[startRow][startCol].getValue()==0)
			{
				break;
			}
			startRow--;
		}
		return startRow+1;
	}
	else
	{
		while (startCol>0)
		{
			if (board[startRow][startCol].getValue()==0)
			{
				break;
			}
			startCol--;
		}
		return startCol+1;
	} 
}



bool CBoard::placeWord(int r, int c, const char* str, bool isVertical)
{
	int row=r+1, col=c+1, pos=0;
	curRow=row;
	curCol=col;
	isVer=isVertical;
	while (str[pos]!='\0')
	{
		if (board[row][col].getValue()==0)
		{
			board[row][col].setValue(str[pos]);
			board[row][col].setFontColor(DefaultHighLightFont);
			board[row][col].setStatus(false);
			pos++;
		}
		else
		{
			//the starting position cannot be occupied
			if (pos==0)
			{
				return false;
			}
		}
		if (isVertical)
		{
			row++;
		}
		else
		{
			col++;
		}
		if (row>boardWidth||col>boardWidth)//the bound is boardWidth
		{			
			return str[pos]=='\0';
		}
	}
	return true;
}


		


 
file name: cell.h
#ifndef CELL_H
#define CELL_H

#include "block.h"

class CCell: public CBlock
{
protected:
	bool isOld;
public:
	CCell();
	void setStatus(bool beOld);
	bool getStatus();
	void setNumber(int num, bool atBottom);//special for index bar
	void setBKGAll(WORD theFont, WORD theBKG);
};

#endif
 
 
 
file name: cell.cpp
#include "cell.h"

CCell::CCell():CBlock(1)
{
	isOld=true;
}

void CCell::setStatus(bool beOld)
{
	isOld=beOld;
}

bool CCell::getStatus()
{
	return isOld;
}

void CCell::setNumber(int num, bool atBottom)
{
	int y=0;
	if (atBottom)
	{
		y=1;
	}
	if (num>9)
	{
		block[0][y].setValue(num/10+'0');
		block[1][y].setValue(num%10+'0');
	}
	else
	{
		block[0][y].setValue(num+'0');
	}
}

void CCell::setBKGAll(WORD theFont, WORD theBKG)
{
	for (int i=0; i<2; i++)
	{
		for (int j=0; j<2; j++)
		{
			block[i][j].setBKGroundColor(theBKG);
			block[i][j].setFontColor(theFont);
		}
	}
}
file name: block.h
#ifndef BLOCK_H
#define BLOCK_H

#include "tile.h"

class CBlock
{
protected:
	CTile** block;
	int width;
	void initialize();
public:
	CBlock(int size=1);
	void setLength(int size);
	void setValue(char myCh);
	char getValue();
	void setFrameColor(WORD theColor);
	void setFontColor(WORD theColor);
	void setBKGroundColor(WORD theColor);
	void display(int x, int y);
};

#endif
 
 
file name: block.cpp
#include "block.h"

CBlock::CBlock(int size)
{
	initialize();
	setLength(size);
}

void CBlock::initialize()
{
	block=NULL;
	width=0;
}

void CBlock::setLength(int size)
{
	width=size;
	block=new CTile*[size+1];
	for (int i=0; i<=size; i++)
	{
		block[i]=new CTile[size+1];
		for (int j=0; j<=size; j++)
		{
			if (i==size||j==size)
			{
				block[i][j].setBKGroundColor(DefaultFrameColor);
			}
		}
	}
}

void CBlock::setValue(char myCh)
{
	block[(width-1)/2][(width-1)/2].setValue(myCh);
}

void CBlock::setBKGroundColor(WORD theColor)
{
	for (int i=0; i<width; i++)
	{
		for (int j=0; j<width; j++)
		{
			block[i][j].setBKGroundColor(theColor);
		}
	}
}

void CBlock::setFontColor(WORD theColor)
{
	for (int i=0; i<width; i++)
	{
		for (int j=0; j<width; j++)
		{
			block[i][j].setFontColor(theColor);
		}
	}
}

void CBlock::setFrameColor(WORD theColor)
{
	for (int i=0; i<=width; i++)
	{
		for (int j=0; j<=width; j++)
		{
			if (i==width||j==width)
			{
				block[i][j].setBKGroundColor(theColor);
			}
		}
	}
}

char CBlock::getValue()
{
	return block[(width-1)/2][(width-1)/2].getValue();
}

void CBlock::display(int x, int y)
{
	for (int i=0; i<=width; i++)
	{
		for (int j=0; j<=width; j++)
		{
			block[i][j].display(x+j, y+i);
		}
	}
}
file name: rummy.h
#ifndef RUMMY_H
#define RUMMY_H

#include "token.h"

class CRummy
{
private:
	int array[7];
	int pos;
	void addOne(CToken* tokens, int index);
public:
	bool verify(CToken* tokens, int len);
	CRummy();
};

#endif
file name: rummy.cpp
#include "rummy.h"

bool CRummy::verify(CToken* tokens, int len)
{
	bool sameSuit=true, isSequence=true, isGroup=true;
	int theSuit, theBase, theNext;
	for (int i=0; i<len; i++)
	{
		addOne(tokens, i);
	}
	theSuit=tokens[array[0]].getSuit();
	theBase=tokens[array[0]].getNumber();
	for (i=1; i<len; i++)
	{
		if (tokens[array[i]].getSuit()!=theSuit)
		{
			sameSuit=false;
		}
		theNext=tokens[array[i]].getNumber();
		if (theNext-theBase!=0)
		{
			isGroup=false;
		}
		if (theNext-theBase!=-1)
		{
			isSequence=false;
		}
		theBase=theNext;
	}
	return sameSuit||isSequence||isGroup;
}
	

CRummy::CRummy()
{
	pos=0;
}

void CRummy::addOne(CToken* tokens, int index)
{
	int i=0;
	if (pos==0)
	{
		array[0]=index;
		pos++;
		return;
	}
	//insertion sorting	
	while (i<pos)
	{
		if (tokens[index].getNumber()>tokens[array[i]].getNumber())
		{
			break;
		}
		i++;	
	}
	
	for (int j=pos; j>i; j--)
	{
		array[j]=array[j-1];
	}
	array[i]=index;
	pos++;
}
file name: dictionary.h
#include "RoverType.h"


struct Letter
{
	char ch;
	Letter* next;
	Letter* son;
	bool end;
};

class Dictionary
{
private:
	Letter* root[52];
	Letter* current;
	Letter* findBrother(Letter* brother, char ch);
	Letter* createLetter(char ch);
	Letter* addSon(char ch);
	int indexOf(char ch);
	bool caseSensitive;
	void change2Capital(char* target, char* source);
public:
	bool addWord(char* str);
	bool findWord(char* str);
	void readFile(const char* fileName);
	void setCaseSensitive(bool isCaseSensitive);
	Dictionary(bool isCaseSensitive=true);
};

file name: dictionary.cpp
#include <stdio.h>
#include "dictionary.h"

void Dictionary::change2Capital(char* target, char* source)
{
	char* tgt=target, *src=source;
	do
	{
		*tgt=toupper(*src);
		tgt++;
		src++;
	}while (*src!='\0');
	*tgt='\0';
}

void Dictionary::readFile(const char* fileName)
{
	char buffer[MaxLengthOfWord];
	char*ptr=buffer;
	char ch;
	FILE* stream;
	stream=fopen(fileName, "r");
	while (!feof(stream))
	{
		ch=fgetc(stream);
		if (isalnum(ch))
		{
			if (!caseSensitive)
			{
				*ptr=toupper(ch);
			}
			else
			{
				*ptr=ch;
			}
			ptr++;
		}
		else
		{
			*ptr='\0';
			if (ptr!=buffer)
			{
				addWord(buffer);
				ptr=buffer;
			}
			//else remain the same ptr.
		}
	}
}


bool Dictionary::findWord(char* str)
{
	char* ptr=str;
	char buffer[MaxLengthOfWord];
	if (!caseSensitive)
	{		
		ptr=buffer;
		change2Capital(buffer, str);
	}
	Letter* hold;
	int index;
	//not empty string
	if (ptr!=NULL)
	{
		index = indexOf(*ptr);
		if (index==-1)
		{
			return false;
		}
		current=root[index];		
		ptr++;

		if (current->son==NULL)
		{
			//if string is a one-letter string
			if (*ptr=='\0')
			{
				//and there is a one-letter word in dictionary
				return current->end;
			}
			else
			{
				return false;
			}
		}
		hold=current;//
		current=current->son;
		
		while (*ptr!='\0')
		{				
			current=findBrother(current, *ptr);
			if (current==NULL)
			{
				return false;
			}
			if (current->ch==*ptr)
			{
				hold=current;
				current=current->son;
			}
			else
			{
				//not found
				return false;
			}
			ptr++;
		} 
		return hold->end;
	}
	//in my dictionary there is no empty string word
	return false;
}
	

Letter* Dictionary::createLetter(char ch)
{
	Letter* ptr=new Letter;
	ptr->ch=ch;
	ptr->end=false;
	ptr->next=NULL;
	ptr->son=NULL;
	return ptr;
}

//ch is not '\0'
Letter* Dictionary::findBrother(Letter* brother, char ch)
{
	Letter* hold=brother;
	if (brother==NULL)
	{
		return NULL;
	}
	while (hold->next!=NULL)
	{
		if (hold->ch==ch)
		{
			break;
		}
		hold=hold->next;
	}
	return hold;
}

Letter* Dictionary::addSon(char ch)
{
	//the word ends
	if (ch=='\0')
	{
		current->end=true;		
	}
	else
	{
		//need a new son
		if (current->son==NULL)
		{
			current->son=createLetter(ch);
			current=current->son;
		}
		else
		{
			//current->son is not NULL!!!
			current=findBrother(current->son, ch);
			//check if the current is the node
			if (current->ch!=ch)
			{
				current->next=createLetter(ch);	
				current=current->next;//add brother
			}	
			//else return current;!!!
		}
	}
	return current;
}


//add word actually add letter by letter till NULL, nonsense!
bool Dictionary::addWord(char* str)
{
	char* ptr=str;
	int index;
	if (*ptr!='\0')
	{
		index=indexOf(*ptr);
		if (index==-1)
		{
			return false;
		}
		current=root[index];		
		do
		{
			ptr++;
			current=addSon(*ptr);			
		} while (*ptr!='\0');
		return true;
	}
	return false;
}

Dictionary::Dictionary(bool isCaseSensitive)
{
	caseSensitive=isCaseSensitive;

	for (int i=0; i<LetterCount; i++)
	{
		root[i]=new Letter;
		root[i]->ch='A'+i;
		root[i]->next=NULL;
		root[i]->son=NULL;
	}
	if (caseSensitive)
	{
		for (i=0; i<LetterCount; i++)
		{
			root[i+LetterCount]=new Letter;
			root[i+LetterCount]->ch='a'+i;
			root[i+LetterCount]->next=NULL;
			root[i+LetterCount]->son=NULL;
		}
	}
}

int Dictionary::indexOf(char ch)
{
	if (ch-'A'>=0&&ch-'Z'<=0)
	{
		return ch-'A';
	}
	if (ch-'a'>=0&&ch-'z'<=0)
	{
		return ch-'a'+LetterCount;
	}
	return -1;
}


file name: listener.h
#include "RoverType.h"

class CListener
{
protected:
	static HANDLE hOut;
	static char buffer[MaxInputBufferLength];
	void initialize();
public:
	CListener();
	int listenMenu();
	char* listenStr();//must ended by entering return
};

file name: listener.cpp
#include "listener.h"

HANDLE CListener::hOut=NULL;
char CListener::buffer[MaxInputBufferLength];

CListener::CListener()
{
	initialize();
}

void CListener::initialize()
{
	hOut=GetStdHandle(STD_INPUT_HANDLE);
	
}

int CListener::listenMenu()
{
	DWORD temp;
	SetConsoleMode(hOut, 0);
	ReadConsole(hOut, buffer, 1, &temp, NULL);
	return buffer[0]-'0';
}

char* CListener::listenStr()
{
	DWORD temp;
	SetConsoleMode(hOut, ENABLE_LINE_INPUT);
	ReadConsole(hOut, buffer, MaxInputBufferLength, &temp, NULL);
	buffer[temp-1]='\0';
	return buffer;
}
file name: background.h
//background
#ifndef BACKGROUND_H
#define BACKGROUND_H

#include "RoverType.h"

class CBackGround
{
private:
	int width, height;
	int row, col;
	WORD ftColor;
	WORD bkColor;
public:
	CBackGround(int theRow=0, int theCol=0);
};

#endif
 
file name: background.cpp
#include "background.h"



CBackGround::CBackGround(int theRow, int theCol)
{
	char ch=0;
	COORD coord;
	bkColor=BKGREEN;
	ftColor=FTWHITE;
	width=DefaultScreenWidth;
	height=DefaultScreenHeight;
	row=theRow;
	col=theCol;
	if (hOutPut==0)
	{
		hOutPut=GetStdHandle(STD_OUTPUT_HANDLE);
	}
	//SetConsoleTextAttribute(hOutPut, bkColor|ftColor);
	for (int r=row; r<height; r++)
	{
		for (int c=col; c<width; c++)
		{	
			coord.X=c;
			coord.Y=r;
			FillConsoleOutputAttribute(hOutPut, ftColor|bkColor, 1, coord, NULL);
			FillConsoleOutputCharacter(hOutPut, ch, 1, coord, NULL);
		}
	}
	SetConsoleTitle("WordRover");
	CONSOLE_CURSOR_INFO cursorInfo;
	cursorInfo.bVisible=false;
	cursorInfo.dwSize=50;
	SetConsoleCursorInfo(hOutPut, &cursorInfo);
	coord.X = DefaultInputPositionCol;
	coord.Y =DefaultInputPositionRow;
	SetConsoleCursorPosition(hOutPut, coord);

}

file name: rack.h
#ifndef CRACK_H
#define CRACK_H
#include "tokens.h"
#include "rummy.h"

class CRack: public CTokens
{
protected:
	char buffer[9];
	CToken cardBuf[7];
	char exchanged;	
	static CRummy rummy;
	CToken empty;
    int selected[7];
	int selectedCount;
	int x,y;
public:
	int exchangedIndex;
	CRack();
	bool selectToken(int index, bool isLetter=true);//success return true
	void addToken(const CToken& token);
	//void showRack(int x,int y);
	void addExchanged(char exch);
	void updateRack(bool rollBack=false);
	bool canAdd() { return selectedCount>0;}
	const char* exportWord();
	bool verifyCards();
	void setCoord(int theX, int theY){ x=theX; y=theY;}
	void removeToken(int index, CToken& result);
	void showRack();
};

#endif
 
 
file name: rack.cpp
#include "rack.h"


CRummy CRack::rummy;

CRack::CRack():CTokens(7)
{
	selectedCount=7;//means empty at beginning
	for (int i=0; i<7; i++)
	{
		selected[i]=i;
	}
	exchangedIndex=-1;//means no exchanged!!!
	x=y=0;
}


bool CRack::selectToken(int index, bool isLetter)
{
	if (selectedCount==7)
	{
		return false;
	}
	for (int i=0; i<selectedCount; i++)
	{
		if (index==selected[i])
		{
			return false;//means repeat selecting
		}
	}
	selected[selectedCount]=index;
	if (isLetter)
	{
		buffer[selectedCount]=tokens[index].getValue();	
	}
	else
	{
		cardBuf[selectedCount]=tokens[index];
	}
	tokens[index].setBKGroundColor(DefaultSelectedBKGColor);	
	tokens[index].setFontColor(DefaultSelectedFontColor);
	selectedCount++;
	showRack();
	return true;
}

bool CRack::verifyCards()
{
	if (selectedCount==0)
	{
		return false;
	}
	return rummy.verify(cardBuf, selectedCount);
}

void CRack::addToken(const CToken& newToken)
{
	if (selectedCount>0)
	{
		tokens[selected[--selectedCount]]=newToken;
	}
}


void CRack::addExchanged(char ch)
{
	exchanged=ch;
	exchangedIndex=selectedCount;
}


void CRack::showRack()
{
	display(x,y);
}


void CRack::removeToken(int index, CToken& result)
{
	result=tokens[index];
	tokens[index]=empty;
}

const char* CRack::exportWord()
{
	//insert the exchanged letter
	if (exchangedIndex!=-1)
	{
		for (int i=selectedCount; i>exchangedIndex; i--)
		{
			buffer[i]=buffer[i-1];
		}
		buffer[exchangedIndex]=exchanged; //insert the char
		buffer[selectedCount+1]='\0';
	}
	else
	{
		buffer[selectedCount]='\0';
	}
	return buffer;
}

void CRack::updateRack(bool rollBack)
{
	if(rollBack)
	{
		for(int i=0; i<selectedCount;i++)
		{
			tokens[selected[i]].setBKGroundColor(DefaultBKGroundColor);
			tokens[selected[i]].setFontColor(DefaultFontColor);			
		}
		selectedCount=0;
		exchangedIndex=-1;
	}
	else
	{
		for(int i=0; i<selectedCount;i++)
		{
			tokens[selected[i]]=empty;			
		}        
		exchangedIndex=-1;//should I do at this moment?
	}
}

file name: deck.h
#ifndef DECK_H
#define DECK_H	

#include "tokens.h"

class CDeck: public CTokens
{
protected:
	CCardBack deckBack;
	bool faceDown;
public:
	CDeck(bool isEmpty=false);
	void showHand();
    int  numOfCards();
	bool addCard(const CToken& card);
	bool removeCard(CToken& token);	
	void setFace(bool faceDown=true);
	void display(int x, int y);
};

#endif
 
file name: deck.cpp
#include "deck.h"

char cardValue[12]={'2','3','4','5','6','7','8','9','J','Q','K','A'};
int suitValue[4]={Club, Diamond, Heart, Spade};

CDeck::CDeck(bool isEmpty):CTokens(52)
{   
	//do initialize
	faceDown=true;
	for(int i=0;i<4;i++)
	{		
		for(int j=0;j<13; j++)
		{
			if (j==12)
			{
				tokens[i*13+j].setNumber(10);
			}
			else
			{
				tokens[i*13+j].setValue(cardValue[j]);
			}
			tokens[i*13+j].setSuit(suitValue[i]);
		}
	} 
	if (isEmpty)
	{
		pos=0;	
	}
	else
	{
		pos=len;
	}	
}

void CDeck::showHand()
{
	for (int i=0; i<4; i++)
	{
		for (int j=0; j<13; j++)
		{
			tokens[i*13+j].display(j*4, i*4);
		}
	}
}

bool CDeck::addCard(const CToken& card)
{
	return pushToken(card);
}

bool CDeck::removeCard(CToken& card)
{
	return popToken(card);
}

void CDeck::setFace(bool isFaceDown)
{
	faceDown=isFaceDown;
}

void CDeck::display(int x, int y)
{
	if (faceDown||pos==0)
	{
		deckBack.display(x, y);
	}
	else
	{
		tokens[pos-1].display(x, y);
	}
}


file name: player.h
#ifndef CPLAYER_H
#define CPLAYER_H

#include "rovertype.h"
#include "rack.h"

//to do:
//I need charles's CScoreBoard to put an instance inside Player
//so that all set, get method is implemented by CScoreBoard
class CPlayer
{
private:
	char* name;
	CRack rackLetter;
	CRack rackCard;
	int currentScore;
	int totalScore;
	int index;
public:
	CPlayer();
	~CPlayer();
	void setName(const char* theName);
	const char* getName();
	int getCurrentScore();
	void setCurrentScore(int score);
	int getTotalScore();
	void setTotalScore(int score);
	int getIndex(void);
	void setIndex(int theIndex);
	bool selectCard(int index);
	bool selectLetter(int index);
	void addCard(const CToken & newCard );
	void addLetter(const CToken& newLetter);
	const char* exportWord();
	bool verifyCards();
	void display();
	void discardCard(int index, CToken& result);
	void discardLetter(int index, CToken& result);
	bool canAddCard();
	bool canAddLetter();
};

#endif
 
 
file name: player.cpp
#include "player.h"


CPlayer::CPlayer()
{
	name=NULL;
	index=-1;
	rackLetter.setCoord(DefaultLetterRack_x, DefaultLetterRack_y);
	rackCard.setCoord(DefaultCardRack_x, DefaultCardRack_y);
	display();
}

void CPlayer::display()
{
	rackLetter.showRack();
	rackCard.showRack();
	//to do:
	//here to call scoreboard set current player method
}

void CPlayer::discardCard(int index, CToken& result)
{
	rackCard.removeToken(index, result);
}

void CPlayer::discardLetter(int index, CToken& result)
{
	rackLetter.removeToken(index, result);
}


CPlayer::~CPlayer()
{
	if (name!=NULL)
	{
		delete[]name;
	}
}

void CPlayer::setName(const char* theName)
{
	if (name!=NULL)
	{
		delete[]name;
	}
	name=new char[strlen(theName)+1];
	strcpy(name, theName);
}


const char* CPlayer::getName()
{
	return name;
}

void CPlayer::setCurrentScore(int score)
{
	currentScore=score;
}

int CPlayer::getCurrentScore()
{
	return currentScore;
}

void CPlayer::setTotalScore(int score)
{
	totalScore=score;
}

int CPlayer::getTotalScore()
{
	return totalScore;
}

int CPlayer::getIndex()
{
	return index;
}

bool CPlayer::selectCard(int index)
{
	return rackCard.selectToken(index);
}

bool CPlayer::selectLetter(int index)
{
	return rackLetter.selectToken(index);
}

void CPlayer::addCard(const CToken& newToken)
{
	rackCard.addToken(newToken);
}
  
void CPlayer::addLetter(const CToken& newToken)
{
	rackLetter.addToken(newToken);
}

const char* CPlayer::exportWord()
{
	return rackLetter.exportWord();
}
  
bool CPlayer::verifyCards()
{
	return rackCard.verifyCards();
}

bool CPlayer::canAddCard()
{
	return rackCard.canAdd();
}

bool CPlayer::canAddLetter()
{
	return rackLetter.canAdd();
}



file name: bag.h
#ifndef BAG_H
#define BAG_H

#include "RoverType.h"
#include "tokens.h"

class CBag: public CTokens
{
private:
	static int tokenData[27][2];
	int tokenLeft;
	CToken bag;
public:
	CBag();
	int getTokenPoint(char ch);
	int getBlankNumber();
	void setBlankNumber(int newNum);	
	int getTokenNumber(char ch);
	void setTokenPoint(char ch, int newPoint);
	void setTokenNumber(char ch, int newNumber);	
	bool getToken(CToken& result);
	void showBag();//only show the number of left tokens
};

#endif
 
file name: bag.cpp



#include "bag.h"

/*
 2 "blank" tiles (scoring 0 points), 9 As (1 point), 2 Bs (3), 2 Cs (3), 4 Ds (2), 
 12 Es (1), 2 Fs (4), 3 Gs (2), 2 Hs (4), 9 Is (1), 1 J (8), 1 K (5), 4 Ls (1), 
 2 Ms (3), 6 Ns (1), 8 Os (1), 2 Ps (3), 1 Q (10), 6 Rs (1), 4 Ss (1), 6 Ts (1),
 4 Us (1), 2 Vs (4), 2 Ws (4), 1 X (8), 2 Ys (4), and 1 Z (10).

  */

int CBag::tokenData[27][2]=
{
	{9,  1}, // As (1 point),
	{2,  3},// Bs (3),
	{2,  3},// Cs (3), 
	{4,  2},// Ds (2), 
	{12, 1},//Es (1),
	{2,  4},// Fs (4),
	{3,  2},//Gs (2), 
	{2,  4},//Hs (4),
	{9,  1},// Is (1), 
	{1,  8},// J (8), 
	{1,  5},// K (5), 
	{4,  1},// Ls (1),
	{2,  3},// Ms (3),
	{6,  1},//Ns (1), 
	{8,  1},// Os (1),
	{2,  3},// Ps (3), 
	{1,  10},// Q (10),
	{6,  1},// Rs (1),
	{4,  1},// Ss (1), 
	{6,  1},// Ts (1),
	{4,  1},// Us (1),
	{2,  4},// Vs (4),
	{2,  4},// Ws (4),
	{1,  8},// X (8),
	{2,  4},// Ys (4), and 
	{1,  10},// Z (10).
	{2,   0}//blank token valued 255
};


bool CBag::getToken(CToken& result)
{
	if (tokenLeft==0)
	{
		return false;
	}
	result=tokens[--tokenLeft];
	return true;
}

CBag::CBag():CTokens(DefaultNumberOfToken)
{
	bag.setNumber(DefaultNumberOfToken);
	tokenLeft=DefaultNumberOfToken;
	int index=0;
	for (int i=0; i<27; i++)
	{
		int j=0;
		while (j<tokenData[i][BagTokenNumber])
		{
			if (i!=26)
			{
				tokens[index].setValue(i+'A');
			}
			else
			{
				tokens[index].setValue((char)DefaultBlankTokenValue);
			}
			j++;//always
			index++;
		}
	}
	shuffle();
}

void CBag::showBag()
{
	bag.setNumber(tokenLeft);
	bag.display(DefaultBag_x, DefaultBag_y);
}

int CBag::getTokenNumber(char ch)
{
	return tokenData[ch-'A'][BagTokenNumber];
}

int CBag::getBlankNumber()
{
	return tokenData[26][BagTokenNumber];
}

void CBag::setBlankNumber(int newNum)
{
	tokenLeft+= newNum-tokenData[26][BagTokenNumber];
}

void CBag::setTokenNumber(char ch, int newNum)
{
	tokenLeft+=newNum-tokenData[ch-'A'][BagTokenNumber];
	tokenData[ch-'A'][BagTokenNumber]=newNum;
}

void CBag::setTokenPoint(char ch, int newPoint)
{
	tokenData[ch-'A'][BagTokenPoints]=newPoint;
}

int CBag::getTokenPoint(char ch)
{
	return tokenData[ch-'A'][BagTokenPoints];
}





file name: main.cpp(main)
#include "tokens.h"
#include "tiles.h"
#include "board.h"
#include "block.h"
#include "listener.h"
#include "rummy.h"
#include "dictionary.h"
#include "background.h"
#include "deck.h"
#include "rack.h"
#include "bag.h"
#include "player.h"


//#include <iostream>
//using namespace std;


int  main()
{
//	const int Size=14;
	CBackGround CB;
/*
	char** matrix;
	
	matrix=new char*[Size];
	for (int i=0; i<Size; i++)
	{
		matrix[i]=new char[Size];
		for (int j=0; j<Size; j++)
		{
			matrix[i][j]='A'+i+j;
		}
	}
	
	CBoard C(Size);
	//normally display a string
	C.placeWord(5, 4, "first");
	C.update();//with updates, change color to normal
	//C.display(1,1);
	//try to place a string which will exceed bounds
	C.placeWord(6, 5, "invisable");
	C.update();
	//update with "roll back" and erase it
	//C.update(true);
	//so you see nothing of this new string
	//C.display(1,1);
	//place a third string for comparison and vertically
	C.placeWord(2, 7, "vertical", true);
	C.update();
	//C.update();
	C.placeWord(7, 5, "newstring");
	C.update();
	C.placeWord(8, 3, "third");
	C.update();
	C.placeWord(9, 6, "fourth");
	//so you will see 1st, 3rd string
	C.display(1,1);

	CTiles D;
	char* ptr;
	int i=0;
	while ((ptr=C.getNextStr())!=NULL)
	{
		D.setValue(ptr);
		D.display(18, 37+i);
		i++;
	}
*/
	//CListener C;
	//CToken T;
	//T.setNumber(C.listenMenu());
	//T.display(10, 10);

	//CTokens tokens;//(C.listenStr());
	//tokens.setValue(C.listenStr());
	//tokens.display(1, 15);
	/*
	const int len=3;
	CTiles ok("ok");
	CToken tokens[len];
	/*
	for (int i=0; i<len; i++)
	{
		tokens[i].setNumber((i+1)*2);
		tokens[i].setSuit(
	}

	tokens[0].setNumber(7);
	tokens[0].setSuit(Spade);
	tokens[1].setNumber(7);
	tokens[1].setSuit(Heart);
	tokens[2].setNumber(7);
	tokens[2].setSuit(Diamond);
	CRummy R;
	if (R.verify(tokens, 3))
	{
		ok.display(1,1);
	}

	for (int i=0; i<len; i++)
	{
		tokens[i].display(i*4+3, 5);
	}
		*/
	char buffer[15]={'a','B', 'c', 'g','x', 'u','o','\0'};
	//CTiles C("ok");
	//Dictionary D(false);
	//D.readFile("wordsource.txt");
	//CDeck deck;
	//deck.setFace();
	//deck.display(5, 5);
	/*
	for (int i=0; i<4; i++)
	{
		CToken token;
		token.setValue(buffer[i]);
		deck.addCard(token);
	}
	//deck.setFace(false);
	
	//deck.
	
	//deck.display(15,15);
	CToken card;
	card.setValue('B');
	//card.display(23, 23);
	deck.shuffle();
	deck.showHand();
	*/
	/*
	CRack C;
	CToken token;
	int i=0;
	while (C.canAdd())
	{
		token.setValue(buffer[i]);

		C.AddToken(token);
		i++;
	}
	C.showRack();

	C.SelectToken(3);
	C.SelectToken(5);
	C.addExchanged('A');
	C.SelectToken(0);
	C.SelectToken(5);
	CTiles t(C.exportSelected());
	t.display(10,10);
	//C.updateRack();
	C.showRack();

	t.setNumber(C.exchangedIndex);
	t.display(5,5);
	*/
	//CBag C;
	//CToken hold;
	
	//C.display(0,0);
	//C.showBag();
	/*
	int x=0, y=0;
	CToken token;

	while (C.getToken(token))
	{
		x+=6;
		if (x>100)
		{
			x=0;
			y+=6;
		}
		//hold.setValue(token.setValue())
		//hold.display(2,2);
		token.display(x,y);
		if (x>15)
			break;
		
	}
	C.showBag();
*/
	CPlayer P;
	CListener C;
	P.display();
	CToken t;
	int i=Heart;
	while (P.canAddCard())
	{
		t.setSuit(i%4+Heart);
		t.setNumber(i+1);
		P.addCard(t);
		i=C.listenMenu();
	}
	while (P.canAddLetter())
	{
		t.setValue(i+'B');
		P.addLetter(t);
		i=C.listenMenu();
	}


	return 0;


}







The input is something like following:
Here is the result:

 





                                 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)