Compare commits

..

No commits in common. "main" and "read-file" have entirely different histories.

23 changed files with 114 additions and 491 deletions

2
.gitignore vendored
View File

@ -86,5 +86,3 @@ dkms.conf
*.out *.out
*.app *.app
# Custom
bin/*

View File

@ -1,17 +1,7 @@
FROM gcc:latest AS build FROM gcc:latest
WORKDIR /app WORKDIR /app
COPY include/* /app/include/ COPY bin/Bowling /app/
COPY src/* /app/src/
RUN g++ src/*.cpp -o Bowling CMD ["./Bowling"]
FROM debian:sid-slim
WORKDIR /app
COPY --from=build /app/Bowling Bowling
COPY rolls.txt /app/
CMD ["./Bowling", "rolls.txt"]

13
Include/FileHelper.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef FILEHELPER_H
#define FILEHELPER_H
class FileHelper {
public:
FileHelper();
~FileHelper();
static bool FileExists(char *path);
};
#endif

16
Include/FileReader.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef FILEREADER_H
#define FILEREADER_H
#include <string>
#include <vector>
class FileReader {
public:
FileReader();
~FileReader();
static std::string GetFile(char *path);
};
#endif

16
Include/NumberHelper.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef NUMBERHELPER_H
#define NUMBERHELPER_H
#include <string>
#include <vector>
class NumberHelper {
public:
NumberHelper();
~NumberHelper();
static std::vector<int> GetNumbers(const std::string csv);
};
#endif

View File

@ -1,9 +1,3 @@
# Bowling # Bowling
To run the project, simply follow these steps: If you want to try out the project, please use git clone with the HTTPS link to the repo, and not the SSH link, as only the owner can pull and push via SSH.
1. `git clone https://git.rbwr.dk/owner/Bowling.git`
2. `cd Bowling/`
2. `docker build -t bowling .`
3. `docker run --rm bowling`
To change bowling score, simply edit the `rolls.txt` file, and build the docker image again.

View File

@ -1,19 +0,0 @@
#ifndef FILEUTILS_H
#define FILEUTILS_H
#include <string>
#include <vector>
using namespace std;
class FileUtils {
public:
FileUtils() = default;
~FileUtils() = default;
static string getFile(char *path);
static bool fileExists(char *path);
};
#endif

View File

@ -1,11 +0,0 @@
#ifndef FRAME_H
#define FRAME_H
#include <vector>
using namespace std;
struct Frame {
vector<int> Roll;
};
#endif

View File

@ -1,28 +0,0 @@
#ifndef NUMBERUTILS_H
#define NUMBERUTILS_H
#include <string>
#include <vector>
#include "../include/Frame.h"
using namespace std;
class NumberUtils {
public:
NumberUtils() = default;
~NumberUtils() = default;
static vector<int> getRolls(const string& csv);
static bool validateRolls(const vector<int>& rolls);
static vector<Frame> createFrames(const vector<int>& rolls);
private:
static Frame createStrikeFrame(int i);
static Frame createFreeFrame(int i, int j);
static Frame createBonusFrame(int i, int j, int k);
static bool isNumber(const std::string& str);
};
#endif

View File

@ -1,24 +0,0 @@
#ifndef PRINTFRAMES_H
#define PRINTFRAMES_H
#include <vector>
#include <string>
#include "../include/Frame.h"
using namespace std;
class PrintFrames {
public:
PrintFrames() = default;
~PrintFrames() = default;
static void printResult(const vector<Frame>& frames);
private:
static void printHeader();
static string parseValue(const vector<Frame>& frames);
};
#endif

View File

@ -1,19 +0,0 @@
#ifndef SCORECALCULATOR_H
#define SCORECALCULATOR_H
#include <string>
#include <vector>
#include "../include/Frame.h"
using namespace std;
class ScoreCalculator {
public:
ScoreCalculator() = default;
~ScoreCalculator() = default;
static int getScore(const vector<Frame>& frames);
};
#endif

16
src/FileHelper.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "../Include/FileHelper.h"
#include <sys/stat.h>
FileHelper::FileHelper() {};
FileHelper::~FileHelper() {};
bool FileHelper::FileExists(char *path){
struct stat s;
// Check if file exists, and if it isn't a folder.
if (stat(path, &s) == 0 && !(s.st_mode & S_IFDIR)){
return true;
}
return false;
}

18
src/FileReader.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "../Include/FileReader.h"
#include <string>
#include <fstream>
FileReader::FileReader() {};
FileReader::~FileReader() {};
std::string FileReader::GetFile(char *path){
std::ifstream file(path);
std::string line;
std::getline(file, line);
file.close();
return line;
}

View File

@ -1,28 +0,0 @@
#include "../include/FileUtils.h"
#include <string>
#include <fstream>
#include <sys/stat.h>
bool FileUtils::fileExists(char *path){
struct stat s;
// Check if file exists, and if it isn't a folder.
if (stat(path, &s) == 0 && !(s.st_mode & S_IFDIR)){
return true;
}
return false;
}
string FileUtils::getFile(char *path){
ifstream file(path);
string line;
// There is only one line in the file
getline(file, line);
file.close();
return line;
}

19
src/NumberHelper.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "../Include/NumberHelper.h"
#include <string>
#include <sstream>
#include <vector>
NumberHelper::NumberHelper() {};
NumberHelper::~NumberHelper() {};
std::vector<int> NumberHelper::GetNumbers(const std::string csv){
std::vector<int> rolls;
std::stringstream ss(csv);
std::string number;
while (std::getline(ss, number, ',')) {
rolls.push_back(std::stoi(number));
}
return rolls;
}

View File

@ -1,140 +0,0 @@
#include "../include/NumberUtils.h"
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cctype>
vector<int> NumberUtils::getRolls(const string& csv){
vector<int> rolls;
stringstream ss(csv);
string number;
// Get number from the CSV file, split by comma, and convert to int.
while (getline(ss, number, ',')) {
if (!isNumber(number)) {
cerr << number << " is not a number.";
break;
}
rolls.push_back(stoi(number));
}
return rolls;
}
bool NumberUtils::validateRolls(const vector<int>& rolls){
int rollCount = rolls.size();
for (int i = 0; i < rollCount; ++i) {
if (rolls[i] > 10 || rolls[i] < 0) {
cerr << "Number: " << rolls[i] << " is invalid.";
return false;
}
}
// A game can not have less than 12 rolls, and more than 21.
if (rollCount < 12 || rollCount > 21) {
cerr << "Incorrect amount of rolls.";
return false;
}
// 10th frame rule.
if (rollCount == 21) {
if (rolls[18] != 10 && rolls[18] + rolls[19] != 10) {
return false;
}
}
return true;
}
vector<Frame> NumberUtils::createFrames(const vector<int>& rolls){
vector<Frame> frame;
int roll = 0;
while (roll != rolls.size()) {
// Strike
if (rolls[roll] == 10) {
// If we're on our last frame, and roll a strike, we're given two bonus rolls.
if (roll + 3 == rolls.size() && rolls[roll - 3] == 10) {
frame.push_back(createBonusFrame(rolls[roll], rolls[roll + 1], rolls[roll + 2]));
break;
}
frame.push_back(createStrikeFrame(10));
roll += 1;
}
// Spare
else if (rolls[roll] + rolls[roll + 1] == 10) {
// If we're on our last frame, and roll a spare, we're given a bonus roll.
if (roll + 3 == rolls.size()) {
frame.push_back(createBonusFrame(rolls[roll], rolls[roll + 1], rolls[roll + 2]));
break;
}
frame.push_back(createFreeFrame(rolls[roll], rolls[roll + 1]));
roll += 2;
}
// Open Frame
else {
frame.push_back(createFreeFrame(rolls[roll], rolls[roll + 1]));
roll += 2;
}
}
return frame;
}
Frame NumberUtils::createStrikeFrame(int i){
struct Frame frame = Frame();
vector<int> rolls;
rolls.push_back(i);
frame.Roll = rolls;
return frame;
}
Frame NumberUtils::createFreeFrame(int i, int j){
struct Frame frame = Frame();
vector<int> rolls;
rolls.push_back(i);
rolls.push_back(j);
frame.Roll = rolls;
return frame;
}
Frame NumberUtils::createBonusFrame(int i, int j, int k){
struct Frame frame = Frame();
vector<int> rolls;
rolls.push_back(i);
rolls.push_back(j);
rolls.push_back(k);
frame.Roll = rolls;
return frame;
}
bool NumberUtils::isNumber(const std::string& str){
for (size_t i = 0; i < str.size(); ++i) {
if (!isdigit(str[i]) && !isspace(str[i])) return false;
}
return true;
}

View File

@ -1,132 +0,0 @@
#include "../include/PrintFrames.h"
#include <iostream>
#include <sstream>
void PrintFrames::printResult(const vector<Frame>& frames) {
printHeader();
cout << parseValue(frames);
}
void PrintFrames::printHeader() {
cout << "| f1 | f2 | f3 | f4 | f5 | f6 | f7 | f8 | f9 | f10 |" << endl;
}
string PrintFrames::parseValue(const vector<Frame>& frames) {
stringstream ss;
// There can only be 10 frames.
for (int i = 0; i < 10; i++) {
ss << "|";
// Strike
if (frames[i].Roll[0] == 10) {
if (frames[i].Roll.size() == 3) {
ss << "X, ";
if (frames[i].Roll[1] == 10 && frames[i].Roll[2] == 10) {
ss << "X, X";
}
else if (frames[i].Roll[1] != 10 && frames[i].Roll[2] == 10) {
ss << frames[i].Roll[1] << ", X ";
}
else if (frames[i].Roll[1] == 10 && frames[i].Roll[2] != 10) {
ss << "X, " << frames[i].Roll[2] << " ";
}
else if (frames[i].Roll[1] == 10 && frames[i].Roll[2] == 0) {
ss << frames[i].Roll[1] << ", - ";
}
else if (frames[i].Roll[1] == 0 && frames[i].Roll[2] == 10) {
ss << "-, " << frames[i].Roll[2] << " ";
}
else if (frames[i].Roll[1] != 10 && frames[i].Roll[2] == 0) {
ss << frames[i].Roll[1] << ", - ";
}
else if (frames[i].Roll[1] == 0 && frames[i].Roll[2] != 10) {
ss << "-, " << frames[i].Roll[2] << " ";
}
continue;
}
// If the next frame has 3 or 2 rolls, then take those 2.
if (frames[i + 1].Roll.size() > 1) {
if (frames[i + 1].Roll[0] == 10 && frames[i + 1].Roll[1] != 10) {
ss << "X, " << frames[i + 1].Roll[0] << " ";
}
else if (frames[i + 1].Roll[0] != 10 && frames[i + 1].Roll[1] == 10) {
ss << frames[i + 1].Roll[1] << ", X";
} else {
if (frames[i + 1].Roll[0] + frames[i + 1].Roll[1] == 10) {
ss << "X, " << frames[i + 1].Roll[0] << ", /";
}
else if (frames[i + 1].Roll[0] == 0 && frames[i + 1].Roll[1] != 0) {
ss << "X, " << "-, " << frames[i + 1].Roll[1];
}
else if (frames[i + 1].Roll[0] != 0 && frames[i + 1].Roll[1] == 0) {
ss << "X, " << frames[i + 1].Roll[0] << ", -";
} else {
ss << "X, ";
}
}
continue;
}
// Both next frames, that are not the last, are 10.
ss << "X ";
continue;
}
// Spare
if (frames[i].Roll[0] + frames[i].Roll[1] == 10) {
if (frames[i].Roll.size() == 3) {
if (frames[i].Roll[0] == 0 && frames[i].Roll[1] != 10 && frames[i].Roll[2] != 10) {
if (frames[i].Roll[2] == 0) {
ss << "-, /, -";
} else {
ss << "-, " << frames[i].Roll[1] << frames[i].Roll[2];
}
}
else if (frames[i].Roll[0] == 0 && frames[i].Roll[1] == 10 && frames[i].Roll[2] != 10) {
if (frames[i].Roll[2] == 0) {
ss << "-, /, -";
} else {
ss << "-, /, " << frames[i].Roll[2];
}
}
else if (frames[i].Roll[0] == 0 && frames[i].Roll[1] == 10 && frames[i].Roll[2] == 10) {
ss << "-, /, X";
} else {
ss << frames[i].Roll[0] << ", /, " << frames[i].Roll[2];
}
continue;
}
ss << frames[i].Roll[0] << ", /";
continue;
}
// Open frame
if (i == 9) {
ss << frames[i].Roll[0] << ", " << frames[i].Roll[1] << " ";
} else {
if (frames[i].Roll[0] == 0 && frames[i].Roll[1] == 0) {
ss << "-, -";
}
else if (frames[i].Roll[0] == 0 && frames[i].Roll[1] != 0) {
ss << "-, " << frames[i].Roll[1];
}
else if (frames[i].Roll[0] != 0 && frames[i].Roll[1] == 0) {
ss << frames[i].Roll[0] << ", -";
} else {
ss << frames[i].Roll[0] << ", " << frames[i].Roll[1];
}
}
}
ss << "|";
ss << endl;
return ss.str();
}

View File

@ -1,43 +0,0 @@
#include "../include/ScoreCalculator.h"
#include "../include/Frame.h"
int ScoreCalculator::getScore(const vector<Frame>& frames) {
int score = 0;
// There can only be 10 frames.
for (int i = 0; i < 10; i++) {
// Strike
if (frames[i].Roll[0] == 10) {
if (frames[i].Roll.size() == 3) {
score += frames[i].Roll[0] + frames[i].Roll[1] + frames[i].Roll[2];
continue;
}
// If the next frame has 3 or 2 rolls, then take those 2.
if (frames[i + 1].Roll.size() > 1) {
score += frames[i].Roll[0] + frames[i + 1].Roll[0] + frames[i + 1].Roll[1];
continue;
}
// Both next frames, that are not the last, are 10.
score += frames[i].Roll[0] + frames[i + 1].Roll[0] + frames[i + 2].Roll[0];
continue;
}
// Spare
if (frames[i].Roll[0] + frames[i].Roll[1] == 10) {
if (frames[i].Roll.size() == 3) {
score += frames[i].Roll[0] + frames[i].Roll[1] + frames[i].Roll[2];
continue;
}
score += 10 + frames[i + 1].Roll[0];
continue;
}
// Open frame
score += frames[i].Roll[0] + frames[i].Roll[1];
}
return score;
}

View File

@ -1,36 +1,27 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "../include/FileUtils.h" #include "../Include/FileReader.h"
#include "../include/NumberUtils.h" #include "../Include/FileHelper.h"
#include "../include/ScoreCalculator.h" #include "../Include/NumberHelper.h"
#include "../include/PrintFrames.h"
using namespace std;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc < 2) { if(argc < 2) {
cerr << "Please provide a CSV formatted file."; std::cerr << "Please provide a CSV formatted file.";
return 0; return 0;
} }
if (!FileUtils::fileExists(argv[1])) { if(!FileHelper::FileExists(argv[1])) {
cerr << "Filepath: " << argv[1] << " doesn't exist."; std::cerr << "Filepath: " << argv[1] << " doesn't exist.";
return 0; return 0;
} }
string file = FileUtils::getFile(argv[1]); std::string file = FileReader::GetFile(argv[1]);
vector<int> rolls = NumberUtils::getRolls(file);
if (!NumberUtils::validateRolls(rolls)) { std::vector<int> numbers = NumberHelper::GetNumbers(file);
return 0;
for(int i = 0; i < numbers.size(); i++) {
std::cout << numbers[i] << ' ';
} }
vector<Frame> frames = NumberUtils::createFrames(rolls);
PrintFrames::printResult(frames);
int score = ScoreCalculator::getScore(frames);
cout << "Score: " << score << endl;
return 0; return 0;
} }

View File

@ -1 +0,0 @@
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10

View File

@ -1 +0,0 @@
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5

View File

@ -1 +0,0 @@
5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 5, 5

View File

@ -1 +0,0 @@
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 10, 10