Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Dec 9th, 2005, 10:42 PM   #1
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
Tic Tac Toe progress

I don't know what happened to the Tic Toe contest (I guess there was not enough interest) but I though I would try working on a Tic Tac Toe game. It currently uses text, but after getting enough experience with Qt, I'd like to try to implement it with a GUI.

It also only uses a random position for the AI, because I haven't developed the AI makeMove() function yet.

Keep in mind, this is the equivalent of a rough draft. I'm sure there are hundreds of improvements.
tic.h

//tic.h -- TicTacToe declarations

#ifndef TICTACTOE_H_
#define TICTACTOE_H_

class Board {
	private:
		static char board[3][3];
		char player;
		char otherPlayer;
		char *checkBoard(int);
	public:
		Board(char,char);
		void reset();
		virtual bool makeMove(int);
		bool checkWin();
		void show() const;
		virtual ~Board(); 
};

/*class CBoard : public Board { //TODO
	public:
		CBoard(char);
		virtual bool makeMove(int);
};*/

#endif

tic.cpp

//tic.cpp -- implementation of class

#include <iostream>
#include "tic.h"

char Board::board[3][3];

Board::Board(char icon, char otherIcon) {
	//std::cout << "constructor called" << std::endl;
	player = icon;
	otherPlayer = otherIcon;
}

/*void Board::set() {
	//std::cout << "set() called" << std::endl;
	if(boardSet == false) {
		//std::cout << "Board being set..." << std::endl;
		for(int x = 0; x < 3; x++)
			for(int y = 0; y < 3; y++)
				Board::board[x][y] = ' ';
	}

	else {
		std::cout << "board previously set" << std::endl;
		std::cout << "use reset() to reset game" << std::endl;
	}

	boardSet = true;
}*/

void Board::reset() {
	for(int x = 0; x < 3; x++)
		for(int y = 0; y < 3; y++)
			Board::board[x][y] = ' ';
}

bool Board::makeMove(int space) {
	//board setup is like that of numpad
	if(space < 1 || space > 9) {
		std::cout << "invalid range!" << std::endl;
		
		return false;
	}

	int x, y; //x-axis, y-axis

	switch(space) {
		case 7:
			x = 0;
			y = 0;
			break;
		case 8:
			x = 1;
			y = 0;
			break;
		case 9:
			x = 2;
			y = 0;
			break;
		case 4:
			x = 0;
			y = 1;
			break;
		case 5:
			x = 1;
			y = 1;
			break;
		case 6:
			x = 2;
			y = 1;
			break;
		case 1:
			x = 0;
			y = 2;
			break;
		case 2:
			x = 1;
			y = 2;
			break;
		case 3:
			x = 2;
			y = 2;
			break;
	}
	
	if((Board::board[x][y] == otherPlayer) || (Board::board[x][y] == player)) //if space is taken...
		return false; //move failed. return false.
	else {
		Board::board[x][y] = player; //otherwise, make move

		return true; //return success
	}
}

char *Board::checkBoard(int part) {
	//0, 1, 2 ==> cols
	//3, 4, 5 ==> rows
	//6, 7 ==> diagonals

	char arr[3];
	char *temp = arr;
	
	int space;
	
	switch(part) {
		//columns
		
		case 0:
		case 1:
		case 2:
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[part][a];
			break;
		//rows
		case 3:
			space = 0;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 4:
			space = 1;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 5:
			space = 2;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		//diagonals
		case 6:
			temp[0] = Board::board[0][2];
			temp[1] = Board::board[1][1];
			temp[2] = Board::board[2][0];
			break;
		case 7:
			temp[0] = Board::board[0][0];
			temp[1] = Board::board[1][1];
			temp[2] = Board::board[2][2];
	}

	return temp;
}
		
