Tron.cpp
/* File: Tron.cpp
Corporation: ENCOM
Author: Ryan Pickelsimer and Kevin Flynn
Created on: August 15, 2014
Class: Programming II, Section 1
Purpose: This file is part of a program designed to breach high security clearance protocols in the
ENCOM mainframe and gain access to the Tron security protocol. In order to destroy the MCP, you must
defeat a computer program in the Lightcycle trial. Controls are up(8), down(2), left(4), right(6)
on the num pad, or the lowercase letters i, j, l, m. With each player win the speed of the game increases
and with each computer win the game speed will slow down.
*/
// Headers
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <string>
#include <windows.h>
#include <cstdlib>
#include <ctime>
using namespace std;
const static enum Direction { N, S, E, W };
class Board;
class Cycle;
////////////////////////////////////////////////////////
///// Board Class /////
////////////////////////////////////////////////////////
class Board {
const static int COLUMNS = 79, ROWS = 37;
char board[ROWS][COLUMNS];
public:
void gotoXY(int, int);
void drawBoard();
void welcomeScreen();
void clear();
void setBoard(int, int, char);
char getBoardPos(int row, int column) { return board[row][column]; }
};
///////////////////////////////////////////
///// Board Functions /////
///////////////////////////////////////////
// Moves cursor to a location that corresponds to board array
void Board::gotoXY(int row, int column)
{
COORD coord;
coord.X = column;
coord.Y = row;
SetConsoleCursorPosition(
GetStdHandle(STD_OUTPUT_HANDLE),
coord
);
}
// Creates and displays game board.
void Board::drawBoard(){
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLUMNS; j++){
if ((i == 0) || (j == 0) || (i == ROWS - 1 ) || (j == COLUMNS - 1)){
board[i][j] = '#';
gotoXY(i, j);
cout << board[i][j];
}
else { board[i][j] = ' '; }
}
}
}
// Displays pre game information. *** add direction keys
void Board::welcomeScreen(){
gotoXY(5, 37);
cout << "TRON";
gotoXY(7, 18);
cout << "Use directional keys on Numpad or I,J,L,M";
gotoXY(16, 23);
cout << "Player";
gotoXY(16, 50);
cout << "Comp";
gotoXY(24, 27);
cout << "Press Any Key When Ready";
}
// Clear console.
void Board::clear() {
COORD topLeft = { 0, 0 };
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO screen;
DWORD written;
GetConsoleScreenBufferInfo(console, &screen);
FillConsoleOutputCharacterA(
console, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written
);
FillConsoleOutputAttribute(
console, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
screen.dwSize.X * screen.dwSize.Y, topLeft, &written
);
SetConsoleCursorPosition(console, topLeft);
}
// Modify the game board externally.
void Board::setBoard(int row, int column, char c){
board[row][column] = c;
gotoXY(row, column);
cout << board[row][column];
}
////////////////////////////////////////////////////////
///// Cycle Class /////
////////////////////////////////////////////////////////
class Cycle {
const static int DIFFICULTY_1 = 10; // indicates 100% chance of reacting to situation.
const static int DIFFICULTY_2 = 8; // indicates 80% chance of reacting to situation.
const static int DIFFICULTY_3 = 4; // indicates 40% chance of reacting to situation.
const static int DIFFICULTY_4 = 2; // indicates 20% chance of reacting to situation.
Direction direction;
int row;
int column;
char bike;
const char horizTrail = '-';
const char vertTrail = '|';
bool automatic;
bool alive;
public:
Cycle();
Cycle(bool);
char markTrail();
void moveCycle();
void changeDirection(char);
void showCycle(Board);
bool collisionTest(Board);
bool testAlive();
int getRow() { return row; }
int getColumn() { return column; }
void testForMove(Board);
};
////////////////////////////////////////
///// Cycle Functions /////
////////////////////////////////////////
// Default human player constructor.
Cycle::Cycle(){
direction = E;
bike = '*';
row = 18;
column = 26;
automatic = false;
alive = true;
}
// Computer simulated player constructor.
Cycle::Cycle(bool aut){
direction = W;
bike = '+';
row = 18;
column = 52;
automatic = aut;
alive = true;
}
// Takes keyboard key value and returns corresponding Direction.
void Cycle::changeDirection(char keyPressed) {
if (keyPressed == '8' || keyPressed == 'i')
direction = N;
if (keyPressed == '4' || keyPressed == 'j')
direction = W;
if (keyPressed == '6' || keyPressed == 'l')
direction = E;
if (keyPressed == '2' || keyPressed == 'm')
direction = S;
}
// Displays Cycle bike skin at current position.
void Cycle::showCycle(Board b){
b.gotoXY(row, column);
cout << bike;
}
// Marks Cycle trail.
char Cycle::markTrail(){
char c;
if (direction == N)
c = vertTrail;
if (direction == S)
c = vertTrail;
if (direction == W)
c = horizTrail;
if (direction == E)
c = horizTrail;
return c;
}
// Updates position.
void Cycle::moveCycle(){
if (direction == N)
row = row - 1;
if (direction == S)
row = row + 1;
if (direction == W)
column = column - 1;
if (direction == E)
column = column + 1;
}
// Tests for vehicle crash. *Returns false to create infinite loop and stop MCP forever.
bool Cycle::collisionTest(Board b) {
if (b.getBoardPos(row, column) != ' '){
alive = false;
return true;
}
return false;
}
// Tests whether Cycle survived race.
bool Cycle::testAlive(){
if (alive == false)
return false;
else
return true;
}
void Cycle::testForMove(Board b) {
srand(static_cast<unsigned int>(time(0)));
int ran = rand() % 10;
int r = row;
int c = column;
/// Locate cell in front of Cycle.
if (direction == N)
r = row - 1;
if (direction == S)
r = row + 1;
if (direction == W)
c = column - 1;
if (direction == E)
c = column + 1;
/// Cycle has chance to turn before crash. May turn any direction but current.
if (b.getBoardPos(r, c) != ' ') {
if (ran < DIFFICULTY_1) {
do {
ran = rand() % 4;
} while (direction == (Direction)ran);
direction = (Direction)ran;
}
}
/// Cycle may make ninety degree turn. Chance of turn increases in zones near border.
/// Zone 1
else if (((row == 2 || row == 3) && direction == N) || ((row == 33 || row == 34) && direction == S)){
if (ran < DIFFICULTY_2) {
ran = ran % 2;
if (ran == 0)
direction = E;
else
direction = W;
}
}
else if (((column == 2 || column == 3) && direction == W) || ((column == 75 || column == 76) && direction == E)){
if (ran < DIFFICULTY_2) {
ran = ran % 2;
if (ran == 0)
direction = N;
else
direction = S;
}
}
/// Zone 2
else if (((row >= 4 && row <= 6) && direction == N) || ((row >= 30 && row <= 32) && direction == S)){
if (ran < DIFFICULTY_3) {
ran = ran % 2;
if (ran == 0)
direction = E;
else
direction = W;
}
}
else if (((column >= 4 && column <= 6) && direction == W) || ((column >= 72 && column <= 74) && direction == E)){
if (ran < DIFFICULTY_3) {
ran = ran % 2;
if (ran == 0)
direction = N;
else
direction = S;
}
}
/// Zone 3
else if (ran < DIFFICULTY_4){
ran = ran % 2;
if (direction == N || direction == S) {
if (ran == 0)
direction = E;
else
direction = W;
}
else if (direction == E || direction == W) {
if (ran == 0)
direction = N;
else
direction = S;
}
}
}
///////////////////////////////////////////
///// Main Program /////
///////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[]){
// resize console window
HWND console = GetConsoleWindow();
RECT r;
GetWindowRect(console, &r); //stores the console's current dimensions
MoveWindow(console, r.left, r.top, 800, 500, TRUE); // 800 width, 500 height
//////////////////////
// Main Game Loop //
//////////////////////
const int GAME_SPEED = 100;
const int LEVEL_UP_SCORE = 1000;
const int SCORE_MULTIPLIER = 10;
int clockMultiplier = 0, playerPoints = 0, points = 0;
bool replay = false;
int keyPressed;
bool gameOver = false;
do {
//setup game board
Board b;
Cycle player;
Cycle comp(true);
b.clear();
b.drawBoard();
player.showCycle(b);
comp.showCycle(b);
b.welcomeScreen();
//wait for player to begin
bool ready = false;
while (!ready){
if (_kbhit()){
ready = true;
}
}
///////////////////////
// Inner Game Loop //
///////////////////////
b.clear();
b.drawBoard();
player.showCycle(b);
comp.showCycle(b);
while (!gameOver) {
Sleep(GAME_SPEED - clockMultiplier);
//test for player input
if (_kbhit()){
keyPressed = _getch();
// key is only assigned a valid value.
try {
player.changeDirection(keyPressed);
}
catch (const char* msg){
cerr << msg << endl;
}
}
//player move
char p = player.markTrail();
int row = player.getRow();
int col = player.getColumn();
b.setBoard(row, col, p);
player.moveCycle();
gameOver = player.collisionTest(b);
player.showCycle(b);
//computer move
if (gameOver == false){
comp.testForMove(b);
char c = comp.markTrail();
row = comp.getRow();
col = comp.getColumn();
b.setBoard(row, col, c);
comp.moveCycle();
gameOver = comp.collisionTest(b);
comp.showCycle(b);
}
} //end inner game loop
if (player.testAlive() == false) {
b.gotoXY(18, 34);
cout << "Game Over!";
clockMultiplier -= 10;
}
else {
b.gotoXY(18, 36);
cout << "You Win!";
points = LEVEL_UP_SCORE + (clockMultiplier * SCORE_MULTIPLIER);
playerPoints += points;
clockMultiplier += 10;
}
b.gotoXY(22, 27);
cout << "Your score this round: " << points;
b.gotoXY(24, 30);
cout << "Your total score: " << playerPoints;
b.gotoXY(28, 20);
cout << "Would you like to play again? (y,n) ";
char n;
cin >> n;
if (n == 'y' || n == 'Y'){
replay = true;
gameOver = false;
}
} while (replay == true);
//end main game loop
return 0;
}