302 lines
8.7 KiB
C++
302 lines
8.7 KiB
C++
#include "Game.hpp"
|
|
#include <SFML/System/Sleep.hpp>
|
|
#include <SFML/System/Time.hpp>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <filesystem> // sprawdzenie, czy plik istnieje
|
|
#include "ssp.hpp" // nagłówkowy parser plików .csv
|
|
#include "Engine.hpp"
|
|
|
|
void Game::printGameWelcomeText() const {
|
|
|
|
std::cout << "\n"
|
|
" .o88b. db db d888888b d8b db .o88b. d88888D db db db dD db .d888b. .d888b.\n"
|
|
"d8P Y8 88 88 `88' 888o 88 d8P Y8 YP d8' `8b d8' 88 ,8P' o88 88 8D 88 8D\n"
|
|
"8P 88ooo88 88 88V8o 88 8P d8' `8bd8' 88,8P 88 `VoooY' `VoooY'\n"
|
|
"8b 88~~~88 88 88 V8o88 8b d8' 88 88`8b 88 .d~~~b. .d~~~b.\n"
|
|
"Y8b d8 88 88 .88. 88 V888 Y8b d8 d8' db 88 88 `88. 88 88 8D 88 8D\n"
|
|
" `Y88P' YP YP Y888888P VP V8P `Y88P' d88888P YP YP YD VP `Y888P' `Y888P'\n"
|
|
"\n";
|
|
|
|
std::cout << "Witaj w Chinczyku!\nAutor: B.Z. (2 EF-DI, L01, 177188)\n";
|
|
std::cout << "Kod zrodlowy: https://gitea.7o7.cx/sherl/Chinczyk188 na licencji GPLv3\n";
|
|
std::cout << "Instrukcja gry powinna zostac dolaczona do tej kopii gry, w przeciwnym razie\n"
|
|
"jest ona dostepna w repozytorium git.\n\n";
|
|
|
|
}
|
|
|
|
void Game::readLeaderboards(std::string leaderboardLocation) {
|
|
|
|
try {
|
|
|
|
// Spróbuj wczytać plik z zapisanymi wynikami
|
|
ss::parser<ss::throw_on_error> p{leaderboardLocation, " "};
|
|
|
|
for (const auto& [csvName, csvWins]: p.iterate<std::string, unsigned int>()) {
|
|
this->leaderboardName.push_back(csvName);
|
|
this->leaderboardWins.push_back(csvWins);
|
|
}
|
|
|
|
}
|
|
catch (ss::exception& e) {
|
|
|
|
// Jeżeli nie udało się wczytać pliku, spróbuj wczytać kopię zapasową
|
|
if (std::filesystem::exists("." + leaderboardLocation + ".old")) {
|
|
|
|
ss::parser<ss::throw_on_error> p{"." + leaderboardLocation + ".old", " "};
|
|
|
|
for (const auto& [csvName, csvWins]: p.iterate<std::string, unsigned int>()) {
|
|
this->leaderboardName.push_back(csvName);
|
|
this->leaderboardWins.push_back(csvWins);
|
|
}
|
|
|
|
// Przekopiuj po cichu (verbose=false) dane do pliku głównego
|
|
this->dumpLeaderboards(leaderboardLocation, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::cerr << "Wystapil blad przy probie wczytania listy wynikow. \n"
|
|
"Gra sprobuje naprawic blad poprzez utworzenie nowego pliku z lista wynikow.\n"
|
|
"Nacisnij CTRL+C w przeciagu 10 sekund aby anulowac i wyjsc z programu.\n";
|
|
sf::sleep(sf::seconds(15));
|
|
|
|
// Utwórz plik
|
|
std::ofstream leaderboardFile;
|
|
leaderboardFile.open(leaderboardLocation);
|
|
leaderboardFile << "\n";
|
|
leaderboardFile.close();
|
|
|
|
// Przykładowe dane
|
|
this->leaderboardName.push_back("Anonymous");
|
|
this->leaderboardWins.push_back(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Game::dumpLeaderboards(std::string leaderboardLocation, bool verbose) const {
|
|
|
|
// Otwórz strumień wyjściowy do ścieżki leaderboardLocation
|
|
std::ofstream leaderboardFile;
|
|
leaderboardFile.open(leaderboardLocation);
|
|
for (int i = 0; i < (this->leaderboardName.size() & this->leaderboardWins.size()); i++) {
|
|
// Zapisz dane z wektora w formacie csv, spacja to separator
|
|
leaderboardFile << this->leaderboardName[i] << " " << this->leaderboardWins[i] << "\n";
|
|
}
|
|
leaderboardFile.close();
|
|
|
|
// Zmienna verbose decyduje o tym, czy chcemy wyświetlić komunikat o zapisie
|
|
if (verbose) std::cout << "Zapisano dane do pliku " << leaderboardLocation << ".\n";
|
|
|
|
}
|
|
|
|
unsigned int Game::updateLeaderboards(std::string winnerNickname) {
|
|
|
|
bool updated = false;
|
|
unsigned int totalWins = 0;
|
|
|
|
for (int i = 0; i < (this->leaderboardName.size() & this->leaderboardWins.size()); i++) {
|
|
|
|
// Szukaj nick we wczytanych danych z pliku CSV
|
|
if (this->leaderboardName[i] == winnerNickname) {
|
|
|
|
totalWins = ++this->leaderboardWins[i];
|
|
updated = true;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!updated) {
|
|
// Jeżeli to pierwsza wygrana tego gracza, to dodaj go do wektora
|
|
this->leaderboardName.push_back(winnerNickname);
|
|
this->leaderboardWins.push_back(1);
|
|
totalWins = 1;
|
|
}
|
|
|
|
// Zapisz po cichu zmiany do obu plików CSV
|
|
this->dumpLeaderboards(LEADERBOARD_FILE, false);
|
|
this->dumpLeaderboards(std::string(".") + LEADERBOARD_FILE + std::string(".old"), false);
|
|
|
|
return totalWins;
|
|
}
|
|
|
|
void Game::printLeaderboards() const {
|
|
|
|
// Zamienia dwa wektory w parę wektorów
|
|
// https://stackoverflow.com/a/18479184
|
|
std::vector<std::pair<std::string, int>> vectorPair(this->leaderboardName.size());
|
|
for (unsigned int i = 0; i < vectorPair.size(); i++) {
|
|
vectorPair[i] = std::make_pair(this->leaderboardName[i], this->leaderboardWins[i]);
|
|
}
|
|
|
|
// Sortuje malejąco parę wektorów biorąc pod uwagę wartości w tym drugim
|
|
// https://stackoverflow.com/a/279878
|
|
std::sort(vectorPair.begin(), vectorPair.end(), [](auto &left, auto &right) {
|
|
return left.second > right.second;
|
|
});
|
|
|
|
for (const auto& [name, wins]: vectorPair) {
|
|
std::cout << "- " << name << ", " << wins << " wygranych\n";
|
|
}
|
|
|
|
}
|
|
|
|
void Game::playStartTune() {
|
|
|
|
// Jeżli plik welcome_alt.ogg istnieje, załaduj go, a potem odtwórz.
|
|
if (!this->soundBuffer1.openFromFile("res/audio/welcome_alt.ogg"))
|
|
return;
|
|
|
|
// Aby dało się usłyszeć dźwięk, nie może on wyjść poza zakres (out of scope).
|
|
// Z tego powodu zapisujemy odnośnik do bufora w pamięci programu (w klasie Game).
|
|
this->soundBuffer1.play();
|
|
|
|
}
|
|
|
|
void Game::initVariables() {
|
|
|
|
// Ustaw wartości na domyślne.
|
|
this->leaderboardLocation = LEADERBOARD_FILE;
|
|
|
|
// Spróbuj wczytać listę wyników z pliku
|
|
this->readLeaderboards(leaderboardLocation);
|
|
// Zapisz po cichu (stąd false) kopię zapasową listy wyników
|
|
this->dumpLeaderboards("." + leaderboardLocation + ".old", false);
|
|
|
|
}
|
|
|
|
Game::Game() {
|
|
//:
|
|
// thread(std::thread([this]() {
|
|
// while (this->running()) {
|
|
// this->update();
|
|
// this->render();
|
|
// sf::sleep(sf::milliseconds(100));
|
|
// } })) {
|
|
|
|
// Konstruktor klasy. Klasę Game tworzymy poprzez
|
|
// ustawienie domyślnych wartości i stworzenie okna.
|
|
|
|
this->initVariables();
|
|
this->board.initVariables();
|
|
this->board.initWindow();
|
|
this->board.initBoard();
|
|
this->board.initView(); // widok musi być zainicjalizowany po oknie
|
|
|
|
// Puść melodyjkę
|
|
this->playStartTune();
|
|
|
|
// Wyświetl witający tekst
|
|
this->printGameWelcomeText();
|
|
|
|
}
|
|
|
|
Game::~Game() {
|
|
|
|
// W destruktorze zapisujemy dane i usuwamy okno.
|
|
this->dumpLeaderboards();
|
|
|
|
}
|
|
|
|
const bool Game::running() const {
|
|
|
|
// Akcesor dla isOpen()
|
|
//return this->window->isOpen();
|
|
return this->board.running();
|
|
|
|
}
|
|
|
|
void Game::run() {
|
|
|
|
Engine engine;
|
|
board.updateAndRender();
|
|
|
|
// this->update();
|
|
// this->render();
|
|
|
|
int numPlayers = 2;
|
|
std::cout << "Podaj prosze liczbe graczy (2-4):\n> ";
|
|
// std::cin >> numPlayers;
|
|
numPlayers = stoi(board.asyncStrCin());
|
|
std::cout << "\n";
|
|
|
|
if (numPlayers < 2) numPlayers = 2;
|
|
if (numPlayers > 4) numPlayers = 4;
|
|
|
|
const char* colorNames[] = {"czerwony", "niebieski", "zolty", "zielony"};
|
|
// Uzyskaj dane o użytkownikach
|
|
for (int i = 0; i < numPlayers; i++) {
|
|
|
|
std::string name;
|
|
std::string str_seed = std::to_string(std::time(nullptr)); // czas
|
|
|
|
std::cout << "Wpisz nazwe gracza " << (i + 1) << " (" << colorNames[i] << "): ";
|
|
//std::cin >> name;
|
|
name = board.asyncStrCin();
|
|
|
|
// Zignoruj zawartość bufora do \n, aby zapobiec nadpisywaniu ziarna
|
|
// poprzez podanie nazwy ze znakami białymi.
|
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
|
|
#ifndef CHINCZYK188_IGNORE_USER_SEED
|
|
// Jeżeli nie została zdefiniowana flaga do ignorowania ziarna użytkownika
|
|
// (deterministyczne losowanie), to pozwól na wprowadzanie ziaren.
|
|
std::cout << "Wpisz ziarno gracza " << (i + 1) << " (" << colorNames[i] << "): ";
|
|
str_seed = board.asyncStrCin();
|
|
// std::cin >> str_seed;
|
|
#endif
|
|
std::cout << "\n";
|
|
|
|
short color = static_cast<short>(i);
|
|
unsigned int seed = std::hash<std::string_view>{}(str_seed);
|
|
engine.addPlayer(name, seed, color);
|
|
|
|
board.updateAndRender();
|
|
|
|
// Podobnie, jak wyżej
|
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
|
|
}
|
|
|
|
// Przekaż ev i window, aby obsługiwać zdarzenia
|
|
// w Engine
|
|
engine.startGame(this->board);
|
|
|
|
// Główna pętla gry
|
|
while (board.running()) {
|
|
|
|
board.updateAndRender();
|
|
// this->update(); // do threadów
|
|
//this->render();
|
|
|
|
if (!engine.isGameOver()) {
|
|
engine.nextTurn();
|
|
} else {
|
|
|
|
// updateLeaderboard() inkrementuje i zwraca liczbę wygranych przekazanego gracza
|
|
std::cout << "To jego(/jej) "
|
|
<< updateLeaderboards(engine.winnerNickname) << ". wygrana!\n";
|
|
|
|
std::cout << "--------------------\n\n"
|
|
<< "Statystyki:\n";
|
|
this->printLeaderboards();
|
|
std::cout << "\n";
|
|
|
|
// Zapisz do pliku CSV
|
|
this->dumpLeaderboards(this->leaderboardLocation);
|
|
this->dumpLeaderboards("." + this->leaderboardLocation + ".old", false);
|
|
|
|
this->board.smartSleep(10000);
|
|
|
|
board.closeWindow();
|
|
|
|
}
|
|
|
|
}
|
|
} |