소스 검색

Initial commit

master
Riyyi 3 년 전
커밋
68197111c4
  1. 1
      .gitignore
  2. 74
      board.cpp
  3. 28
      board.h
  4. 84
      boardwindow.cpp
  5. 26
      boardwindow.h
  6. 75
      gamestate.h
  7. 47
      infowindow.cpp
  8. 25
      infowindow.h
  9. 69
      inputoutput.cpp
  10. 29
      inputoutput.h
  11. 56
      main.cpp
  12. 338
      maingame.cpp
  13. 49
      maingame.h
  14. 98
      mainmenu.cpp
  15. 25
      mainmenu.h
  16. 54
      makefile
  17. 57
      messagebox.cpp
  18. 17
      messagebox.h
  19. 53
      player.cpp
  20. 31
      player.h
  21. 88
      selectionbox.cpp
  22. 26
      selectionbox.h
  23. 57
      spaceship.cpp
  24. 36
      spaceship.h
  25. 68
      test.cpp
  26. 12
      test.h
  27. 222
      window.cpp
  28. 75
      window.h

1
.gitignore vendored

@ -0,0 +1 @@
space-walk

74
board.cpp

@ -0,0 +1,74 @@
#include <algorithm>
#include "board.h"
#include "spaceship.h"
Board::Board() {
// Reserve 0 SpaceShips of memory for each planet
for (unsigned char i = 0; i < BOARD_SIZE; i++) {
this->planets[i] = new std::vector<SpaceShip *>(0);
}
}
Board::~Board() {
for (auto planet : this->planets) {
delete planet;
}
}
SpaceShip *Board::getShip(unsigned char planet, unsigned char pos) {
if (planet >= BOARD_SIZE || pos >= this->planets[planet]->size()) {
return new SpaceShip;
}
return this->planets[planet]->at(pos);
}
std::vector<SpaceShip *> *Board::getShips(unsigned char planet) {
if (planet >= BOARD_SIZE) {
return nullptr;
}
return this->planets[planet];
}
bool Board::setShip(unsigned char planet, SpaceShip *ship) {
if (planet >= BOARD_SIZE) {
return false;
}
// Insert if the ship doesn't already exist on a planet
if (ship->getPlanet() == PLANET_UNSET) {
ship->setPlanet(planet);
this->planets[planet]->push_back(ship);
this->sortPlanet(planet);
}
return true;
}
bool Board::moveShip(unsigned char planet, SpaceShip *ship) {
char shipPlanet = ship->getPlanet();
if (planet >= BOARD_SIZE || shipPlanet == -1 || shipPlanet == planet) {
return false;
}
auto tmp = this->planets[(unsigned char)shipPlanet];
// Move ship to the end of the vector and then erase the last element
// (Erase-remove idiom)
tmp->erase(std::remove(tmp->begin(), tmp->end(), ship), tmp->end());
ship->setPlanet(planet);
this->planets[planet]->push_back(ship);
this->sortPlanet(planet);
return true;
}
void Board::sortPlanet(unsigned char planet) {
// Sort all ships on the planet, using function/functor/lambda
std::sort(this->planets[planet]->begin(), this->planets[planet]->end(),
[](SpaceShip *s1, SpaceShip *s2) -> bool {
return s1->getSize() > s2->getSize();
});
}

28
board.h

@ -0,0 +1,28 @@
#ifndef BOARD_H
#define BOARD_H
#define BOARD_SIZE 14
#include <vector>
class SpaceShip;
class Board
{
public:
Board();
~Board();
SpaceShip *getShip(unsigned char planet, unsigned char pos);
std::vector<SpaceShip *> *getShips(unsigned char planet);
bool setShip(unsigned char planet, SpaceShip *ship);
bool moveShip(unsigned char planet, SpaceShip *ship);
void sortPlanet(unsigned char planet);
private:
// Data layout:
// Black hole, 6 planets, 6 planets, black hole
std::vector<SpaceShip *> *planets[BOARD_SIZE];
};
#endif // BOARD_H

84
boardwindow.cpp

@ -0,0 +1,84 @@
#include "board.h"
#include "boardwindow.h"
#include "maingame.h"
#include "spaceship.h"
BoardWindow::BoardWindow(int height, int width, Board *board) :
height(height),
width(width),
board(board) {
}
BoardWindow::~BoardWindow() {
}
void BoardWindow::update() {
Window::update();
this->resize();
int twoThirds = (this->getRows() / 3) * 2;
int halfCols = this->getCols() / 2;
int y = (twoThirds / 2) - 12;
int x = halfCols - 4 - 1;
// Print black hole
this->printBlackHole(y, x, 0);
y += 6;
x = (this->getCols() / 2) - (46 / 2) - 1;
// Print all planets
for (int i = 1; i < BOARD_SIZE - 1; i++) {
this->printPlanet(y, x, i);
x += 8;
if (i == (BOARD_SIZE - 2) / 2) {
x = (this->getCols() / 2) - (46 / 2) - 1;
y += 6;
}
}
y += 6;
x = halfCols - 4 - 1;
// Print black hole
this->printBlackHole(y, x, BOARD_SIZE - 1);
}
void BoardWindow::resize() {
int rows = this->getMaxRows() - this->height;
int cols = this->getMaxCols() - this->width;
this->setWindow(rows, cols, 0, 0);
Window::resize();
}
void BoardWindow::printBlackHole(int y, int x, int planet) {
this->print("+------+", y, x);
this->print("| |", y + 1, x);
this->print("| |", y + 2, x);
this->print("| |", y + 3, x);
this->print("+------+", y + 4, x);
this->printSpaceShip(y + 1, x + 1, planet, 6);
}
void BoardWindow::printPlanet(int y, int x, int planet) {
this->print("+----+", y, x);
this->print("| |", y + 1, x);
this->print("| |", y + 2, x);
this->print("| |", y + 3, x);
this->print("+----+", y + 4, x);
this->printSpaceShip(y + 1, x + 1, planet, 4);
}
void BoardWindow::printSpaceShip(int y, int x, int planet, int width) {
auto tmp = this->board->getShips(planet);
int size = (int)tmp->size() + 1;
for (int i = 1; i < size; i++) {
tmp->at(i - 1)->render(this, y, x, false);
x++;
if (i != 1 && i % width == 0) {
y++;
x -= width;
}
}
}