bool Board::checkWin() {
	int count = 0;
	bool winner = false;
	
	//checking rows
	for(int x = 0; x < 3; x++) { //for each row
		char *row = checkBoard(x);//get the row
		count = 0;
		for(int a = 0; a < 3; a++) //check each space in row
			if(*(row + a) == player) //if space is taken
				count++; //increase count

		if(count == 3) //if all three taken on row...
			winner = true; //set winner to true;
	}
	
	//checking columns
	
	for(int x = 3; x < 6; x++) { //for each column
		char *col = checkBoard(x);
		count = 0; //starting count again
		for(int a = 0; a < 3; a++)
			if(*(col + a) == player) //if space is taken
				count++; //increase count

		if(count == 3)
			winner = true;
	}
	
	//checking diagonals
	count = 0;
	
	char *dia1 = checkBoard(6);
	for(int x = 0; x < 3; x++) {
		if(*(dia1 + x) == player)
			count++;
	}
	if(count == 3)
		winner = true;

	//second diagonal
	count = 0;
	char *dia2 = checkBoard(7);
	for(int x = 0; x < 3; x++)
		if(*(dia2 + x) == player)
			count++;
	if(count == 3)
		winner = true;

	return winner; //returns false if no wine, true if winner
}

void Board::show() const {
	std::cout << "---------";
	for(int a = 0; a < 3; a++) {
		std::cout << std::endl;
		std::cout << "|";
		for(int b = 0; b < 3; b++)
			std::cout << " " <<  Board::board[b][a];
		std::cout.put(' ');
		std::cout << "|";
	}
	std::cout << "\n---------" << std::endl;
}

Board::~Board() {
}

main.cpp

#include "tic.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
	srand(time(0));
		
	Board b1('x', 'o');
	Board b2('o', 'x');

	bool done = false;

	int move;
	while(!done) {
		b1.reset();
		while(1) {
			cout << "Enter space with numpad: ";
			cin >> move;
			
			if(!b1.makeMove(move)) {
				cout << "bad move" << endl;
				continue;
			}

			b1.show();
			
			if(b1.checkWin()) {
				cout << "x wins!" << endl;
				done = true;
				break;
			}

			move = rand() % 8 + 1;
			while(1) {
				if(!b2.makeMove(move)) {
					continue;
				}
				else
					break;
			}

			if(b2.checkWin()) {
				cout << "o wins!" << endl;
				done = true;
				break;
			}
			
			b1.show();
			
		}
	}	
	cout << "Done!" << endl;
	
	return 0;
}


EDIT:fixed a large bug

EDIT2: I realize that it sometimes lags becuase the random moves keep getting rejected. This problem will disappear once I have written a good AI
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!

Last edited by Jessehk; Dec 9th, 2005 at 11:07 PM.
Jessehk is offline   Reply With Quote
Old Dec 9th, 2005, 11:20 PM   #2
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
new main.cpp

#include "tic.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
	srand(time(0));
		
	Board b1('x', 'o');
	Board b2('o', 'x');

	bool done = false;

	int move;
	while(!done) {
		b1.reset();
		while(1) {
			cout << "Enter space with numpad: ";
			cin >> move;
			
			if(!b1.makeMove(move)) {
				cout << "bad move" << endl;
				continue;
			}

			b1.show();
			
			if(b1.checkWin()) {
				cout << "x wins!" << endl;
				done = true;
				break;
			}

			
			while(1) {
				move = rand() % 9 + 1;
				if(!b2.makeMove(move)) {
					continue;
				}
				else
					break;
			}

			b2.show();

			if(b2.checkWin()) {
				cout << "o wins!" << endl;
				done = true;
				break;
			}
		}
	}	
	cout << "Done!" << endl;
	
	return 0;
}
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!

Last edited by Jessehk; Dec 9th, 2005 at 11:44 PM.
Jessehk is offline   Reply With Quote
Old Dec 12th, 2005, 6:16 AM   #3
UnKnown X
Hobbyist Programmer
 
UnKnown X's Avatar
 
Join Date: Dec 2005
Location: Sandvika, Norway
Posts: 114
Rep Power: 0 UnKnown X is an unknown quantity at this point
Send a message via MSN to UnKnown X
You should try making an expanded tic-tac-toe where the user decides how many rows and columns on which to play. Then you can't make the AI so specific. Makes for a nice challenge.
UnKnown X is offline   Reply With Quote
Old Dec 14th, 2005, 12:00 PM   #4
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
Quote:
Originally Posted by UnKnown X
You should try making an expanded tic-tac-toe where the user decides how many rows and columns on which to play. Then you can't make the AI so specific. Makes for a nice challenge.
thanks, I'll keep that in mind for a challenge

Here is the second rough version.

The computer will now block you from winning.
Next I'd like to add a offensive function with a 50% chance of running (so the computer is still beatable)

anyway, here it is:

tic.h

