On second thoughts move filesystem game code out to a filesystem cpp
This commit is contained in:
parent
0962546a82
commit
8835bfb82a
6 changed files with 234 additions and 227 deletions
|
@ -13,6 +13,7 @@ set( SOURCES
|
||||||
client.cpp
|
client.cpp
|
||||||
server.cpp
|
server.cpp
|
||||||
net.cpp
|
net.cpp
|
||||||
|
filesystem.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set defaults for ttrts variables
|
# Set defaults for ttrts variables
|
||||||
|
|
222
source/client/filesystem.cpp
Normal file
222
source/client/filesystem.cpp
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#include "filesystem.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <formatters.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// time for waiting between file stats
|
||||||
|
static const std::chrono::milliseconds sk_waitTime = std::chrono::milliseconds(100);
|
||||||
|
|
||||||
|
// Check if a file exists
|
||||||
|
inline bool FileExists( const std::string& name )
|
||||||
|
{
|
||||||
|
struct stat buffer;
|
||||||
|
return (stat (name.c_str(), &buffer) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for a file to exist
|
||||||
|
inline void WaitForFile( const std::string& name, const std::chrono::milliseconds& time )
|
||||||
|
{
|
||||||
|
while( !FileExists(name) ) std::this_thread::sleep_for(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutputGameStateFile(CTTRTSGame &game, const std::string &gameDir)
|
||||||
|
{
|
||||||
|
char turnFileName[128];
|
||||||
|
snprintf(turnFileName,128,"%s/Turn_%i.txt",gameDir.c_str(),game.GetTurn());
|
||||||
|
std::ofstream turnFile(turnFileName, std::ios_base::trunc); // truncate to overwrite if a file exists
|
||||||
|
|
||||||
|
if ( turnFile.bad() )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the turn description
|
||||||
|
std::string turnDescriptor = GetStringFromGame(game);
|
||||||
|
|
||||||
|
turnFile<<turnDescriptor;
|
||||||
|
turnFile.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int runFromFilesystem( const std::string& directory, const std::string gamefile )
|
||||||
|
{
|
||||||
|
|
||||||
|
std::ifstream file(gamefile);
|
||||||
|
|
||||||
|
std::cout<<"Launching TTRTS with "<<gamefile<<std::endl;
|
||||||
|
|
||||||
|
std::string gameDescriptor;
|
||||||
|
|
||||||
|
// Reserve the string needed up front
|
||||||
|
file.seekg(0, std::ios::end);
|
||||||
|
gameDescriptor.reserve(file.tellg());
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// Grab the string from the file
|
||||||
|
gameDescriptor.assign((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
if( gameDescriptor.size() == 0 )
|
||||||
|
{
|
||||||
|
std::cerr<<"Error: failed to read in any information from "<<gamefile<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the game
|
||||||
|
CTTRTSGame game = GetGameFromString(gameDescriptor);
|
||||||
|
|
||||||
|
// Grab the players involved
|
||||||
|
auto players = game.GetPlayers();
|
||||||
|
|
||||||
|
// Current game directory
|
||||||
|
std::string gameDir = directory + game.GetName();
|
||||||
|
|
||||||
|
// Empty the current game directory
|
||||||
|
struct stat info;
|
||||||
|
int ret = stat( gameDir.c_str(), &info );
|
||||||
|
if( ret == 0 && info.st_mode & S_IFDIR )
|
||||||
|
{
|
||||||
|
std::cout<< gameDir << " game directory already exists"<<std::endl;
|
||||||
|
std::cout<<"Confirm to delete contents [y/N] ";
|
||||||
|
std::string input;
|
||||||
|
std::cin>>input;
|
||||||
|
if( !input.size() || std::tolower(input[0]) != 'y' )
|
||||||
|
{
|
||||||
|
std::cerr<<"Aborting..."<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ret == 0 )
|
||||||
|
{
|
||||||
|
std::cerr<< gameDir << " exists but is not directory \nAborting..."<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the game directory
|
||||||
|
char cmd2[128];
|
||||||
|
snprintf(cmd2,128, "test -d %s || mkdir %s",gameDir.c_str(),gameDir.c_str());
|
||||||
|
if( system(cmd2) == -1)
|
||||||
|
{
|
||||||
|
std::cerr<<"Error: Failed to create the game directory"<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean out the game directory
|
||||||
|
char cmd1[128];
|
||||||
|
snprintf(cmd1,128, "rm -rf %s/*",gameDir.c_str());
|
||||||
|
if ( system(cmd1) == -1 )
|
||||||
|
{
|
||||||
|
std::cerr<<"Error: Failed to clean the game directory"<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While the game isn't finished
|
||||||
|
while ( ! game.GameOver() )
|
||||||
|
{
|
||||||
|
std::cout<<"Starting turn "<<game.GetTurn()<<std::endl;
|
||||||
|
|
||||||
|
// Create a turn file
|
||||||
|
if( !OutputGameStateFile(game, gameDir))
|
||||||
|
{
|
||||||
|
std::cerr<<"Error: Failed to output new turn file" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for order files
|
||||||
|
for( player_t player : players)
|
||||||
|
{
|
||||||
|
// Construct the player order filename
|
||||||
|
char playerOrderFileName[128];
|
||||||
|
snprintf(playerOrderFileName, 128, "%s/Player_%i_Turn_%i.txt", gameDir.c_str(), (int) player, game.GetTurn());
|
||||||
|
|
||||||
|
// Wait for the player order file to be created
|
||||||
|
std::cout<<"Waiting for "<< playerOrderFileName <<std::endl;
|
||||||
|
bool hasOrderFile = false;
|
||||||
|
while(!hasOrderFile)
|
||||||
|
{
|
||||||
|
WaitForFile(playerOrderFileName,sk_waitTime); // Wait for the file
|
||||||
|
|
||||||
|
// File must have END
|
||||||
|
// Method taken from http://stackoverflow.com/questions/11876290/c-fastest-way-to-read-only-last-line-of-text-file
|
||||||
|
std::ifstream turnFile(playerOrderFileName);
|
||||||
|
turnFile.seekg(-1,std::ios_base::end);
|
||||||
|
|
||||||
|
// Loop back from the end of file
|
||||||
|
bool keepLooping = true;
|
||||||
|
while(keepLooping) {
|
||||||
|
char ch;
|
||||||
|
turnFile.get(ch); // Get current byte's data
|
||||||
|
|
||||||
|
if((int)turnFile.tellg() <= 1) { // If the data was at or before the 0th byte
|
||||||
|
turnFile.seekg(0); // The first line is the last line
|
||||||
|
keepLooping = false; // So stop there
|
||||||
|
}
|
||||||
|
else if(ch == '\n') { // If the data was a newline
|
||||||
|
keepLooping = false; // Stop at the current position.
|
||||||
|
}
|
||||||
|
else { // If the data was neither a newline nor at the 0 byte
|
||||||
|
turnFile.seekg(-2,std::ios_base::cur); // Move to the front of that data, then to the front of the data before it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab this line
|
||||||
|
std::string lastLine;
|
||||||
|
std::getline(turnFile,lastLine);
|
||||||
|
if(lastLine == "END")
|
||||||
|
hasOrderFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream turnFile(playerOrderFileName);
|
||||||
|
|
||||||
|
// Reserve the full order string
|
||||||
|
std::string orders;
|
||||||
|
turnFile.seekg(0, std::ios::end);
|
||||||
|
orders.reserve(turnFile.tellg());
|
||||||
|
turnFile.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// Grab the string from the file
|
||||||
|
orders.assign((std::istreambuf_iterator<char>(turnFile)),std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
// Issue the orders to the game
|
||||||
|
if( game.IssueOrders(player, orders) )
|
||||||
|
std::cerr<<"Warning: Orders for player "<<(int) player <<" failed to correctly parse"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate turn
|
||||||
|
std::cout<<"Simulating this turn!"<<std::endl;
|
||||||
|
if ( game.SimulateToNextTurn() )
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Failed to simulate for turn "<<game.GetTurn()<<std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output final gamestate
|
||||||
|
OutputGameStateFile(game, gameDir);
|
||||||
|
|
||||||
|
// Get the winning player
|
||||||
|
player_t winningPlayer = game.GetWinningPlayer();
|
||||||
|
|
||||||
|
// Print the winner!
|
||||||
|
if ( winningPlayer != player_t::NUM_INVALID )
|
||||||
|
{
|
||||||
|
std::cout<<"Game over! Winner:"<<(int) winningPlayer <<std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout<<"Game over! It was a draw!"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)winningPlayer;
|
||||||
|
}
|
8
source/client/filesystem.h
Normal file
8
source/client/filesystem.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef _TTRTS_FILESYSTEM_H_
|
||||||
|
#define _TTRTS_FILESYSTEM_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int runFromFilesystem( const std::string& directory, const std::string gamefile );
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "server.h"
|
#include "filesystem.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -60,6 +60,6 @@ int main(int argc, char* argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return runServer(ttrts_games_dir, gameFile);
|
return runFromFilesystem(ttrts_games_dir, gameFile);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,221 +1 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <formatters.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// time for waiting between file stats
|
|
||||||
static const std::chrono::milliseconds sk_waitTime = std::chrono::milliseconds(100);
|
|
||||||
|
|
||||||
// Check if a file exists
|
|
||||||
inline bool FileExists( const std::string& name )
|
|
||||||
{
|
|
||||||
struct stat buffer;
|
|
||||||
return (stat (name.c_str(), &buffer) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for a file to exist
|
|
||||||
inline void WaitForFile( const std::string& name, const std::chrono::milliseconds& time )
|
|
||||||
{
|
|
||||||
while( !FileExists(name) ) std::this_thread::sleep_for(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OutputGameStateFile(CTTRTSGame &game, const std::string &gameDir)
|
|
||||||
{
|
|
||||||
char turnFileName[128];
|
|
||||||
snprintf(turnFileName,128,"%s/Turn_%i.txt",gameDir.c_str(),game.GetTurn());
|
|
||||||
std::ofstream turnFile(turnFileName, std::ios_base::trunc); // truncate to overwrite if a file exists
|
|
||||||
|
|
||||||
if ( turnFile.bad() )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the turn description
|
|
||||||
std::string turnDescriptor = GetStringFromGame(game);
|
|
||||||
|
|
||||||
turnFile<<turnDescriptor;
|
|
||||||
turnFile.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int runServer(const std::string& ttrts_dir,const std::string& gameFile)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::ifstream file(gameFile);
|
|
||||||
|
|
||||||
std::cout<<"Launching TTRTS with "<<gameFile<<std::endl;
|
|
||||||
|
|
||||||
std::string gameDescriptor;
|
|
||||||
|
|
||||||
// Reserve the string needed up front
|
|
||||||
file.seekg(0, std::ios::end);
|
|
||||||
gameDescriptor.reserve(file.tellg());
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
// Grab the string from the file
|
|
||||||
gameDescriptor.assign((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
if( gameDescriptor.size() == 0 )
|
|
||||||
{
|
|
||||||
std::cerr<<"Error: failed to read in any information from "<<gameFile<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the game
|
|
||||||
CTTRTSGame game = GetGameFromString(gameDescriptor);
|
|
||||||
|
|
||||||
// Grab the players involved
|
|
||||||
auto players = game.GetPlayers();
|
|
||||||
|
|
||||||
// Current game directory
|
|
||||||
std::string gameDir = ttrts_dir + game.GetName();
|
|
||||||
|
|
||||||
// Empty the current game directory
|
|
||||||
struct stat info;
|
|
||||||
int ret = stat( gameDir.c_str(), &info );
|
|
||||||
if( ret == 0 && info.st_mode & S_IFDIR )
|
|
||||||
{
|
|
||||||
std::cout<< gameDir << " game directory already exists"<<std::endl;
|
|
||||||
std::cout<<"Confirm to delete contents [y/N] ";
|
|
||||||
std::string input;
|
|
||||||
std::cin>>input;
|
|
||||||
if( !input.size() || std::tolower(input[0]) != 'y' )
|
|
||||||
{
|
|
||||||
std::cerr<<"Aborting..."<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( ret == 0 )
|
|
||||||
{
|
|
||||||
std::cerr<< gameDir << " exists but is not directory \nAborting..."<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the game directory
|
|
||||||
char cmd2[128];
|
|
||||||
snprintf(cmd2,128, "test -d %s || mkdir %s",gameDir.c_str(),gameDir.c_str());
|
|
||||||
if( system(cmd2) == -1)
|
|
||||||
{
|
|
||||||
std::cerr<<"Error: Failed to create the game directory"<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean out the game directory
|
|
||||||
char cmd1[128];
|
|
||||||
snprintf(cmd1,128, "rm -rf %s/*",gameDir.c_str());
|
|
||||||
if ( system(cmd1) == -1 )
|
|
||||||
{
|
|
||||||
std::cerr<<"Error: Failed to clean the game directory"<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// While the game isn't finished
|
|
||||||
while ( ! game.GameOver() )
|
|
||||||
{
|
|
||||||
std::cout<<"Starting turn "<<game.GetTurn()<<std::endl;
|
|
||||||
|
|
||||||
// Create a turn file
|
|
||||||
if( !OutputGameStateFile(game, gameDir))
|
|
||||||
{
|
|
||||||
std::cerr<<"Error: Failed to output new turn file" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for order files
|
|
||||||
for( player_t player : players)
|
|
||||||
{
|
|
||||||
// Construct the player order filename
|
|
||||||
char playerOrderFileName[128];
|
|
||||||
snprintf(playerOrderFileName, 128, "%s/Player_%i_Turn_%i.txt", gameDir.c_str(), (int) player, game.GetTurn());
|
|
||||||
|
|
||||||
// Wait for the player order file to be created
|
|
||||||
std::cout<<"Waiting for "<< playerOrderFileName <<std::endl;
|
|
||||||
bool hasOrderFile = false;
|
|
||||||
while(!hasOrderFile)
|
|
||||||
{
|
|
||||||
WaitForFile(playerOrderFileName,sk_waitTime); // Wait for the file
|
|
||||||
|
|
||||||
// File must have END
|
|
||||||
// Method taken from http://stackoverflow.com/questions/11876290/c-fastest-way-to-read-only-last-line-of-text-file
|
|
||||||
std::ifstream turnFile(playerOrderFileName);
|
|
||||||
turnFile.seekg(-1,std::ios_base::end);
|
|
||||||
|
|
||||||
// Loop back from the end of file
|
|
||||||
bool keepLooping = true;
|
|
||||||
while(keepLooping) {
|
|
||||||
char ch;
|
|
||||||
turnFile.get(ch); // Get current byte's data
|
|
||||||
|
|
||||||
if((int)turnFile.tellg() <= 1) { // If the data was at or before the 0th byte
|
|
||||||
turnFile.seekg(0); // The first line is the last line
|
|
||||||
keepLooping = false; // So stop there
|
|
||||||
}
|
|
||||||
else if(ch == '\n') { // If the data was a newline
|
|
||||||
keepLooping = false; // Stop at the current position.
|
|
||||||
}
|
|
||||||
else { // If the data was neither a newline nor at the 0 byte
|
|
||||||
turnFile.seekg(-2,std::ios_base::cur); // Move to the front of that data, then to the front of the data before it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab this line
|
|
||||||
std::string lastLine;
|
|
||||||
std::getline(turnFile,lastLine);
|
|
||||||
if(lastLine == "END")
|
|
||||||
hasOrderFile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream turnFile(playerOrderFileName);
|
|
||||||
|
|
||||||
// Reserve the full order string
|
|
||||||
std::string orders;
|
|
||||||
turnFile.seekg(0, std::ios::end);
|
|
||||||
orders.reserve(turnFile.tellg());
|
|
||||||
turnFile.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
// Grab the string from the file
|
|
||||||
orders.assign((std::istreambuf_iterator<char>(turnFile)),std::istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
// Issue the orders to the game
|
|
||||||
if( game.IssueOrders(player, orders) )
|
|
||||||
std::cerr<<"Warning: Orders for player "<<(int) player <<" failed to correctly parse"<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate turn
|
|
||||||
std::cout<<"Simulating this turn!"<<std::endl;
|
|
||||||
if ( game.SimulateToNextTurn() )
|
|
||||||
{
|
|
||||||
std::cerr << "Error: Failed to simulate for turn "<<game.GetTurn()<<std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output final gamestate
|
|
||||||
OutputGameStateFile(game, gameDir);
|
|
||||||
|
|
||||||
// Get the winning player
|
|
||||||
player_t winningPlayer = game.GetWinningPlayer();
|
|
||||||
|
|
||||||
// Print the winner!
|
|
||||||
if ( winningPlayer != player_t::NUM_INVALID )
|
|
||||||
{
|
|
||||||
std::cout<<"Game over! Winner:"<<(int) winningPlayer <<std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout<<"Game over! It was a draw!"<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)winningPlayer;
|
|
||||||
}
|
|
|
@ -1,8 +1,4 @@
|
||||||
#ifndef _TTRTS_SERVER_H_
|
#ifndef _TTRTS_SERVER_H_
|
||||||
#define _TTRTS_SERVER_H_
|
#define _TTRTS_SERVER_H_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
int runServer(const std::string& dir,const std::string& file);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Add table
Reference in a new issue