26
boardwindow.h

@ -0,0 +1,26 @@
#ifndef BOARDWINDOW_H
#define BOARDWINDOW_H
#include "window.h"
class Board;
class BoardWindow : public Window
{
public:
BoardWindow(int height, int width, Board *board);
~BoardWindow();
void update();
void resize();
void printBlackHole(int y, int x, int planet);
void printPlanet(int y, int x, int planet);
void printSpaceShip(int y, int x, int planet, int width);
private:
int height;
int width;
Board *board;
};
#endif // BOARDWINDOW_H

75
gamestate.h

@ -0,0 +1,75 @@
#ifndef GAMESTATE
#define GAMESTATE
#include <chrono> // time
#include <thread> // sleep_for
#include "inputoutput.h"
#include "window.h"
class GameState
{
public:
// Makes sure that the inherited class's destructor is called
virtual ~GameState() {}
virtual void initialize() {}
virtual void update() {}
virtual void render() {}
virtual void destroy() {}
static void sleep(int amount) {
// Sleep for amount ms
std::this_thread::sleep_for(std::chrono::milliseconds(amount));
}
};
class GameStateManager
{
public:
GameStateManager() : state(nullptr) {
Window::initialize();
}
~GameStateManager() {
if(this->state != nullptr) {
this->state->destroy();
delete this->state;
}
Window::destroy();
}
void setState(GameState* state) {
if(this->state != nullptr) {
this->state->destroy();
delete this->state;
}
this->state = state;
if(this->state != nullptr) {
this->state->initialize();
}
}
void update() {
GameState::sleep(15);
if(this->state != nullptr) {
this->state->update();
}
}
void render() {
if(this->state != nullptr) {
this->state->render();
}
}
private:
GameState *state;
};
extern GameStateManager gameStateManager;
#endif // GAMESTATE

47
infowindow.cpp

@ -0,0 +1,47 @@
#include "infowindow.h"
#include "maingame.h"
#include "player.h"
#include "spaceship.h"
InfoWindow::InfoWindow(int height, int width, Player **player, SpaceShip **ship) :
height(height),
width(width),
player(player),
ship(ship) {
}
InfoWindow::~InfoWindow() {
}
void InfoWindow::update() {
Window::update();
this->resize();
int y = 0;
int x = 1;
for (unsigned char i = 0; i < PLAYER_SIZE; i++) {
this->player[i]->render(this, y, x, i + 1);
y += 6;
int shipIdx = i * SHIP_SIZE / 2;
for (unsigned char j = shipIdx; j < shipIdx + SHIP_SIZE / 2; j++) {
this->ship[j]->render(this, y, x);
x++;
if (x > 3) {
y++;
x = 1;
}
}
y += 2;
}
}
void InfoWindow::resize() {
int rows = this->getMaxRows() - this->height;
int x = this->getMaxCols() - this->width;
int cols = this->getMaxCols() - x;
this->setWindow(rows, cols, 0, x);
Window::resize();
}

25
infowindow.h

@ -0,0 +1,25 @@
#ifndef INFOWINDOW_H
#define INFOWINDOW_H
#include "window.h"
class Player;
class SpaceShip;
class InfoWindow : public Window
{
public:
InfoWindow(int height, int width, Player **player, SpaceShip **ship);
~InfoWindow();
void update();
void resize();
private:
int height;
int width;
Player **player;
SpaceShip **ship;
};
#endif // INFOWINDOW_H

69
inputoutput.cpp

@ -0,0 +1,69 @@
#include <cstdio> // size_t
#include <ncurses.h>
#include "inputoutput.h"
void IO::initialize() {
}
void IO::update() {
IO::keyCode = getch();
if (keyCode == KEY_ESC) {
IO::setQuit();
return;
}
}
std::string IO::trim(std::string str) {
size_t first = str.find_first_not_of(" ");
if (first == std::string::npos) {
return "";
}
size_t last = str.find_last_not_of(" ");
return str.substr(first, (last - first + 1));
}
std::string IO::untrim(std::string str, unsigned int length) {
unsigned int strLength = str.length();
if (length > strLength) {
int halfDiff = (length - strLength) / 2;
std::string tmpStr;
for (int i = 0; i < halfDiff; i++) {
tmpStr += " ";
}
str.insert(0, tmpStr);
str.append(tmpStr);
}
return str;
}
int IO::getKeyCode() {
return IO::keyCode;
}
std::string IO::getKeyName() {
return std::string(keyname(IO::keyCode));
}
std::string IO::getStrInput() {
echo();
char *tmp = new char();
getstr(tmp);
noecho();
return std::string(tmp);
}
bool IO::getQuit() {
return IO::quit;
}
void IO::setQuit() {
IO::quit = true;
}
int IO::keyCode = ERR;
bool IO::quit = false;

29
inputoutput.h

@ -0,0 +1,29 @@
#ifndef INPUTOUTPUT_H
#define INPUTOUTPUT_H
#define KEY_ESC 27
#define KEY_SPACE 32
#include <string>
class IO
{
public:
static void initialize();
static void update();
static std::string trim(std::string str);
static std::string untrim(std::string str, unsigned int length);
static int getKeyCode();
static std::string getKeyName();
static std::string getStrInput();
static bool getQuit();
static void setQuit();
private:
static int keyCode;
static bool quit;
};
#endif // INPUTOUTPUT_H