//tic.h -- TicTacToe declarations

#ifndef TICTACTOE_H_
#define TICTACTOE_H_

class Board
{
	private:
		char *checkBoard(int);
	protected:
		static char board[3][3];
		char player;
		char otherPlayer;
	public:
		Board(char,char);
		void reset();
		virtual bool makeMove(int);
		bool checkWin();
		void show() const;
		virtual ~Board(); 
		bool checkCats() const;
};

class CBoard : public Board
{
	public:
		CBoard(char, char);
		virtual bool makeMove();
	private:
		int *checkDefence();
		void makeRandomMove();
//		int checkOffence();
};

#endif

tic.cpp

//tic.cpp -- implementation of class

#include <iostream>
#include "tic.h"

char Board::board[3][3];

Board::Board(char icon, char otherIcon)
{
	//std::cout << "constructor called" << std::endl;
	player = icon;
	otherPlayer = otherIcon;
}

void Board::reset() 
{
	for(int x = 0; x < 3; x++)
		for(int y = 0; y < 3; y++)
			Board::board[x][y] = ' ';
}


bool Board::makeMove(int space)
{
	//board setup is like that of numpad
	if(space < 1 || space > 9)
	{
		std::cout << "invalid range!" << std::endl;
		
		return false;
	}

	int x, y; //x-axis, y-axis
	x = y = 0;

	switch(space) {
		case 7:
			x = 0;
			y = 0;
			break;
		case 8:
			x = 1;
			y = 0;
			break;
		case 9:
			x = 2;
			y = 0;
			break;
		case 4:
			x = 0;
			y = 1;
			break;
		case 5:
			x = 1;
			y = 1;
			break;
		case 6:
			x = 2;
			y = 1;
			break;
		case 1:
			x = 0;
			y = 2;
			break;
		case 2:
			x = 1;
			y = 2;
			break;
		case 3:
			x = 2;
			y = 2;
			break;
	}
	
	if((Board::board[x][y] == otherPlayer) || (Board::board[x][y] == player)) //if space is taken...
		return false; //move failed. return false.
	else
	{
		Board::board[x][y] = player; //otherwise, make move

		return true; //return success
	}
}

char *Board::checkBoard(int part)
{
	//0, 1, 2 ==> cols
	//3, 4, 5 ==> rows
	//6, 7 ==> diagonals

	char *temp = new char[3];
	
	int space;
	
	switch(part)
	{
		//columns
		
		case 0:
		case 1:
		case 2:
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[part][a];
			break;
		//rows
		case 3:
			space = 0;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 4:
			space = 1;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 5:
			space = 2;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		//diagonals
		case 6:
			temp[0] = Board::board[0][2];
			temp[1] = Board::board[1][1];
			temp[2] = Board::board[2][0];
			break;
		case 7:
			temp[0] = Board::board[0][0];
			//std::cout << "from checkBoard -- diagonal 2 " << Board::board[0][0] << std::endl;
			temp[1] = Board::board[1][1];
			//std::cout << "from checkBoard -- diagonal 2 " << Board::board[1][1] << std::endl;
			temp[2] = Board::board[2][2];
			//std::cout << "from checkBoard -- diagonal 2" << Board::board[2][2] << std::endl;
			break;
	}

	return temp;
}
		
bool Board::checkWin()
{
	int count = 0;
	bool winner = false;
	
	//checking columns
	for(int x = 0; x < 3; x++)
	{ //for each colums
		char *col = checkBoard(x);//get the column
		count = 0;
		for(int a = 0; a < 3; a++) //check each space in column
			if(*(col + a) == player) //if space is taken
				count++; //increase count

		if(count == 3)
		{		//if all three taken on column...
			winner = true; //set winner to true;
			//std::cout << "column winner" << std::endl;
		}
		delete [] col;
	}
	
	
	//checking rows
	
	for(int x = 3; x < 6; x++)
	{ //for each rows
		char *row = checkBoard(x);
		count = 0; //starting count again
		for(int a = 0; a < 3; a++)
			if(*(row + a) == player) //if space is taken
				count++; //increase count

		if(count == 3)
		{
			winner = true;
			//std::cout << "row winner" << std::endl;
		}
		
		delete [] row;
	}
	
	
	//checking diagonals
	count = 0;
	
	char *dia1 = checkBoard(6);
	
	//for(int a = 0; a < 3; a++)
	//	std::cout << "diagonal[" << a << "] = " << dia1[a] << std::endl;
	
	for(int x = 0; x < 3; x++)
	{
		if(*(dia1 + x) == player)
			count++;
	}
	
	if(count == 3)
	{	
		//std::cout << "diagonal 1 winner" << std::endl << std::endl;
		winner = true;
	}

	delete [] dia1;
	
	//second diagonal
	count = 0;
	char *dia2 = checkBoard(7);
	
	//for(int a = 0; a < 3; a++)
	//	std::cout << "diagonal[" << a << "] = " << dia2[a] << std::endl;
	
	for(int x = 0; x < 3; x++)
		if(*(dia2 + x) == player)
			count++;
	if(count == 3)
	{
		//std::cout << "diagonal 2 winner" << std::endl;
		winner = true;
	}
	
	delete [] dia2;

	return winner; //returns false if no win, true if winner
}

