Initial commit

This commit is contained in:
Jan Potocki
2020-05-04 15:56:02 +02:00
commit a8382b30e1
27 changed files with 1282 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
#include "Brick.h"
#include <cstdlib>
#include <iostream>
#include <unistd.h>
Platform *Brick::platform = 0;
Brick::Brick(int xPosition, int descentRate)
{
//ctor
this->xPosition = xPosition;
this->yPosition = -1;
this->descentRate = descentRate;
this->falling = false;
randomColor();
}
Brick::~Brick()
{
//dtor
}
void Brick::setPlatform(Platform *newPlatform)
{
platform = newPlatform;
}
int Brick::getxPosition()
{
return xPosition;
}
int Brick::getyPosition()
{
return yPosition;
}
int Brick::getColor()
{
return color;
}
bool Brick::isFalling()
{
return falling;
}
void Brick::fall()
{
if(!initialized)
{
std::cout << "Scene size not initialized!" << std::endl;
return;
}
if(platform == 0)
{
std::cout << "Platform not set!" << std::endl;
return;
}
falling = true;
while(running & falling & yPosition < yMax - 2)
{
// Freeze game
if(freezed)
{
std::unique_lock<std::mutex> freezeLock(freezeMutex);
while(freezed)
{
freezeCondition.wait(freezeLock);
}
}
// If game terminated, we shouldn't do all this stuff
if(running)
{
yPosition++;
if(yPosition == yMax - 2 && platform->getPosition() <= xPosition && platform->getEnd() >= xPosition)
{
falling = false;
if(platform->getColor() == color)
{
points += 5;
}
else
{
if(points != 0)
{
points--;
}
freeze();
}
break;
}
usleep(250000 - 10000 * descentRate);
}
}
if(running)
{
// Reset
yPosition = -1;
falling = false;
randomColor();
}
}
std::thread Brick::fallThread()
{
return std::thread(&Brick::fall, this);
}
void Brick::randomColor()
{
color = rand() % 6 + 1;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef BRICK_H
#define BRICK_H
#include <thread>
#include "Platform.h"
#include "Scene.h"
class Brick : public Scene
{
public:
Brick(int xPosition, int descentRate);
~Brick();
static void setPlatform(Platform *newPlatform);
int getxPosition();
int getyPosition();
int getColor();
bool isFalling();
std::thread fallThread();
protected:
private:
static Platform *platform;
int xPosition;
int yPosition;
int descentRate;
int color;
bool falling;
void fall();
void randomColor();
};
#endif // BRICK_H
BIN
View File
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
CXXFLAGS = -Wall -std=c++11
OBJS = so2-game.o Brick.o Platform.o Scene.o Stopwatch.o
LIBS = -pthread -lncurses
TARGET = so2-game
$(TARGET): $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
all: $(TARGET)
clean:
rm -f $(OBJS) $(TARGET)
+133
View File
@@ -0,0 +1,133 @@
#include "Platform.h"
#include <iostream>
#include <ncurses.h>
#include <unistd.h>
Platform::Platform()
{
//ctor
points = 0;
color = 0;
sprite = "<--->";
}
Platform::~Platform()
{
//dtor
}
const char *Platform::getSprite()
{
return sprite.c_str();
}
int Platform::getPosition()
{
return position;
}
int Platform::getEnd()
{
int endPos = position + sprite.length() - 1;
return endPos;
}
int Platform::getColor()
{
return color;
}
void Platform::terminateThreads()
{
running = false;
}
void Platform::moveKey()
{
if(!initialized)
{
std::cout << "Scene size not initialized!" << std::endl;
return;
}
int key;
while(running)
{
ncursesMutex.lock();
key = getch();
ncursesMutex.unlock();
// Freeze game
if(freezed)
{
std::unique_lock<std::mutex> freezeLock(freezeMutex);
while(freezed)
{
freezeCondition.wait(freezeLock);
}
// Ignore keys pressed when frozen
flushinp();
}
switch(key)
{
case 'a':
if(position > 0)
{
position--;
}
break;
case 'd':
if(position < xMax - sprite.length())
{
position++;
}
}
}
}
std::thread Platform::moveKeyThread()
{
return std::thread(&Platform::moveKey, this);
}
void Platform::colorChange()
{
const int idleSeconds = 15;
while(running)
{
color = rand() % 6 + 1;
// Waiting - this must be interruptable, so it can't be just sleep(idleSeconds)
for(int i = 0; i < idleSeconds * 10; i++)
{
// Freeze game
if(freezed)
{
std::unique_lock<std::mutex> freezeLock(freezeMutex);
while(freezed)
{
freezeCondition.wait(freezeLock);
}
}
if(!running)
{
break;
}
// Every tick = 100 ms
usleep(100000);
}
}
}
std::thread Platform::colorChangeThread()
{
return std::thread(&Platform::colorChange, this);
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_H
#define PLATFORM_H
#include <string>
#include <thread>
#include "Scene.h"
class Platform : public Scene
{
public:
Platform();
~Platform();
const char *getSprite();
int getPosition();
int getEnd();
int getColor();
void terminateThreads();
std::thread moveKeyThread();
std::thread colorChangeThread();
protected:
private:
std::string sprite;
int position;
int points;
int color;
void moveKey();
void colorChange();
};
#endif // PLATFORM_H
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
#include "Scene.h"
#include <unistd.h>
int Scene::xMax;
int Scene::yMax;
int Scene::points = 0;
bool Scene::initialized = false;
bool Scene::freezed = false;
bool Scene::running = false;
std::mutex Scene::ncursesMutex;
std::mutex Scene::freezeMutex;
std::condition_variable Scene::freezeCondition;
Scene::Scene()
{
//ctor
}
Scene::~Scene()
{
//dtor
}
void Scene::init(int xRes, int yRes)
{
xMax = xRes;
yMax = yRes;
running = true;
initialized = true;
}
int Scene::getPoints()
{
return points;
}
bool Scene::isFreezed()
{
return freezed;
}
void Scene::freeze()
{
const int idleSeconds = 10;
std::unique_lock<std::mutex> freezeLock(freezeMutex);
freezed = true;
sleep(idleSeconds);
// // This must be interruptable, so it can't be just sleep(idleSeconds)
// for(int i = 0; i < idleSeconds * 10; i++)
// {
// if(running)
// {
// // Every tick = 100 ms
// usleep(100000);
// }
// else
// {
// break;
// }
// }
freezed = false;
freezeCondition.notify_all();
}
void Scene::terminateAll()
{
Scene::running = false;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef SCENE_H
#define SCENE_H
#include <condition_variable>
#include <mutex>
#include <thread>
class Scene
{
public:
static std::mutex ncursesMutex;
static std::mutex freezeMutex;
static std::condition_variable freezeCondition;
Scene();
virtual ~Scene();
static void init(int xRes, int yRes);
static int getPoints();
static bool isFreezed();
static void terminateAll();
protected:
static int xMax;
static int yMax;
static int points;
static bool initialized;
static bool freezed;
static bool running;
static void freeze();
private:
};
#endif // SCENE_H
BIN
View File
Binary file not shown.
+40
View File
@@ -0,0 +1,40 @@
#include "Stopwatch.h"
Stopwatch::Stopwatch()
{
//ctor
// Jan Potocki 2018
}
void Stopwatch::start()
{
running = true;
miliseconds = 0;
measureThread = std::thread(&Stopwatch::measure, this);
}
void Stopwatch::stop()
{
running = false;
measureThread.join();
}
bool Stopwatch::isRunning()
{
return running;
}
float Stopwatch::read()
{
float measurement = (float)miliseconds / 1000;
return measurement;
}
void Stopwatch::measure()
{
while(running)
{
usleep(1000);
miliseconds++;
}
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef STOPWATCH_H
#define STOPWATCH_H
#include <thread>
#include <unistd.h>
// Klasa do pomiaru czasu w oparciu o funkcje systemowe
// Jan Potocki 2018
class Stopwatch
{
public:
Stopwatch();
void start();
void stop();
bool isRunning();
float read();
protected:
private:
unsigned long long int miliseconds;
bool running;
std::thread measureThread;
void measure();
};
#endif // STOPWATCH_H
Binary file not shown.
+202
View File
@@ -0,0 +1,202 @@
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <ncurses.h>
#include <unistd.h>
#include "Brick.h"
#include "Platform.h"
#include "Stopwatch.h"
const int gameTime = 120;
int xMax, yMax;
bool refreshing = false;
bool climate = false;
std::vector<Brick> bricks;
Platform platform;
Stopwatch gameClock;
// "Monitor" function
void refreshScreen()
{
while(refreshing == true)
{
Scene::ncursesMutex.lock();
clear();
for(int i = 0; i < bricks.size(); i++)
{
// Easter egg (1)
if(climate)
{
attron(COLOR_PAIR(bricks[i].getColor()));
mvprintw(bricks[i].getyPosition(), bricks[i].getxPosition(), "*");
attroff(COLOR_PAIR(bricks[i].getColor()));
}
else
{
attron(COLOR_PAIR(bricks[i].getColor()));
mvprintw(bricks[i].getyPosition(), bricks[i].getxPosition(), "#");
attroff(COLOR_PAIR(bricks[i].getColor()));
}
}
attron(COLOR_PAIR(platform.getColor()));
mvprintw(yMax - 2, platform.getPosition(), platform.getSprite());
attroff(COLOR_PAIR(platform.getColor()));
mvprintw(yMax - 1, 0, "%.3f", gameClock.read());
mvprintw(yMax - 1, xMax - 3, "%.3d", Scene::getPoints());
refresh();
Scene::ncursesMutex.unlock();
// Refresh every 0.01 s
usleep(10000);
}
}
int main(int argc, char *argv[])
{
std::vector<std::thread> brickThreads;
srand(time(0));
// Easter egg (2)
if(argc == 2)
{
std::string param(argv[1]);
if(param == "--globalwarming")
{
climate = true;
}
}
// Initialize ncurses
initscr();
curs_set(0);
getmaxyx(stdscr, yMax, xMax);
// Initialize colors
start_color();
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_YELLOW, COLOR_BLACK);
init_pair(4, COLOR_BLUE, COLOR_BLACK);
init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
init_pair(6, COLOR_CYAN, COLOR_BLACK);
// Non-blocking input for platform-movement
timeout(0);
// Initialize scene
Scene::init(xMax, yMax);
Brick::setPlatform(&platform);
// Initialize all bricks...
for(int i = 0; i < xMax; i++)
{
// ...with random descent rate in range 0 (slow) to 15 (fast)
Brick brick(i, rand() % 16);
bricks.push_back(brick);
}
// Start monitor
refreshing = true;
std::thread monitor(refreshScreen);
// Start platform treads
std::thread platformMover(platform.moveKeyThread());
std::thread platformColorChanger(platform.colorChangeThread());
// Start game
gameClock.start();
while(gameClock.read() < gameTime)
{
// Freeze game
if(Scene::isFreezed() == true)
{
std::unique_lock<std::mutex> freezeLock(Scene::freezeMutex);
while(Scene::isFreezed() == true)
{
Scene::freezeCondition.wait(freezeLock);
}
}
// Determine random brick...
int randBrick = rand() % xMax;
while(bricks.at(randBrick).isFalling())
{
// ...which still isn't falling down...
randBrick = rand() % xMax;
}
// ...and launch it with nuclear-powered hammer ;-)
brickThreads.push_back(bricks.at(randBrick).fallThread());
// Random time in range 400 to 800 ms until next fall
unsigned randTime = rand() % 4 + 4;
usleep(100000 * randTime);
}
// Stop clock
gameClock.stop();
// Stop scene objects threads
Scene::terminateAll();
platformMover.join();
platformColorChanger.join();
for(int i = 0; i < brickThreads.size(); i++)
{
brickThreads.at(i).join();
}
// Stop monitor
refreshing = false;
monitor.join();
sleep(1);
// Close ncurses
endwin();
std::cout << "Your score: " << Scene::getPoints() << " points" << std::endl;
if(Scene::getPoints() != 0)
{
std::cout << "Congratulations!" << std::endl;
}
std::cout << std::endl;
std::cout << "BRIcks-ng Caban Kernel-thread System Next Generation v1.0" << std::endl;
std::cout << "Jan Potocki 2018" << std::endl;
std::cout << "(beerware)" << std::endl;
std::cout << std::endl;
std::cout << '"' << "...Back around that Halloween," << std::endl;
std::cout << "Microsoft said open source would never last," << std::endl;
std::cout << "But now they use the repo tools," << std::endl;
std::cout << "In the same open access way..." << '"' << std::endl;
std::cout << "(and recently acquired GitHub)" << std::endl;
std::cout << std::endl;
// Easter egg (3)
if(climate)
{
std::cout << "SEVERE WEATHER ALERT: major snowfall predicted in 48h forecast for Lower Silesia, south-western Poland" << std::endl;
std::cout << "Global warming affecting again!... ;-)" << std::endl;
}
else
{
std::cout << "Beware of BRICKS! ;-)" << std::endl;
}
return 0;
}
Binary file not shown.