56
main.cpp

@ -0,0 +1,56 @@
/*
* Rick van Vonderen
* 0945444
* TI2B
*
* Avoid repeated writing by using:
* - functions with parameters (no globals) instead of almost identical pieces of code
* - repetitive loops and arrays instead of identical activities
* - constants instead of identical values
*
* Divide your program into modules and/or classes that:
* - have an explicit, well-defined interface
* - be as independent as possible
* - to be developed and tested separately
*
* Make your code understandable for others by using:
* - Clear names in camel case, only start class names with a capital letter, consistently indent
* - Clear, concise commentary, only where this adds something
* - Standard terminology from the customer's field or application
*
* ClassExample
* variableExample
* DEFINE_EXAMPLE
*/
#include <cstring> // strcmp()
#include <ncurses.h> // refresh()
#include "gamestate.h"
#include "inputoutput.h"
#include "mainmenu.h"
#include "test.h"
GameStateManager gameStateManager;
int main(int argc, char *argv[]) {
#ifdef DEBUG
// IO::print("DEBUG MODE ENABLED");
refresh();
GameState::sleep(1000);
if (argc >= 2 && strcmp(argv[1], "-t") == 0) {
Test();
}
#endif
gameStateManager.setState(new MainMenu());
while (!IO::getQuit()) {
gameStateManager.render();
gameStateManager.update();
}
return 0;
}

338
maingame.cpp