void Board::show() const
{
	std::cout << "---------";
	for(int a = 0; a < 3; a++)
	{
		std::cout << std::endl;
		std::cout << "|";
		for(int c = 0; c < 3; c++)
			std::cout << " " <<  Board::board[c][a];
		std::cout.put(' ');
		std::cout << "|";
	}
	std::cout << "\n---------" << std::endl;
}

bool Board::checkCats() const
{
	int taken = 0;
	
	for(int x = 0; x < 3; x++)
		for(int y = 0; y < 3; y++)
			if(Board::board[x][y] != ' ')
				taken++;
	
	/*if(taken == 9)
		std::cout << "return true" << std::endl;
	else
		std::cout << "return false" << std::endl;
	
	return (taken == 9);*/
	return taken == 9;
}

Board::~Board()
{
}

//CBoard method definitions

CBoard::CBoard(char icon, char otherIcon)
	: Board(icon, otherIcon) 
{
	player = icon;
	otherPlayer = otherIcon;
}

int *CBoard::checkDefence()
{
	//look for any spots where the human player will win
	
	//first look for rows
	
	int *spot = new int[3];
	bool found = false;
	int count = 0;
	
	for(int x = 0; x < 3; x++)
	{
		count = 0;
		for(int y = 0; y < 3; y++)
		{
			if(Board::board[x][y] == otherPlayer && Board::board[x][y] != player)
				count++;
			if(count == 2)
			{
				for(int c = 0; c < 3; c++)
				{
					if(Board::board[x][c] != otherPlayer && Board::board[x][c] != player)
					{	
						spot[0] = x;
						spot[1] = c;
						found = true;
					}
				} 

			}
		}
	}
	
	if(found)
		return spot;
	
	//then check for columns
	
	count = 0;
	
	for(int x = 0; x < 3; x++)
	{
		count = 0;
		for(int y = 0; y < 3; y++)
		{
			if(Board::board[y][x] == otherPlayer && Board::board[y][x] != player)
				count++;
			if(count == 2)
			{
				for(int c = 0; c < 3; c++)
				{
					if(Board::board[c][x] != otherPlayer && Board::board[c][x] != player)
					{
						spot[0] = c;
						spot[1] = x;
						found = true;
					}
				}
			}
		}
	}
	
	if(found) 
		return spot;
	
	//check diagonals
	
	count = 0;
	
	//first diagonal: lower left to upper right
	
	
	if(Board::board[0][2] == otherPlayer && Board::board[1][1] == otherPlayer 
		 && Board::board[2][0] != player)
	{
		spot[0] = 2; //2
		spot[1] = 0; //0
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	else if(Board::board[1][1] == otherPlayer && Board::board[2][0] == otherPlayer 
		&& Board::board[0][2] != player)
	{
		spot[0] = 0; //0
		spot[1] = 2; //2
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	else if(Board::board[0][2] == otherPlayer && Board::board[2][0] == otherPlayer
		&& Board::board[1][1] != player)
	{
		spot[0] = 1; //1
		spot[1] = 1; //1
 		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}

	if(found)
		return spot;
	
	
	//second diagonal
	
	if(Board::board[0][0] == otherPlayer && Board::board[1][1] == otherPlayer 
		  && Board::board[2][2] != player)
	{
		spot[0] = 2; //2
		spot[1] = 2; //2
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	else if(Board::board[1][1] == otherPlayer && Board::board[2][2] == otherPlayer 
		 && Board::board[0][0] != player)
	{
		spot[0] = 0; //0
		spot[1] = 0; //0
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	else if(Board::board[0][0] == otherPlayer && Board::board[2][2] == otherPlayer 
		 && Board::board[1][1] != player)
	{
		spot[0] = 1; //1
		spot[1] = 1; //1
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	if(found)
		return spot;
		
	return NULL;
}
	
void CBoard::makeRandomMove()
{
	srand(time(0));
	
	while(1)
	{
		int move = rand() % 9 + 1;
		if(Board::makeMove(move)) //if move is good
			break;
		else
			continue; //otherwise, make another move
	}
}

bool CBoard::makeMove()
{
	int *spot = checkDefence();
	if(spot != NULL)
	{
		//std::cout << "spot[0] = " << spot[0] << std::endl;
		//std::cout << "spot[1] = " << spot[1] << std::endl;
		Board::board[spot[0]][spot[1]] = player;
	}
	
	else
	{
		srand(time(0));
		
		makeRandomMove();
	}
	
	delete [] spot;
	return true;
}

main.cpp

#include "tic.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
	srand(time(0));
		
	Board b1('x', 'o');
	CBoard b2('o', 'x');

	bool done = false;
	
	b2.reset();

	while(!done)
	{
		int move;
		while(1)
		{	
			cout << "Enter move: ";
			cin >> move;
			if(!b1.makeMove(move)) //bad move
				cout << "bad move" << endl;
			else
				break;
		}
		
		//cout << "out of first whiel loop" << endl;
		
		b1.show();
		if(b1.checkWin())
		{
			cout << "x wins!" << endl;
			done = true;
			continue;
		}
		
		if(b1.checkCats())
		{
			cout << "cat's game" << endl;
			done = true;
			continue;
		}
		
		//cout << "b2.makeMove()" << endl;
		b2.makeMove();
		b2.show();
		if(b2.checkWin())
		{
			cout << "o wins!" << endl;
			done = true;
			continue;
		}
		
		if(b2.checkCats())
		{
			cout << "cat's game" << endl;
			done = true;
			continue;
		}
	}
	
	return 0;
	
}
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Old Dec 14th, 2005, 6:59 PM   #5
andro
Professional Programmer
 
Join Date: Oct 2005
Location: California
Posts: 319
Rep Power: 4 andro is on a distinguished road
Send a message via AIM to andro
I have some tic-tac-toe code lying around somewhere that implements minimax, if you're interested in seeing it.

Edit: It's actually a minimax variant called negamax. Really it's the same thing, it just eliminates the need for dual recursive functions and replaces it with one function.
andro is offline   Reply With Quote
Old Dec 15th, 2005, 4:10 PM   #6
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
Quote:
Originally Posted by andro
I have some tic-tac-toe code lying around somewhere that implements minimax, if you're interested in seeing it.

Edit: It's actually a minimax variant called negamax. Really it's the same thing, it just eliminates the need for dual recursive functions and replaces it with one function.
I've actually never heard of minimax. *Google to the rescue...*
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Old Dec 15th, 2005, 5:07 PM   #7
andro
Professional Programmer
 
Join Date: Oct 2005
Location: California
Posts: 319
Rep Power: 4 andro is on a distinguished road
Send a message via AIM to andro
Long story short, you can't win against my tic-tac-toe.
andro is offline   Reply With Quote
Old Dec 15th, 2005, 6:03 PM   #8
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Quote:
Originally Posted by andro
Long story short, you can't win against my tic-tac-toe.
That's easy to do. Computer can't win against me either, that's the problem.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Dec 19th, 2005, 9:49 PM   #9
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
Well, I don't think it's pretty, but it works.
The AI is not supposed to be unbeatable. The human player should win about 50% of the time. I did not use an algorithm to make moves. Instead, the computer will make winning moves, and block you. All other moves are random. I also realise that if you enter in non-numerical input for a move, an endless loop will ensure. This will be fixed shortly.

Thanks for looking

EDIT: I will probably also change the AI so that after offensive, and defensive moves, the computer will attempt to make a move in the corners, and then the center, and then a random move will take place. it's too easy to beat the computer when it makes stupid moves.
Attached Files
File Type: zip tictactoe.zip (4.6 KB, 8 views)
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 9:24 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC