├── .gitignore ├── Makefile ├── README.md ├── inc ├── chromosome.h ├── compactGA.h └── pirateGame.h └── src ├── chromosome.cpp ├── compactGA.cpp ├── main.cpp └── pirateGame.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | pirate_game 31 | 32 | # Sublime stuffs 33 | *.sublime* 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | CC = g++ 4 | CPPFLAGS = -O3 -Wall -std=c++11 5 | INCLUDE = -Iinc 6 | 7 | FLAGS = $(CPPFLAGS) $(INCLUDE) 8 | SRC = $(wildcard src/*.cpp) 9 | OBJ = $(SRC:.cpp=.o) 10 | 11 | all: pirate_game 12 | 13 | pirate_game: $(OBJ) 14 | $(CC) $(FLAGS) $(OBJ) -o $@ 15 | 16 | $(OBJ): src/%.o : src/%.cpp 17 | $(CC) $(FLAGS) -c $< -o $@ 18 | 19 | clean: 20 | @rm -rf src/*.o pirate_game 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GT_Project 2 | Pirate game using Genetic Algorithm 3 | -------------------------------------------------------------------------------- /inc/chromosome.h: -------------------------------------------------------------------------------- 1 | #ifndef _CHROMOSOME_ 2 | #define _CHROMOSOME_ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Chromosome 10 | { 11 | public: 12 | Chromosome() {}; 13 | void init(int, int, int, int); 14 | vector geneDecode(); 15 | void distribute(int, int, vector&); 16 | bool vote(int, const vector&); 17 | void setGenes(const vector< vector >&); 18 | 19 | int _order; // 1 is the smallest 20 | int _precision; 21 | int _nGene; 22 | int _nPlayers; 23 | int _nRes; 24 | int _gameResult; 25 | vector< vector > _genes; //[distribute value[_order-1], vote strategy[_nplayers+1]] 26 | // double _fitness; 27 | }; 28 | 29 | #endif -------------------------------------------------------------------------------- /inc/compactGA.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMPACTGA_ 2 | #define _COMPACTGA_ 3 | 4 | #include 5 | #include 6 | #include "chromosome.h" 7 | 8 | using namespace std; 9 | 10 | class CompactGA 11 | { 12 | public: 13 | // CompactGA(int, int, int); // 14 | 15 | // Player, population size, genePrecision, resources, generation number 16 | void setParams(int, int, int, int, int, int); 17 | void runGA(); 18 | void printResult(ostream&); 19 | void printExpected(ostream&); 20 | void printBit(ostream&); 21 | 22 | void setPlayerNumber(int); 23 | void setPrecision(int); 24 | void setGeneration(int); 25 | void setPopSize(int); 26 | void setResNum(int); 27 | void setSimPopSize(int); 28 | 29 | protected: 30 | virtual void executeGame(vector&) = 0; 31 | void init(); 32 | void fitness(); 33 | void generate(); // generate new generation (reset genes of chromosome) 34 | bool checkTermCond(); 35 | 36 | int _popSize; 37 | int _nGeneration; 38 | int _nPlayers; 39 | int _nResources; 40 | int _genePrecision; 41 | int _maxPrec; // 2^_genePrecision 42 | int _simPopSize; 43 | 44 | vector< vector > _populations; 45 | vector< vector< vector > > _probVec; // probability vector to generate new chromosomes) 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /inc/pirateGame.h: -------------------------------------------------------------------------------- 1 | #ifndef _PIRATE_GAME_ 2 | #define _PIRATE_GAME_ 3 | 4 | #include "compactGA.h" 5 | 6 | class PirateGame : public CompactGA { 7 | protected: 8 | void executeGame(vector&); 9 | }; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/chromosome.cpp: -------------------------------------------------------------------------------- 1 | #include "chromosome.h" 2 | #include 3 | #include 4 | 5 | uniform_real_distribution uniRand(0.0, 1.0); 6 | default_random_engine generator(time(0)); 7 | 8 | void Chromosome::init(int order, int prec, int nPlayer, int nRes) { 9 | _order = order; 10 | _precision = prec; 11 | _nPlayers = nPlayer; 12 | _nRes = nRes; 13 | // _nGene = order + nPlayer; // order-1 + nPlayer+1 14 | _nGene = order; // fixed threshold 0.5, only depends on own obtained amount 15 | _genes.resize(_nGene); 16 | for(unsigned i = 0; i < _nGene; ++i) { 17 | _genes[i].resize(_precision); 18 | } 19 | } 20 | 21 | // convert gene to int num 22 | vector Chromosome::geneDecode() { 23 | vector ret; 24 | for(unsigned i = 0; i < _nGene; ++i) { 25 | int temp = 0; 26 | for(unsigned j = 0; j < _precision; ++j) { 27 | temp *= 2; 28 | temp += _genes[i][j]; 29 | } 30 | ret.push_back(temp); 31 | } 32 | return ret; 33 | } 34 | 35 | void Chromosome::distribute(int nRes, int maxPrec, vector& distr) { 36 | int tempRes = nRes; 37 | vector genes = geneDecode(); 38 | for(unsigned i = 0; i < _nPlayers - _order; ++i) { 39 | distr.push_back(0); 40 | } 41 | for(unsigned i = 0; i < _order - 1; ++i) { 42 | int temp = (double)tempRes*(double)genes[i]/(double)maxPrec+0.5; 43 | distr.push_back(temp); 44 | tempRes -= temp; 45 | } 46 | distr.push_back(tempRes); 47 | } 48 | 49 | // original version that consider the whole distribution 50 | // bool Chromosome::vote(int maxPrec, const vector& distr) { 51 | // vector genes = geneDecode(); 52 | // double value = 0; 53 | // double threshold = genes.back(); 54 | // for(unsigned i = 0; i < _nPlayers; ++i) { 55 | // value += (double)genes[i+_order-1] * (double)distr[i] / (double)maxPrec; 56 | // } 57 | // if(value >= threshold) return true; 58 | // return false; 59 | // } 60 | 61 | // version that one only considers his own obtained amount 62 | bool Chromosome::vote(int maxPrec, const vector& distr) { 63 | vector genes = geneDecode(); 64 | double value = (double)distr[_nPlayers-_order] / (double)_nRes; 65 | double threshold = (double)genes[_order-1] / (double)maxPrec; 66 | if(value >= threshold) return true; 67 | return false; 68 | } 69 | 70 | void Chromosome::setGenes(const vector< vector >& probVec) { 71 | // uniform_real_distribution uniRand(0.0, 1.0); 72 | // default_random_engine generator; 73 | for(int i = 0; i < _nGene; ++i) { 74 | for(int j = 0; j < _precision; ++j) { 75 | _genes[i][j] = (probVec[i][j] > uniRand(generator)) ? 1 : 0; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/compactGA.cpp: -------------------------------------------------------------------------------- 1 | #include "compactGA.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void CompactGA::setParams(int player, int pop, int pre, int res, int gen, int sim) { 8 | setPlayerNumber(player); 9 | setPopSize(pop); 10 | setPrecision(pre); 11 | setResNum(res); 12 | setGeneration(gen); 13 | setSimPopSize(sim); 14 | } 15 | 16 | void CompactGA::init() { 17 | _populations.resize(_nPlayers); 18 | _probVec.resize(_nPlayers); 19 | for(int i = 0; i < _nPlayers; ++i) { 20 | _populations[i].resize(_popSize); 21 | for(int j = 0; j < _popSize; ++j) { 22 | _populations[i][j].init(_nPlayers - i, _genePrecision, _nPlayers, _nResources); 23 | } 24 | // _probVec[i].resize(2 * _nPlayers - i); 25 | _probVec[i].resize(_nPlayers - i); 26 | for(int j = 0, size = _probVec[i].size(); j < size; ++j) { 27 | _probVec[i][j].resize(_genePrecision, 0.5); 28 | } 29 | } 30 | // _probVec[0][0][0] = 0; 31 | // _probVec[0][0][1] = 1; 32 | // _probVec[0][0][2] = 1; 33 | // _probVec[0][0][3] = 1; 34 | // _probVec[0][1][0] = 0; 35 | // _probVec[0][1][1] = 0; 36 | // _probVec[0][1][2] = 0; 37 | // _probVec[0][1][3] = 0; 38 | // _probVec[1][1][0] = 1; 39 | // _probVec[1][1][1] = 1; 40 | // _probVec[1][1][2] = 1; 41 | // _probVec[1][1][3] = 1; 42 | // _probVec[2][0][0] = 1; 43 | // _probVec[2][0][1] = 1; 44 | // _probVec[2][0][2] = 1; 45 | // _probVec[2][0][3] = 1; 46 | } 47 | 48 | void CompactGA::setPlayerNumber(int num) { 49 | _nPlayers = num; 50 | } 51 | 52 | void CompactGA::setPopSize(int pop) { 53 | assert(!(pop % 2)); 54 | _popSize = pop; 55 | } 56 | 57 | void CompactGA::setPrecision(int pre) { 58 | _genePrecision = pre; 59 | _maxPrec = pow(2, pre) - 1; 60 | } 61 | 62 | void CompactGA::setResNum(int res) { 63 | _nResources = res; 64 | } 65 | 66 | void CompactGA::setGeneration(int gen) { 67 | _nGeneration = gen; 68 | } 69 | 70 | void CompactGA::setSimPopSize(int sim) { 71 | _simPopSize = sim; 72 | } 73 | 74 | void CompactGA::generate() { 75 | for(unsigned i = 0; i < _nPlayers; ++i) { 76 | for(unsigned j = 0; j < _popSize; ++j) { 77 | _populations[i][j].setGenes(_probVec[i]); 78 | } 79 | } 80 | } 81 | 82 | bool CompactGA::checkTermCond() { 83 | for(int i = 0, s1 = _probVec.size(); i < s1; ++i) { 84 | for(int j = 0, s2 = _probVec[i].size(); j < s2; ++j) { 85 | for(int k = 0, s3 = _probVec[i][j].size(); k < s3; ++k) { 86 | //ignore convergence of vote stategy of top-ordered player 87 | if(i == 0 && j >= _nPlayers - 1) continue; 88 | if((_probVec[i][j][k] != 0.0) && (_probVec[i][j][k] != 1.0)) 89 | return false; 90 | } 91 | } 92 | } 93 | return true; 94 | } 95 | 96 | void CompactGA::runGA() { 97 | init(); 98 | int gendiv80 = _nGeneration/80; 99 | for(unsigned u = 0; u < _nGeneration; ++u) { 100 | if(checkTermCond()) break; 101 | generate(); 102 | for(unsigned j = 0; j < _popSize; ++j) { 103 | vector players; 104 | for(unsigned k = 0; k < _nPlayers; ++k) { 105 | players.push_back(&_populations[k][j]); 106 | } 107 | executeGame(players); 108 | } 109 | Chromosome *winner, *loser; 110 | for(unsigned i = 0; i < _nPlayers; ++i) { 111 | for(unsigned j = 0; j < _popSize; j += 2) { 112 | if(_populations[i][j]._gameResult == _populations[i][j+1]._gameResult) 113 | continue; 114 | if(_populations[i][j]._gameResult > _populations[i][j+1]._gameResult) { 115 | winner = &_populations[i][j]; 116 | loser = &_populations[i][j+1]; 117 | } else { 118 | winner = &_populations[i][j+1]; 119 | loser = &_populations[i][j]; 120 | } 121 | for(unsigned x = 0; x < winner->_nGene; ++x) { 122 | for(unsigned y = 0; y < _genePrecision; ++y) { 123 | if(winner->_genes[x][y] != loser->_genes[x][y]) { 124 | if(winner->_genes[x][y] == 1) { 125 | _probVec[i][x][y] += 1.0 / _simPopSize; 126 | if(_probVec[i][x][y] > 0.98) _probVec[i][x][y] = 0.98; 127 | } else { 128 | _probVec[i][x][y] -= 1.0 / _simPopSize; 129 | if(_probVec[i][x][y] < 0.02) _probVec[i][x][y] = 0.02; 130 | } 131 | if(_probVec[i][x][y] < 1.0 / _simPopSize) 132 | _probVec[i][x][y] = 0.0; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | // printCurrent(cout); 139 | if(u % gendiv80 == 0) cout << '='; 140 | cout.flush(); 141 | } 142 | cout << endl; 143 | } 144 | 145 | void CompactGA::printResult(ostream& out) { 146 | out << "total resources: " << _nResources << '\n'; 147 | for(int i = 0, s1 = _probVec.size(); i < s1; ++i) { 148 | int tempRes = _nResources; 149 | vector genes; 150 | genes.reserve(_nPlayers - i); 151 | // convert result bits to double 152 | for(int j = 0, s2 = _probVec[i].size(); j < s2; ++j) { 153 | double temp = 0; 154 | for(int k = 0, s3 = _probVec[i][j].size(); k < s3; ++k) { 155 | temp *= 2; 156 | temp += _probVec[i][j][k]; 157 | } 158 | genes.push_back(temp); 159 | } 160 | 161 | out << "Player" << i+1 << ":\n"; 162 | out << "distribute: "; 163 | 164 | // convert result to distribution 165 | for(unsigned j = 0; j < i; ++j) { 166 | out << "* "; 167 | } 168 | for(unsigned j = 0; j < _nPlayers-i-1; ++j) { 169 | int temp = (double)tempRes * genes[j] / (double)_maxPrec + 0.5; 170 | out << temp << ' '; 171 | tempRes -= temp; 172 | } 173 | out << tempRes << ' '; 174 | out << "\nthreshold: "; 175 | if(i == 0) out << "*\n"; 176 | else out << genes.back() / (double)_maxPrec << '\n'; 177 | } 178 | out.flush(); 179 | } 180 | 181 | void CompactGA::printExpected(ostream& out) { 182 | for(int i = 0, s1 = _probVec.size(); i < s1; ++i) { 183 | for(int j = 0, s2 = _probVec[i].size(); j < s2; ++j) { 184 | double temp = 0; 185 | for(int k = 0, s3 = _probVec[i][j].size(); k < s3; ++k) { 186 | temp *= 2; 187 | temp += _probVec[i][j][k]; 188 | // out << setprecision(3) << _probVec[i][j][k] << " "; 189 | } 190 | out << setprecision(3) << (double)temp / (double)_maxPrec << ' '; 191 | } 192 | out << "\n"; 193 | } 194 | out.flush(); 195 | } 196 | 197 | void CompactGA::printBit(ostream& out) { 198 | for(int i = 0, s1 = _probVec.size(); i < s1; ++i) { 199 | for(int j = 0, s2 = _probVec[i].size(); j < s2; ++j) { 200 | for(int k = 0, s3 = _probVec[i][j].size(); k < s3; ++k) { 201 | out << setprecision(3) << _probVec[i][j][k] << " "; 202 | } 203 | out << "\n"; 204 | } 205 | out << "\n"; 206 | } 207 | out.flush(); 208 | } 209 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "chromosome.h" 2 | #include "compactGA.h" 3 | #include "pirateGame.h" 4 | 5 | int main(int argc, char const *argv[]) { 6 | PirateGame game; 7 | // setParams(players, population, precision, resources, generation, simPop) 8 | game.setParams(3, 1000, 4, 50, 200000, 500); 9 | game.runGA(); 10 | game.printBit(cout); 11 | // game.printExpected(cout); 12 | game.printResult(cout); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /src/pirateGame.cpp: -------------------------------------------------------------------------------- 1 | #include "CompactGA.h" 2 | #include "pirateGame.h" 3 | 4 | void PirateGame::executeGame(vector& players) { 5 | for(unsigned i = 0; i < _nPlayers; ++i) { 6 | vector distribution; 7 | distribution.reserve(_nPlayers); 8 | 9 | //1 player left case 10 | if(i == _nPlayers - 1) { 11 | players[i]->_gameResult = _nResources; 12 | break; 13 | } 14 | 15 | //get distribution 16 | players[i]->distribute(_nResources, _maxPrec, distribution); 17 | 18 | //vote 19 | int nCount = 0; 20 | int pCount = 1; // 1 for self vote 21 | for(unsigned j = i + 1; j < _nPlayers; ++j) { 22 | if(players[j]->vote(_maxPrec, distribution)) ++pCount; 23 | else ++ nCount; 24 | } 25 | 26 | //result 27 | if(pCount >= nCount) { 28 | for(unsigned j = i; j < _nPlayers; ++j) { 29 | players[j]->_gameResult = distribution[j]; 30 | } 31 | break; 32 | } 33 | else players[i]->_gameResult = -1; //eliminated 34 | } 35 | } 36 | --------------------------------------------------------------------------------