@ -0,0 +1,338 @@
#include <algorithm>
#include "board.h"
#include "boardwindow.h"
#include "inputoutput.h"
#include "maingame.h"
#include "mainmenu.h"
#include "messagebox.h"
#include "player.h"
#include "selectionbox.h"
#include "spaceship.h"
#include "window.h"
#include "infowindow.h"
MainGame::MainGame(Player **player) :
help("Phase 1!\n\nThe players take turns, placing a spaceship on a planet\nof their choice."),
phase(false),
playerTurn(0),
queuePlanet(-1),
player(player),
board(nullptr),
ship(nullptr),
boardWindow(nullptr),
infoWindow(nullptr) {
// Reserve 0 spaceships of memory for the queue
this->queue = new std::vector<SpaceShip *>(0);
}
void MainGame::initialize() {
this->board = new Board();
this->ship = new SpaceShip*[SHIP_SIZE] { nullptr };
unsigned char cCounter = 0;
unsigned char colors[PLAYER_SIZE] = { PAIR_RED_BLACK, PAIR_BLUE_BLACK };
unsigned char sCounter = 0;
unsigned char sizes[3] = { SpaceShip::SMALL, SpaceShip::MEDIUM, SpaceShip::BIG };
// Create 9 ships for each player, 3 of each size
for (unsigned char i = 0; i < SHIP_SIZE; i++) {
if (i != 0 && i % (SHIP_SIZE / PLAYER_SIZE) == 0) {
cCounter++;
}
if (i != 0 && i % 3 == 0) {
sCounter++;
}
if (sCounter >= 3) {
sCounter = 0;
}
this->ship[i] = new SpaceShip(colors[cCounter], sizes[sCounter]);
}
this->boardWindow = new BoardWindow(0, 16, this->board);
this->infoWindow = new InfoWindow(0, 16, this->player, this->ship);
// Display help message
MainGame::render();
MessageBox(this->help);
}
void MainGame::update() {
MainGame::sleep(250);
// Display new help message on phase change
if (this->changePhase) {
this->phase = true;
this->changePhase = false;
this->help = "Phase 2!\n\nThe players take turns, evacuating a planet of their choice.";
MessageBox(this->help);
return;
}
if (!this->phase) {
this->phase1();
}
else {
this->phase2();
}
}
void MainGame::render() {
this->boardWindow->clear();
this->infoWindow->clear();
this->boardWindow->update();
this->infoWindow->update();
this->boardWindow->render();
this->infoWindow->render();
}
void MainGame::destroy() {
delete this->board;
delete this->boardWindow;
delete this->infoWindow;
for (int i = 0; i < SHIP_SIZE; i++) {
delete this->ship[i];
}
delete []this->ship;
for (int i = 0; i < PLAYER_SIZE; i++) {
delete this->player[i];
}
delete []this->player;
}
void MainGame::phase1() {
std::string playerTurnStr = std::to_string(this->playerTurn + 1);
SelectionBox s = SelectionBox(0, 16);
// Ask the current player to pick a Spaceship size
std::string sizeStr = "Player " + playerTurnStr + ", pick a spaceship size.";
std::string sizeOptions[] = {"S", "M", "B", "\0"};
unsigned char sizeSelection = s.select(sizeStr, &sizeOptions[0]);
// Ask the current player to pick a planet
std::string planetStr = "Player " + playerTurnStr + ", pick a planet to put this spaceship on.";
std::string planetOptions[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "\0"};
unsigned char planetSelection = s.select(planetStr, &planetOptions[0]);
// Calculate array index
int startLoop = SHIP_SIZE / PLAYER_SIZE * this->playerTurn + (sizeSelection * 3);
// Get ships of player selected planet
auto ships = this->board->getShips(std::stoi(planetOptions[planetSelection]));
bool placedShip = false;
bool shouldExit;
// Check all 3 ships of the size the player selected
for (int i = startLoop; i < startLoop + 3; i++) {
shouldExit = false;
// Check if spaceship is already on a planet
if (this->ship[i]->getPlanet() != PLANET_UNSET) {
continue;
}
// If planet already holds spaceship of equal size
for(auto ship : *ships) {
if (this->ship[i]->getSize() == ship->getSize()) {
shouldExit = true;
break;
}
}
if (shouldExit) {
MessageBox("You cant place spaceships of the same size on a planet during this phase!", "Error");
break;
}
// Add spaceship to planet
this->board->setShip(std::stoi(planetOptions[planetSelection]), this->ship[i]);
this->nextPlayerTurn();
placedShip = true;
break;
}
if (!placedShip && !shouldExit) {
MessageBox("Please select a size of which you still have unplaced spaceships!", "Error");
}
// Check if all ships have been placed
bool allPlaced = true;
for (int i = 0; i < SHIP_SIZE; i++) {
if (this->ship[i]->getPlanet() == PLANET_UNSET) {
allPlaced = false;
break;
}
}
if (allPlaced) {
this->changePhase = true;
}
}
void MainGame::phase2() {
std::string playerTurnStr = std::to_string(this->playerTurn + 1);
SelectionBox s = SelectionBox(0, 16);
// Move next spaceship in the queue
if (this->queue->size() > 0) {
// Determine the middle of the board
unsigned char halfBoard = (BOARD_SIZE - 2) / 2; // 6
// Planet rotation order, where |x| is a black hole
// 1 ... 6 -> |13| -> 12 ... 7 -> |0| -> 1
// 0 .. 5
if (this->queuePlanet < halfBoard) {
this->queuePlanet++;
}
// 8 .. 13
else if (this->queuePlanet > halfBoard + 1) {
this->queuePlanet--;
}
// 6
else if (this->queuePlanet == halfBoard) {
this->queuePlanet = BOARD_SIZE - 1;
}
// 7
else if (this->queuePlanet == halfBoard + 1) {
this->queuePlanet = 0;
}
unsigned char shipSelection = 0;
// If the the current and next ship are of the same size, ask which goes first
if (this->queue->size() > 1) {
SpaceShip *tmpShip = this->queue->at(0);
SpaceShip *tmpShip2 = this->queue->at(1);
if (tmpShip->getSize() == tmpShip2->getSize() &&
tmpShip->getColor() != tmpShip2->getColor()) {
std::string shipStr = "Player " + playerTurnStr + ", pick the next ship that will evacuate.";
std::string shipOptions[] = {"Yours", "Theirs", "\0"};
shipSelection = s.select(shipStr, &shipOptions[0]);
}
}
board->moveShip(this->queuePlanet, this->queue->at(shipSelection));
return;
}
else if (this->queuePlanet != -1) {
this->queuePlanet = -1;
this->nextPlayerTurn();
this->calculateWinner();
return;
}
// Ask the current player if they want to skip their turn
unsigned char playerChip = this->player[this->playerTurn]->getChip();
if (playerChip > 0) {
std::string skipStr = "Player " + playerTurnStr + ", do you want to skip your turn for 1 chip?";
std::string skipOptions[] = {"No", "Yes", "\0"};
unsigned char skipSelection = s.select(skipStr, &skipOptions[0]);
if (skipOptions[skipSelection] == "Yes") {
this->player[this->playerTurn]->setChip(playerChip - 1);
this->nextPlayerTurn();
return;
}
}
// Ask the current player to pick a planet
std::string planetStr = "Player " + playerTurnStr + ", pick a planet to evacuate.";
std::string planetOptions[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "\0"};
unsigned char planetSelection = s.select(planetStr, &planetOptions[0]);
// Get ships of player selected planet
auto ships = this->board->getShips(std::stoi(planetOptions[planetSelection]));
// Check if the selected planet holds a spaceship of the current player,
// using function/functor/lambda
unsigned char playerColor = this->player[(int)this->playerTurn]->getColor();
auto findShip = std::find_if(ships->begin(), ships->end(),
[playerColor](SpaceShip *ship) {return ship->getColor() == playerColor; });
// If so, add this planet to the queue
if (findShip != ships->end()) {
this->queue = ships;
this->queuePlanet = this->queue->at(0)->getPlanet();
}
else {
MessageBox("Please select a planet that holds a ship of your own!", "Error");
}
}
void MainGame::nextPlayerTurn() {
this->playerTurn++;
if (this->playerTurn > PLAYER_SIZE - 1) {
this->playerTurn = 0;
}
}
void MainGame::calculateWinner() {
// Get all ships from the black holes
auto blackHole1 = this->board->getShips(0);
auto blackHole2 = this->board->getShips(BOARD_SIZE - 1);
int totalScore = CHIP_AMOUNT * CHIP_SCORE +
3 * SpaceShip::BIG +
3 * SpaceShip::MEDIUM +
3 * SpaceShip::SMALL;
// Fill players possible total score
int score[PLAYER_SIZE];
std::fill_n(score, PLAYER_SIZE, totalScore);
// Calculate players score
int crashedShips;
bool gameOver = false;
for (int i = 0; i < PLAYER_SIZE; i++) {
// Subtract all used chips from the total score
score[i] -= (CHIP_AMOUNT - this->player[i]->getChip()) * CHIP_SCORE;
crashedShips = 0;
for (auto ship : *blackHole1) {
if (this->player[i]->getColor() == ship->getColor()) {
crashedShips++;
// Subtract crashed ship from the total score
score[i] -= ship->getSize();
}
}
for (auto ship : *blackHole2) {
if (this->player[i]->getColor() == ship->getColor()) {
crashedShips++;
// Subtract crashed ship from the total score
score[i] -= ship->getSize();
}
}
// If a player has run out of ships..
if (crashedShips == SHIP_SIZE / PLAYER_SIZE) {
gameOver = true;
}
}
// Print victory screen
if (gameOver) {
std::string printStr;
int winnerIdx = 0;
for (int i = 0; i < PLAYER_SIZE; i++) {
printStr += "Player " + std::to_string(i + 1) + ": scored " +
std::to_string(score[i]) + " points.\n";
if (i < PLAYER_SIZE - 1 && score[i] < score[i + 1]) {
winnerIdx = i + 1;
}
}
printStr.insert(0, this->player[winnerIdx]->getName() + " has won!\n\n");
MessageBox(printStr, "Victory");
gameStateManager.setState(new MainMenu());
}
}

49
maingame.h

@ -0,0 +1,49 @@
#ifndef MAINGAME_H
#define MAINGAME_H
// Each player holds 9 ships, 3 of each size
#define SHIP_SIZE 18
#define PLAYER_SIZE 2
#include <vector>
#include "gamestate.h"
class Board;
class BoardWindow;
class InfoWindow;
class Player;
class SpaceShip;
class MainGame : public GameState
{
public:
MainGame(Player **player);
void initialize();
void update();
void render();
void destroy();
private:
void phase1();
void phase2();
void nextPlayerTurn();
void calculateWinner();
std::string help;
bool phase;
bool changePhase;
unsigned char playerTurn;
char queuePlanet;
std::vector<SpaceShip *> *queue;
Player **player;
Board *board;
SpaceShip **ship;
BoardWindow *boardWindow;
InfoWindow *infoWindow;
};
#endif // MAINGAME_H

98
mainmenu.cpp

@ -0,0 +1,98 @@
#include "inputoutput.h"
#include "maingame.h"
#include "mainmenu.h"
#include "player.h"
#include "window.h"
void MainMenu::initialize() {
int rows;
int cols;
Window::getMaXYZ(stdscr, rows, cols);
this->window = new Window(rows, cols, 0, 0);
this->titleScreen = true;
this->player = new Player*[PLAYER_SIZE] { nullptr };
}
void MainMenu::update() {
if (this->titleScreen) {
IO::update();
if (IO::getKeyName() == " ") {
this->titleScreen = false;
}
}
else {
int y;
int x;
std::string tmpStr;
unsigned char colors[PLAYER_SIZE] = { PAIR_RED_BLACK, PAIR_BLUE_BLACK };
for (int i = 0; i < PLAYER_SIZE; i++) {
if (this->player[i] == nullptr) {
this->window->getYX(y, x);
tmpStr = "";
while (tmpStr == "") {
tmpStr = IO::trim(this->window->getStr());
this->window->setYX(y, x);
}
this->player[i] = new Player();
this->player[i]->setName(tmpStr);
this->player[i]->setColor(colors[i]);
break;
}
if (i == PLAYER_SIZE - 1) {
gameStateManager.setState(new MainGame(this->player));
}
}
}
}
void MainMenu::render() {
this->window->clear();
this->window->update();
this->window->setWindow(this->window->getMaxRows(), this->window->getMaxCols(), 0, 0);
this->window->resize();
if (this->titleScreen) {
this->window->printSide("", "Rick van Vonderen");
this->window->setYX(1, 0);
this->window->printSide("", "0945444");
this->window->setYX(2, 0);
this->window->printSide("", "TI2B");
this->window->setYX(this->window->getRows() / 2 - 1, 0);
this->window->printCenter("--- Space Walk ---");
this->window->setYX(this->window->getRows() - 4, 0);
this->window->printCenter("Press <Space> to walk..");
}
else {
int x = this->window->getCols() / 2 - 11 ;
int y = this->window->getRows() / 2;
std::string tmp;
for (int i = 0; i < PLAYER_SIZE; i++) {
tmp = std::string("Enter Player ") + std::to_string(i + 1) + std::string(" name: ");
if (this->player[i] != nullptr) {
tmp += this->player[i]->getName();
}
this->window->print(tmp, y, x);
y++;
if (this->player[i] == nullptr) {
break;
}
}
}
this->window->render();
}
void MainMenu::destroy() {
delete this->window;
}

25
mainmenu.h

@ -0,0 +1,25 @@
#ifndef MAINMENU_H
#define MAINMENU_H
#include <memory>
#include "gamestate.h"
class Player;
class Window;
class MainMenu : public GameState
{
public:
void initialize();
void update();
void render();
void destroy();
private:
bool titleScreen;
Window *window;
Player **player;
};
#endif // MAINMENU_H

54
makefile

@ -0,0 +1,54 @@
#------------------------------------------------------------------------------#
PROGRAM := "space-walk"
HEADERS := \
board.h \
boardwindow.h \
gamestate.h \
infowindow.h \
inputoutput.h \
maingame.h \
mainmenu.h \
messagebox.h \
player.h \
selectionbox.h \
spaceship.h \
test.h \
window.h
SOURCES := \
board.cpp \
boardwindow.cpp \
infowindow.cpp \
inputoutput.cpp \
main.cpp \
maingame.cpp \
mainmenu.cpp \
messagebox.cpp \
player.cpp \
selectionbox.cpp \
spaceship.cpp \
test.cpp \
window.cpp
#------------------------------------------------------------------------------#
CXX := g++
CXXFLAGS := -lncurses -std=c++11 -Wall -Wextra
.PHONY: all debug run clean
all: run
debug: CXXFLAGS += -g -DDEBUG
debug: run
run: compile
@./$(PROGRAM) ; \
stty sane
compile: ${HEADERS} ${SOURCES}
$(CXX) $(CXXFLAGS) $? -o $(PROGRAM)
clean:
@-echo "Cleaning project.." ; \
rm -f $(PROGRAM)

57
messagebox.cpp

@ -0,0 +1,57 @@
#include <ncurses.h> // A_REVERSE
#include <sstream> // istringstream
#include <vector>
#include "inputoutput.h"
#include "messagebox.h"
MessageBox::MessageBox(std::string message) :
MessageBox(message, "") {
}
MessageBox::MessageBox(std::string message, std::string title) {
// Split message on newline
std::vector<std::string> lines;
std::istringstream strStream(message);
std::string tmpStr;
while (std::getline(strStream, tmpStr, '\n')) {
lines.push_back(tmpStr);
}
int rows;
int cols;
Window::getMaXYZ(stdscr, rows, cols);
// Calculate window dimension and size
int winRows = lines.size() + 8;
int winCols = cols * 0.9;
int y = (rows - winRows) / 2;
int x = (cols - winCols) / 2;
this->setWindow(winRows, winCols, y, x);
// Print title
title = IO::untrim(!title.empty() ? title : "Message", winCols - 2);
this->print(title, 0, 0, A_REVERSE);
// Print the message line by line
y = (winRows - lines.size()) / 2 - 1;
for (auto l : lines) {
this->setYX(y, 0);
this->printCenter(l);
y++;
}
this->setYX(winRows - 3, 0);
this->printCenter("Press <Space> to continue ",
COLOR_PAIR(PAIR_GRAY_BLACK_BRIGHT));
this->render();
// Press space to continue
while(!IO::getQuit()) {
IO::update();
if (IO::getKeyName() == " ") {
break;
}
}
}

17
messagebox.h

@ -0,0 +1,17 @@
#ifndef MESSAGEBOX_H
#define MESSAGEBOX_H
#include <string>
#include "window.h"
class MessageBox : public Window
{
public:
MessageBox(std::string message);
MessageBox(std::string message, std::string title);
private:
};
#endif // MESSAGEBOX_H

53
player.cpp

@ -0,0 +1,53 @@
#include <ncurses.h> // A_REVERSE
#include <stdio.h>
#include "player.h"
#include "infowindow.h"
Player::Player() :
chip(CHIP_AMOUNT),
name("") {
}
void Player::render(InfoWindow *window, int y, int x, unsigned char number) {
std::string print;
print += " Player ";
print += std::to_string(number);
print += " ";
window->print(print, y, x - 1, A_REVERSE);
y += 2;
window->print(this->name, y, x, COLOR_PAIR(this->color));
y += 2;
for (unsigned char i = 0; i < this->chip; i++) {
window->print("C", y, x, COLOR_PAIR(PAIR_WHITE_BLACK));
x++;
window->print(" ", y, x);
x++;
}
}
unsigned char Player::getChip() {
return this->chip;
}
void Player::setChip(unsigned char chip) {
this->chip = chip;
}
unsigned char Player::getColor() {
return this->color;
}
void Player::setColor(unsigned char color) {
this->color = color;
}
std::string Player::getName() {
return this->name;
}
void Player::setName(std::string name) {
this->name = name;
}

31
player.h

@ -0,0 +1,31 @@
#ifndef PLAYER_H
#define PLAYER_H
#define CHIP_AMOUNT 4
#define CHIP_SCORE 2
#include <string>
class InfoWindow;
class Player
{
public:
Player();
void render(InfoWindow *window, int y, int x, unsigned char number);
unsigned char getChip();
void setChip(unsigned char chip);
unsigned char getColor();
void setColor(unsigned char color);
std::string getName();
void setName(std::string name);
private:
unsigned char chip;
unsigned char color;
std::string name;
};
#endif // PLAYER_H

88
selectionbox.cpp

@ -0,0 +1,88 @@
#include <cstring> // strlen
#include <sstream> // istringstream
#include "inputoutput.h"
#include "selectionbox.h"
SelectionBox::SelectionBox(int height, int width) :
height(height),
width(width) {
this->update();
}
void SelectionBox::update() {
Window::update();
this->resize();
}
void SelectionBox::resize() {
int rows = (this->getMaxRows() - this->height) / 4;
int cols = this->getMaxCols() - this->width;
this->setWindow(rows, cols, this->getMaxRows() - rows, 0);
Window::resize();
}
unsigned char SelectionBox::select(std::string str, std::string *selection) {
int amount = 0;
while (!selection[amount].empty()) {
amount++;
}
std::string tmpStr;
int tmpInt;
// Display options and get user input
while(!IO::getQuit()) {
this->clear();
this->update();
this->printSelection(str, selection);
this->render();
tmpStr = IO::trim(this->getStr());
if (tmpStr == "") {
continue;
}
if (this->isNumber(tmpStr)) {
tmpInt = std::stoi(tmpStr);
if (tmpInt > 0 && tmpInt < amount + 1) {
break;
}
}
}
return (unsigned char)tmpInt - 1;
}
void SelectionBox::printSelection(std::string str, std::string *selection) {
int y = 0;
// Split and print message on newline
std::istringstream strStream(str);
std::string tmpStr;
while (std::getline(strStream, tmpStr, '\n')) {
this->print(tmpStr, y, 1);
y++;
}
y++;
int amount = 0;
while (!selection[amount].empty()) {
if (amount < 6) {
this->print("- " + selection[amount], y, 1);
}
else {
this->print("- " + selection[amount], y - 6, 10);
}
y++;
amount++;
}
this->print("Select option number: ", this->getRows() - 3, 1);
}
bool SelectionBox::isNumber(const std::string &s) {
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) it++;
return !s.empty() && it == s.end();
}

26
selectionbox.h

@ -0,0 +1,26 @@
#ifndef SELECTIONBOX_H
#define SELECTIONBOX_H
#include <string>
#include "window.h"
class SelectionBox : public Window
{
public:
SelectionBox(int height, int width);
void update();
void resize();
unsigned char select(std::string str, std::string *selection);
void printSelection(std::string str, std::string *selection);
private:
bool isNumber(const std::string &s);
int height;
int width;
};
#endif // SELECTIONBOX_H

57
spaceship.cpp

@ -0,0 +1,57 @@
#include "spaceship.h"
#include "window.h"
SpaceShip::SpaceShip() :
color(COLOR_UNSET),
size(SpaceShip::SIZE_UNSET),
planet(PLANET_UNSET) {
}
SpaceShip::SpaceShip(unsigned char color, unsigned char size) :
color(color),
size(size),
planet(PLANET_UNSET) {
}
void SpaceShip::render(Window *window, int y, int x, bool checkPlaced) {
if (checkPlaced && this->planet != PLANET_UNSET) {
return;
}
std::string print = "";
if (this->size == SpaceShip::SMALL) {
print = "S";
}
else if (this->size == SpaceShip::MEDIUM) {
print = "M";
}
else if (this->size == SpaceShip::BIG) {
print = "B";
}
window->print(print, y, x, COLOR_PAIR(this->color));
}
unsigned char SpaceShip::getColor() {
return this->color;
}
void SpaceShip::setColor(unsigned char color) {
this->color = color;
}
unsigned char SpaceShip::getSize() {
return this->size;
}
void SpaceShip::setSize(unsigned char size) {
this->size = size;
}
char SpaceShip::getPlanet() {
return this->planet;
}
void SpaceShip::setPlanet(char planet) {
this->planet = planet;
}

36
spaceship.h

@ -0,0 +1,36 @@
#ifndef SPACESHIP_H
#define SPACESHIP_H
#define PLANET_UNSET -1
class Window;
class SpaceShip
{
public:
SpaceShip();
SpaceShip(unsigned char color, unsigned char size);
void render(Window *window, int y, int x, bool checkPlaced = true);
unsigned char getColor();
void setColor(unsigned char color);
unsigned char getSize();
void setSize(unsigned char size);
char getPlanet();
void setPlanet(char planet);
enum Size {
SIZE_UNSET = 0,
SMALL = 1,
MEDIUM = 3,
BIG = 4,
};
private:
unsigned char color;
unsigned char size;
char planet;
};
#endif // SPACESHIP_H

68
test.cpp

@ -0,0 +1,68 @@
#include <cassert>
#include <iostream>
#include <ncurses.h>
#include "board.h"
#include "inputoutput.h"
#include "maingame.h"
#include "player.h"
#include "spaceship.h"
#include "test.h"
Test::Test() {
// IO::print("Unit test\n");
refresh();
// Board tests
Board *board = new Board;
char arrayShip[3] = { SpaceShip::SMALL, SpaceShip::MEDIUM, SpaceShip::BIG };
SpaceShip *ship = new SpaceShip(1, arrayShip[0]);
SpaceShip *ship2 = new SpaceShip(1, arrayShip[1]);
SpaceShip *ship3 = new SpaceShip(1, arrayShip[2]);
board->setShip(0, ship);
board->setShip(0, ship);
board->setShip(1, ship);
board->setShip(1, ship2);
board->setShip(2, ship3);
for (int i = 0; i < 3; i++) {
auto ships = board->getShips(i);
// printf("%lu\n", ships->size());
for (int j = 0; j < (int)ships->size(); j++) {
// printf("%d\n", ships->at(j)->getSize());
assert(ships->at(j)->getSize() == arrayShip[i]);
}
assert(ships->size() == 1);
}
board->moveShip(3, ship3);
assert(board->getShip(3, 0)->getSize() == arrayShip[2]);
// char array[SHIP_SIZE] = {
// SpaceShip::SMALL, SpaceShip::SMALL, SpaceShip::SMALL,
// SpaceShip::MEDIUM, SpaceShip::MEDIUM, SpaceShip::MEDIUM,
// SpaceShip::BIG, SpaceShip::BIG, SpaceShip::BIG,
// SpaceShip::SMALL, SpaceShip::SMALL, SpaceShip::SMALL,
// SpaceShip::MEDIUM, SpaceShip::MEDIUM, SpaceShip::MEDIUM,
// SpaceShip::BIG, SpaceShip::BIG, SpaceShip::BIG,
// };
// for (unsigned char i = 0; i < SHIP_SIZE; i++) {
// // printf("%d\n", board.ships[i]->getSize());
// // printf("%d\n", array[i]);
// assert(board.ships[i]->getSize() == array[i]);
// }
// IO::print("Passed board checks..");
refresh();
getch();
// Cleanup resources
delete board;
delete ship;
delete ship2;
delete ship3;
IO::setQuit();
}

12
test.h

@ -0,0 +1,12 @@
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test();
private:
};
#endif // TEST_H

222
window.cpp

@ -0,0 +1,222 @@
#include <cstdio>
#include "gamestate.h"
#include "window.h"
Window::Window(int rows, int cols, int y, int x) :
rows(rows),
cols(cols),
y(0),
x(0),
window(newwin(rows, cols, y, x)) {
}
Window::~Window() {
delwin(this->window);
}
void Window::initialize() {
// Start curses mode
initscr();
// Disable line buffering
cbreak();
// Enable reading of function keys
keypad(stdscr, TRUE);
// Dont echo while reading input
noecho();
// Disable cursor visibility
curs_set(0);
// If terminal supports colors
if(!has_colors()) {
printw("Your terminal does not support color\n");
}
else {
start_color();
use_default_colors();
init_pair(PAIR_WHITE_BLACK, COLOR_WHITE, COLOR_BLACK);
init_pair(PAIR_WHITE_BRIGHT_BLACK, COLOR_WHITE_BRIGHT, COLOR_BLACK);
init_pair(PAIR_RED_BLACK, COLOR_RED, COLOR_BLACK);
init_pair(PAIR_BLUE_BLACK, COLOR_BLUE, COLOR_BLACK);
init_pair(PAIR_GRAY_BLACK_BRIGHT, COLOR_GRAY, COLOR_BLACK_BRIGHT);
}
// Add bright colors, intensity range: 0-1000
if(!can_change_color()) {
printw("Your terminal does not support changing colors\n");
}
else {
init_color(COLOR_BLACK, 0, 0, 0);
init_color(COLOR_WHITE, 680, 680, 680);
init_color(COLOR_GRAY, 380, 380, 380);
init_color(COLOR_BLACK_BRIGHT, 110, 110, 110); // 0, 0, 0
init_color(COLOR_RED_BRIGHT, 900, 0, 0); // 680, 0, 0
init_color(COLOR_GREEN_BRIGHT, 0, 900, 0); // 0, 680, 0
init_color(COLOR_YELLOW_BRIGHT, 900, 900, 0); // 680, 680, 0
init_color(COLOR_BLUE_BRIGHT, 0, 0, 900); // 0, 0, 680
init_color(COLOR_MAGENTA_BRIGHT, 900, 0, 900); // 680, 0, 680
init_color(COLOR_CYAN_BRIGHT, 0, 900, 900); // 0, 680, 680
init_color(COLOR_WHITE_BRIGHT, 900, 900, 900); // 680, 680, 680
}
}
void Window::update() {
Window::getMaXYZ(stdscr, this->maxRows, this->maxCols);
}
void Window::render() {
box(this->window, 0, 0);
wrefresh(this->window);
}
void Window::destroy() {
// Restore line buffering
nocbreak();
// Restore cursor
curs_set(1);
// End curses mode
endwin();
}
void Window::clear() {
this->setYX(0, 0);
// Set background color
// wbkgdset(this->window, COLOR_PAIR(3));
// Copy blanks to every position in the window, clearing the screen
werase(this->window);
}
void Window::resize() {
wresize(this->window, this->rows, this->cols);
mvwin(this->window, this->y, this->x);
}
void Window::print(std::string str, char newLine) {
this->print(str, this->y, this->x);
this->x += str.length();
if (newLine == 1) {
this->x = 0;
this->y++;
}
}
void Window::print(std::string str, int y, int x) {
this->y = y;
this->x = x;
mvwprintw(this->window, y + 1, x + 1, str.c_str());
}
void Window::print(std::string str, int y, int x, int attribute) {
wattron(this->window, attribute);
this->print(str, y, x);
wattroff(this->window, attribute);
}
void Window::printCenter(std::string str) {
int halfBoard = this->cols / 2;
int halfStr = str.length() / 2;
this->print(str, this->y, halfBoard - halfStr - 1);
}
void Window::printCenter(std::string str, int attribute) {
wattron(this->window, attribute);
this->printCenter(str);
wattroff(this->window, attribute);
}
void Window::printSide(std::string left, std::string right) {
this->print(left, this->y, 1);
this->print(right, this->y, this->cols - right.length() - 3);
}
void Window::getYX(int &y, int &x) {
getyx(this->window, y, x);
}
void Window::setYX(int y, int x) {
this->y = y;
this->x = x;
wmove(this->window, y, x);
}
void Window::getMaXYZ(int &rows, int &cols) {
getmaxyx(this->window, rows, cols);
}
void Window::getMaXYZ(WINDOW *window, int &rows, int &cols) {
getmaxyx(window, rows, cols);
}
std::string Window::getStr() {
curs_set(1);
echo();
char *tmp = new char();
wgetstr(this->window, tmp);
noecho();
curs_set(0);
return std::string(tmp);
}
int Window::getMaxRows() {
return this->maxRows;
}
int Window::getMaxCols() {
return this->maxCols;
}
int Window::getRows() {
return this->rows;
}
void Window::setRows(int rows) {
this->rows = rows;
}
int Window::getCols() {
return this->cols;
}
void Window::setCols(int cols) {
this->cols = cols;
}
int Window::getY() {
return this->y;
}
void Window::setY(int y) {
this->y = y;
}
int Window::getX() {
return this->x;
}
void Window::setX(int x) {
this->x = x;
}
void Window::setWindow(int rows, int cols, int y, int x) {
this->setRows(rows);
this->setCols(cols);
this->setY(y);
this->setX(x);
if (this->window == nullptr) {
this->window = newwin(rows, cols, y, x);
}
}
//----------------------------------------------------------------------------//
Window::Window() :
rows(0),
cols(0),
y(0),
x(0),
window(nullptr) {
}

75
window.h

@ -0,0 +1,75 @@
#ifndef WINDOW_H
#define WINDOW_H
#define COLOR_UNSET 0
#define COLOR_BLACK_BRIGHT 8
#define COLOR_RED_BRIGHT 9
#define COLOR_GREEN_BRIGHT 10
#define COLOR_YELLOW_BRIGHT 11
#define COLOR_BLUE_BRIGHT 12
#define COLOR_MAGENTA_BRIGHT 13
#define COLOR_CYAN_BRIGHT 14
#define COLOR_WHITE_BRIGHT 15
#define COLOR_GRAY 16
#define PAIR_WHITE_BLACK 1
#define PAIR_WHITE_BRIGHT_BLACK 2
#define PAIR_RED_BLACK 3
#define PAIR_BLUE_BLACK 4
#define PAIR_GRAY_BLACK_BRIGHT 5
#include <ncurses.h>
#include <string>
class Window
{
public:
Window(int rows, int cols, int y, int x);
~Window();
static void initialize();
void update();
void render();
static void destroy();
void clear();
void resize();
void print(std::string str, char newLine = 1);
void print(std::string str, int y, int x);
void print(std::string str, int y, int x, int attribute);
void printCenter(std::string str);
void printCenter(std::string str, int attribute);
void printSide(std::string left, std::string right);
void getYX(int &y, int &x);
void setYX(int y, int x);
void getMaXYZ(int &rows, int &cols);
static void getMaXYZ(WINDOW *window, int &rows, int &cols);
std::string getStr();
int getMaxRows();
int getMaxCols();
int getRows();
void setRows(int rows);
int getCols();
void setCols(int cols);
int getY();
void setY(int y);
int getX();
void setX(int x);
void setWindow(int rows, int cols, int y, int x);
protected:
Window();
private:
int maxRows;
int maxCols;
int rows;
int cols;
int y;
int x;
WINDOW *window;
};
#endif // WINDOW_H
불러오는 중...
취소
저장