Skip to content

Commit b2075ff

Browse files
committed
Imported into Microsoft Visual Studio
diff --git a/.gitignore b/.gitignore index a48f643..9f32482 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,362 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# Log files for saved players -*.log \ No newline at end of file +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o + +# Precompiled Headers +*.gch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + + + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ \ No newline at end of file diff --git a/Genetic.cpp b/Genetic.cpp index 4ebd56a..3d04407 100644 --- a/Genetic.cpp +++ b/Genetic.cpp @@ -1,6 +1,7 @@ #include "Genetic.h" + //mutationRate is in the range [0, 1], greedyPercent is in the range [0, 1] Genetic::Genetic(const float mutationRate, const float greedyPercent) : m_mutationRate(clamp(mutationRate, 0.0f, 1.0f)) @@ -15,7 +16,7 @@ void Genetic::setPopulationSize(int populationSize){ //Make new players based on how successful the current ones are void Genetic::breed(vector<playerContainer<NeuralPlayer> >& population){ vector<playerContainer<NeuralPlayer> > newPop; - newPop.resize(m_populationSize); + newPop.reserve(m_populationSize); //Keep the best greedyPercent of last generation int numToKeep = (int)(m_greedyPercent * (float)m_populationSize); @@ -25,18 +26,18 @@ void Genetic::breed(vector<playerContainer<NeuralPlayer> >& population){ //Copy the players which are being kept from greedyPercent for(int i = 0; i < numToKeep; ++i){ - newPop[i] = population[m_populationSize - 1 - i]; + newPop.push_back(population[m_populationSize - 1 - i]); } //Iterates over the remaining child elements for(int i = numToKeep; i < m_populationSize; ++i){ playerContainer<NeuralPlayer> parent1 = pickParent(population); playerContainer<NeuralPlayer> parent2 = pickParent(population); - vector<Matrix> newWeights = crossOver(parent1, parent2); + vector<MatrixXd> newWeights = crossOver(parent1, parent2); playerContainer<NeuralPlayer> temp(population[m_populationSize-1 - i]); temp.player.neural.setWeights(newWeights); - newPop[i] = temp; + newPop.push_back(temp); } population = newPop; } @@ -50,17 +51,17 @@ void Genetic::mutate(vector<playerContainer<NeuralPlayer> >& population){ int numToKeep = (int)(m_greedyPercent * (float)m_populationSize); for(int i = numToKeep; i < m_populationSize; ++i){ - vector<Matrix> weights = population[i].player.neural.getWeights(); + vector<MatrixXd> weights = population[i].player.neural.getWeights(); size_t layers = weights.size(); //For each layer for(size_t lay = 0; lay < layers; ++lay){ - int rows = weights[lay].numRows(); - int cols = weights[lay].numCols(); + int rows = weights[lay].rows(); + int cols = weights[lay].cols(); //Randomly mutate each element - for(int row = 0; row < rows; ++row){ - for(int col = 0; col < cols; ++col){ + for(int col = 0; col < cols; ++col){ + for(int row = 0; row < rows; ++row){ //Mutate with a certain chance if( ((float)rand() / float(RAND_MAX)) < m_mutationRate){ weights[lay](row, col) += distribution(gen); @@ -98,10 +99,10 @@ playerContainer<NeuralPlayer> Genetic::pickParent( return population.back(); } -vector<Matrix> Genetic::crossOver(const playerContainer<NeuralPlayer> parent1, - const playerContainer<NeuralPlayer> parent2){ - vector<Matrix> weights1; - vector<Matrix> weights2; +vector<MatrixXd> Genetic::crossOver(const playerContainer<NeuralPlayer>& parent1, + const playerContainer<NeuralPlayer>& parent2){ + vector<MatrixXd> weights1; + vector<MatrixXd> weights2; //Parent 1 weights1 = parent1.player.neural.getWeights(); @@ -111,12 +112,12 @@ vector<Matrix> Genetic::crossOver(const playerContainer<NeuralPlayer> parent1, //For each layer for(size_t i = 0; i < length; ++i){ - int rows = weights1[i].numRows(); - int cols = weights1[i].numCols(); + int rows = weights1[i].rows(); + int cols = weights1[i].cols(); //Cross breed matrix - for(int row = 0; row < rows; ++row){ - for(int col = 0; col < cols; ++col){ + for(int col = 0; col < cols; ++col){ + for(int row = 0; row < rows; ++row){ //50% chance of being from parent1 or parent2 if(rand() % 2 == 0){ weights1[i](row, col) = weights2[i](row, col); diff --git a/Genetic.h b/Genetic.h index 3c1563a..9d3ed76 100644 --- a/Genetic.h +++ b/Genetic.h @@ -4,7 +4,9 @@ #include <iostream> #include <random> -#include "Matrix.h" +#include <Eigen/Dense> +using namespace Eigen; + #include "NeuralNet.h" #include "Player.h" #include "main.h" @@ -24,8 +26,8 @@ public: void mutate(vector<playerContainer<NeuralPlayer> >& population); private: - vector<Matrix> crossOver(const playerContainer<NeuralPlayer> parent1, - const playerContainer<NeuralPlayer> parent2); + vector<MatrixXd> crossOver(const playerContainer<NeuralPlayer>& parent1, + const playerContainer<NeuralPlayer>& parent2); playerContainer<NeuralPlayer> pickParent( const vector<playerContainer<NeuralPlayer> >& population) const; diff --git a/Matrix.cpp b/Matrix.cpp deleted file mode 100644 index e445b7d..0000000 --- a/Matrix.cpp +++ /dev/null @@ -1,244 +0,0 @@ - -#include "Matrix.h" - - - - -//Size Constructor -Matrix::Matrix(const unsigned int rows, const unsigned int cols) - : m_rows(rows) - , m_cols(cols){ - if (rows == 0 || cols == 0){ - cerr << "Error: Matrix size constructor has 0 size" << endl; - exit(1); - } - m_data = new double[rows * cols]; -} - -//Copy constructor -Matrix::Matrix(const Matrix& m) - : m_rows(m.m_rows) - , m_cols(m.m_cols){ - if (m_rows <= 0 || m_cols <= 0){ - cerr << "Error: Matrix copy constructor has 0 size" << endl; - exit(1); - } - m_data = new double[m_rows * m_cols]; - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - m_data[m_cols * row + col] = m.m_data[m.m_cols * row + col]; - } - } -} - -//Sets all matrix elements to 'n' -void Matrix::initialize(const int n){ - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - m_data[m_cols * row + col] = n; - } - } -} - -vector<double> Matrix::toVector() const{ - vector<double> temp; - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp.push_back(m_data[m_cols * row + col]); - } - } - return temp; -} - -unsigned int Matrix::numRows() const{ - return m_rows; -} - -unsigned int Matrix::numCols() const{ - return m_cols; -} - -//Prints the matrix as a grid to the console -void Matrix::printData() const{ - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - printf("%9.4lf", m_data[m_cols * row + col]); - } - cout << endl; - } -} - -//Returns a copy of itself which is transposed -Matrix Matrix::transpose() const{ - Matrix temp(m_cols, m_rows); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp(col, row) = m_data[m_cols * row + col]; - } - } - return temp; -} - -//Destructor -Matrix::~Matrix(){ - delete[] m_data; -} - -//Override = operator to copy each element -void Matrix::operator= (const Matrix& m){ - if(m.numRows() != m_rows || m.numCols() != m_cols){ - cerr << "Error: Matrix sizes are not equivalent. Cannot perform \ - assignment." << endl; - exit(1); - } - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - m_data[m_cols * row + col] = m.m_data[m.m_cols * row + col]; - } - } -} - -//Override - (unary) operator to negate each element -Matrix Matrix::operator- () const{ - Matrix temp(m_rows, m_cols); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp(row, col) = -1 * m_data[m_cols * row + col]; - } - } - return temp; -} - -//Override + operator to add elementwise -Matrix Matrix::operator+ (const Matrix& a) const{ - if(a.numRows() != m_rows || a.numCols() != m_cols){ - cerr << "Error: Matrix sizes are not equivalent. Cannot perform \ - addition." << endl; - exit(1); - } - Matrix temp(m_rows, m_cols); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp(row, col) = a(row, col) + m_data[m_cols * row + col]; - } - } - return temp; -} - -//Override - operator to subtract elementwise -Matrix Matrix::operator- (const Matrix& a) const{ - if(a.numRows() != m_rows || a.numCols() != m_cols){ - cerr << "Error: Matrix sizes are not equivalent. Cannot perform \ - subtraction." << endl; - exit(1); - } - Matrix temp(m_rows, m_cols); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp(row, col) = m_data[m_cols * row + col] - a(row, col); - } - } - return temp; -} - -//Override * operator to multiply elementwise by a constant -Matrix Matrix::operator* (const int a) const{ - Matrix temp(m_rows, m_cols); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - temp(row, col) = a * m_data[m_cols * row + col]; - } - } - return temp; -} - -//Override * operator to perform standard matrix multiplication -Matrix Matrix::operator* (const Matrix& a) const{ - if(m_cols != a.numRows()){ - cerr << "Error: Matrix sizes are incompatible. Cannot perform \ - matrix multiplication." << endl; - exit(1); - } - Matrix temp(m_rows, a.m_cols); - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < a.m_cols; ++col){ - //perform cross product between current row and current column - temp(row, col) = 0; - for(unsigned int element = 0; element < m_cols; ++element){ - temp(row, col) += m_data[m_cols * row + element] - * a(element, col); - } - } - } - return temp; -} - -//Override () operator to allow access at a specific location -double& Matrix::operator() (const unsigned int row, const unsigned int col){ - if (row >= m_rows || col >= m_cols ){ - cerr << "Error: Matrix subscript out of bounds (too large)." << endl; - exit(1); - } - return m_data[m_cols * row + col]; -} - -//Override () operator to allow access at a specific location -double Matrix::operator() (const unsigned int row, - const unsigned int col) const{ - if (row >= m_rows || col >= m_cols){ - cerr << "Error: Matrix subscript out of bounds (too large)." << endl; - exit(1); - } - return m_data[m_cols * row + col]; -} - -//Sets each element to a random double in the range [min, max] with specified -//resolution -void Matrix::initRand(const double min, const double max, - const unsigned int resolution){ - if(min > max){ - cerr << "Error: initRand(): Min is larger than max." << endl; - exit(1); - } - if(resolution == 0){ - cerr << "Error: initRand(): Resolution is equal to 0" << endl; - exit(1); - } - for(unsigned int row = 0; row < m_rows; ++row){ - for(unsigned int col = 0; col < m_cols; ++col){ - /* resolution represents how many pieces each (int) is broken into. - * bound is used because we can generate ints better than doubles. - * bound is the product of the total range * resolution. - * Afterward, we divide bound by resolution to get a double. - */ - int bound = (int)( (double)resolution * (max - min) ); - //The double value is created by dividing bound by resolution - double randDouble = min + (double)(rand() % bound) / resolution; - //Passed into the matrix - m_data[m_cols * row + col] = randDouble; - } - } -} - -Matrix Matrix::addRowsCols(unsigned int extraRows, unsigned int extraCols, - const double value){ - unsigned int newRows = m_rows + extraRows; - unsigned int newCols = m_cols + extraCols; - Matrix temp(newRows, newCols); - - for(unsigned int row = 0; row < newRows; ++row){ - for(unsigned int col = 0; col < newCols; ++col){ - if(row < m_rows && col < m_cols){ - temp(row, col) = m_data[m_cols * row + col]; - } else{ - temp(row, col) = value; - } - } - } - return temp; -} - - - - - diff --git a/Matrix.h b/Matrix.h deleted file mode 100644 index 3e04666..0000000 --- a/Matrix.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MATRIX_H -#define MATRIX_H - -#include <stdexcept> -#include <vector> -#include <iostream> -#include <time.h> -#include <stdlib.h> -#include <stdio.h> - -using std::cout; -using std::cin; -using std::cerr; -using std::endl; -using std::vector; - -class Matrix { -public: - Matrix(const unsigned int rows, const unsigned int cols); - Matrix(const Matrix& m); - ~Matrix(); - - double& operator() (const unsigned int row, const unsigned int col); - double operator() (const unsigned int row, const unsigned int col) const; - void operator= (const Matrix& m); - - std::vector<double> toVector() const; - - unsigned int numRows() const; - unsigned int numCols() const; - void printData() const; - - Matrix operator- () const; - Matrix operator+ (const Matrix& a) const; - Matrix operator- (const Matrix& a) const; - Matrix operator* (const int a) const; - Matrix operator* (const Matrix& a) const; - - Matrix transpose() const; - void initialize(const int n); - void initRand(const double min, const double max, - const unsigned int resolution=20); - - Matrix addRowsCols(unsigned int extraRows, unsigned int extraCols, - const double value); - -private: - unsigned int m_rows, m_cols; - double* m_data; -}; - -#endif diff --git a/NeuralNet.cpp b/NeuralNet.cpp index d86037e..e0865af 100644 --- a/NeuralNet.cpp +++ b/NeuralNet.cpp @@ -9,11 +9,12 @@ NeuralNet::NeuralNet(){ //Constructor takes in the structure of the network as a matrix NeuralNet::NeuralNet(const vector<unsigned int>& layerSizes) : m_layerSizes(layerSizes){ + unsigned int numLayers = layerSizes.size() - 1; + m_weights.reserve(numLayers); + //Create vectors for weights. Each entry is a matrix for that layer - for(unsigned int i = 0; i < layerSizes.size() - 1; ++i){ - Matrix tempWeight(layerSizes[i] + 1, layerSizes[i+1]); - tempWeight.initRand(-1, 1); - m_weights.push_back(tempWeight); + for(unsigned int i = 0; i < numLayers; ++i){ + m_weights.push_back(MatrixXd::Random(layerSizes[i] + 1, layerSizes[i+1])); } } @@ -32,7 +33,7 @@ void NeuralNet::printWeights() const{ cout << "Current weights:" << endl; for(unsigned int i = 0; i < m_weights.size(); ++i){ cout << "================================================" << endl; - m_weights[i].printData(); + cout << m_weights[i] << endl; } cout << "================================================" << endl; } @@ -54,13 +55,12 @@ bool NeuralNet::saveToFile(string fileName) const{ outputFile << "\n"; for(unsigned int lay = 0; lay < m_weights.size(); ++lay){ - unsigned int numRows = m_weights[lay].numRows(); - unsigned int numCols = m_weights[lay].numCols(); + unsigned int rows = m_weights[lay].rows(); + unsigned int cols = m_weights[lay].cols(); - for(unsigned int i = 0; i < numRows; ++i){ - for(unsigned int j = 0; j < numCols; ++j){ - Matrix cur = m_weights[lay]; - outputFile << cur(i, j) << " "; + for(unsigned int col = 0; col < cols; ++col){ + for(unsigned int row = 0; row < rows; ++row){ + outputFile << m_weights[lay](row, col) << " "; } } } @@ -88,12 +88,14 @@ bool NeuralNet::loadFromFile(string fileName){ } for(unsigned int lay = 0; lay < numLayers - 1; ++lay){ - Matrix cur(m_layerSizes[lay] + 1, m_layerSizes[lay + 1]); - for(unsigned int i = 0; i < cur.numRows(); ++i){ - for(unsigned int j = 0; j < cur.numCols(); ++j){ + unsigned int rows = m_layerSizes[lay] + 1; + unsigned int cols = m_layerSizes[lay + 1]; + MatrixXd cur(rows, cols); + for(unsigned int col = 0; col < cols; ++col){ + for(unsigned int row = 0; row < rows; ++row){ double temp; inputFile >> temp; - cur(i, j) = temp; + cur(row, col) = temp; } } m_weights.push_back(cur); @@ -112,27 +114,31 @@ bool NeuralNet::loadFromFile(string fileName){ } //Performs forward propagation using m_weights and 'input' -Matrix NeuralNet::forward(const Matrix& input) const{ +RowVectorXd NeuralNet::forward(const RowVectorXd& input) const{ + unsigned int numLayers = m_weights.size(); + //Stores the previous layer's output - vector<Matrix> layers; + vector<RowVectorXd> layers; + layers.reserve(numLayers + 1); layers.push_back(input); - for(unsigned int lay = 0; lay < m_weights.size(); ++lay){ - //Add extra col with 1.0 in it for bias - Matrix prev = (layers.back()).addRowsCols(0, 1, 1.0f); + for(unsigned int lay = 0; lay < numLayers; ++lay){ + unsigned int numCols = layers[lay].size(); + RowVectorXd prev(numCols + 1); + prev << layers[lay], 1.0; //Cur = f(layers * weights + bias)...where f(x) is nonlinearity funtion - layers.push_back( applyNonlinearity(prev * m_weights[lay], sigmoid) ); + layers.push_back(applyNonlinearity(prev * m_weights[lay], Activations::relu)); } - return layers.back(); + return layers[numLayers]; } -vector<Matrix> NeuralNet::getWeights() const{ +vector<MatrixXd> NeuralNet::getWeights() const{ return m_weights; } //Sets the internal weights -void NeuralNet::setWeights(const vector<Matrix>& weights){ +void NeuralNet::setWeights(const vector<MatrixXd>& weights){ if (weights.size() == 0 || weights.size() != m_weights.size()){ cerr << "Error: setWeights(): Weights have different sizes." << endl; exit(1); @@ -142,20 +148,14 @@ void NeuralNet::setWeights(const vector<Matrix>& weights){ } } -//Applies the nonlinearity function (sigmoid) elementwise -Matrix NeuralNet::applyNonlinearity(const Matrix& input, - double(*callback)(double)) const{ - Matrix temp(input); - for(unsigned int row = 0; row < input.numRows(); ++row){ - for(unsigned int col = 0; col < input.numCols(); ++col){ - //Applies the callback to each element of input - temp(row, col) = callback(input(row, col)); - } - } - return temp; +RowVectorXd NeuralNet::applyNonlinearity(const RowVectorXd& input, Activations activation) const{ + switch (activation){ + case Activations::sigmoid: // 1 / (1 + e^-x) + return (((-1 * input.array()).exp() + 1).inverse()).matrix(); + case Activations::relu: // max(0, x) + return ((input.array() > 0).cast<double>() * input.array()).matrix(); + default: + return input; + } } -//Sigmoid function. Returns a double between (0, 1) -double NeuralNet::sigmoid(const double x){ - return 1 / (1 + exp(-x)); -} diff --git a/NeuralNet.h b/NeuralNet.h index ff3f64a..362af2d 100644 --- a/NeuralNet.h +++ b/NeuralNet.h @@ -1,7 +1,9 @@ #ifndef NN_H #define NN_H -#include "Matrix.h" +#include <Eigen/Dense> +using namespace Eigen; + #include <iostream> #include <fstream> #include <vector> @@ -10,36 +12,43 @@ using std::cout; using std::cin; +using std::cerr; using std::endl; using std::vector; using std::ofstream; using std::ifstream; using std::string; +enum Activations { sigmoid, relu }; + class NeuralNet { + + public: NeuralNet(); NeuralNet(const vector<unsigned int>& layerSizes); NeuralNet(const NeuralNet& nn); - Matrix forward(const Matrix& input) const; + RowVectorXd forward(const RowVectorXd& input) const; void printWeights() const; void operator= (const NeuralNet& nn); - vector<Matrix> getWeights() const; - void setWeights(const vector<Matrix>& weights); + vector<MatrixXd> getWeights() const; + void setWeights(const vector<MatrixXd>& weights); bool saveToFile(string fileName) const; bool loadFromFile(string fileName); private: vector<unsigned int> m_layerSizes; - vector<Matrix> m_weights; + vector<MatrixXd> m_weights; - Matrix applyNonlinearity(const Matrix& input, - double(*funct)(double)) const; - static double sigmoid(const double x); + /*RowVectorXd applyNonlinearity(const RowVectorXd& input, + double(*funct)(double)) const;*/ + RowVectorXd applyNonlinearity(const RowVectorXd& input, Activations activation) const; + //static double sigmoid(const double x); + //static double relu(const double x); }; #endif diff --git a/Player.cpp b/Player.cpp index df231b7..27dfbad 100644 --- a/Player.cpp +++ b/Player.cpp @@ -24,8 +24,7 @@ void Player::operator= (const Player& right){ } /* vector<double> Player::getMove() const{ - Matrix temp(1, 9); - temp.initRand(-1, 1); + MatrixXd temp = MatrixXd::Random(1, 9); return temp.toVector(); }*/ @@ -68,8 +67,8 @@ void NeuralPlayer::operator= (const NeuralPlayer& right){ neural = right.neural; } -vector<double> NeuralPlayer::getMove(const Matrix& input) const{ - return neural.forward(input).toVector(); +RowVectorXd NeuralPlayer::getMove(const RowVectorXd& input) const{ + return neural.forward(input); } //----------ManualPlayer-------------- @@ -98,7 +97,7 @@ void ManualPlayer::operator= (const ManualPlayer& right){ Player::operator=(right); } -vector<double> ManualPlayer::getMove(const Matrix& input) const{ +RowVectorXd ManualPlayer::getMove(const RowVectorXd& input) const{ unsigned int row, col; char eater; m_os << "Your move, of the form \"row, col\": "; @@ -106,10 +105,10 @@ vector<double> ManualPlayer::getMove(const Matrix& input) const{ row --; col --; - Matrix temp(m_rows, m_cols); - temp.initialize(0); - temp(row, col) = 1; - return temp.toVector(); + RowVectorXd temp(m_rows * m_cols); + temp << RowVectorXd::Constant(m_rows * m_cols, 0); + temp(row * m_cols + col) = 1.0; + return temp; } //----------PerfectPlayer-------------- diff --git a/Player.h b/Player.h index f15f861..6449e6e 100644 --- a/Player.h +++ b/Player.h @@ -1,8 +1,10 @@ #ifndef PLAYER_H #define PLAYER_H +#include <Eigen/Dense> +using namespace Eigen; + #include <vector> -#include "Matrix.h" #include "NeuralNet.h" using std::cout; @@ -22,7 +24,7 @@ public: void operator= (const Player& right); bool operator< (const Player& right) const; - virtual vector<double> getMove(const Matrix& input) const = 0; + virtual RowVectorXd getMove(const RowVectorXd& input) const = 0; void addToFitness(const double a); double getFitness() const; @@ -44,7 +46,7 @@ public: void operator= (const NeuralPlayer& right); - virtual vector<double> getMove(const Matrix& input) const override; + virtual RowVectorXd getMove(const RowVectorXd& input) const override; NeuralNet neural; private: @@ -61,7 +63,7 @@ public: void operator= (const ManualPlayer& right); - virtual vector<double> getMove(const Matrix& input) const override; + virtual RowVectorXd getMove(const RowVectorXd& input) const override; private: istream& m_is; @@ -79,7 +81,7 @@ public: void operator= (const PerfectPlayer& right); - virtual vector<double> getMove(const Matrix& input) const override; + virtual vector<double> getMove(const VectorXd& input) const override; private: double winningMove() const; diff --git a/Population.h b/Population.h index 0d7953c..2f006df 100644 --- a/Population.h +++ b/Population.h @@ -7,13 +7,16 @@ #include <vector> #include <algorithm> #include <string> +#include <ctime> + +#include <Eigen/Dense> +using namespace Eigen; -#include "Matrix.h" #include "NeuralNet.h" #include "Player.h" #include "TicTacToe.h" #include "Genetic.h" -#include "UltimateTTT.h" +//#include "UltimateTTT.h" using std::cout; using std::cin; @@ -29,7 +32,7 @@ public: Population<Game>(); void init(unsigned int seed = 1, istream& is = cin, ostream& os = cout); - void train(bool verbose); + time_t train(bool verbose); string saveBest(string path); void loadBest(string path, string name = ""); @@ -140,7 +143,8 @@ string Population<Game>::saveBest(string path){ template <template <class, class> class Game> -void Population<Game>::train(bool verbose){ +time_t Population<Game>::train(bool verbose){ + time_t startTime = time(NULL); for(int generation = 0; generation < m_iterations; ++generation){ //Play games with every permutaiton of players roundRobin(); @@ -149,7 +153,7 @@ void Population<Game>::train(bool verbose){ sort(m_population.begin(), m_population.end(), comparePlayerContainer<NeuralPlayer>); - m_hallOfFame.push_back(m_population.back()); + m_hallOfFame.push_back(m_population[m_populationSize - 1]); //Print board if(verbose){ @@ -179,6 +183,7 @@ void Population<Game>::train(bool verbose){ m_population[i].player.resetFitness(); } } + return time(NULL) - startTime; } @@ -241,6 +246,7 @@ void Population<Game>::init(unsigned int seed, istream& is, ostream& os){ } m_ga.setPopulationSize(m_populationSize); + m_hallOfFame.reserve(m_iterations); } template <template <class, class> class Game> diff --git a/README.md b/README.md index 1fbf255..f4e88d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TicTacToeMachineLearning -The goal of this project is to train the computer to play tic tac toe at a superhuman level. This is a rather trivial problem, but I'm simply using it as a chance to learn more about machine learning. My approach is overkill, but this is just a fun project. - -I'm using a neural network trained by a genetic algorithm to learn tic tac toe. I start with a random population of players. Each generation they play every other player once. Fitness points are awarded for their record: 0 points for each loss, 0.5 for each tie, and 1 point for each win. I then evolve the the players based on normal genetic algorithm techniques (mutation, breeding, crossover, etc.). The goal is to maximize the player's fitness. +# TicTacToeMachineLearning +The goal of this project is to train the computer to play tic tac toe at a superhuman level. This is a rather trivial problem, but I'm simply using it as a chance to learn more about machine learning. My approach is overkill, but this is just a fun project. + +I'm using a neural network trained by a genetic algorithm to learn tic tac toe. I start with a random population of players. Each generation they play every other player once. Fitness points are awarded for their record: 0 points for each loss, 0.5 for each tie, and 1 point for each win. I then evolve the the players based on normal genetic algorithm techniques (mutation, breeding, crossover, etc.). The goal is to maximize the player's fitness. diff --git a/TicTacToe.h b/TicTacToe.h index f7d97eb..530bb82 100644 --- a/TicTacToe.h +++ b/TicTacToe.h @@ -1,7 +1,9 @@ #ifndef TTT_H #define TTT_H -#include "Matrix.h" +#include <Eigen/Dense> +using namespace Eigen; + #include "NeuralNet.h" #include "Player.h" @@ -12,6 +14,7 @@ using std::cout; using std::cin; +using std::cerr; using std::endl; using std::vector; using std::pair; @@ -35,13 +38,13 @@ private: bool isEmpty() const; bool isFull() const; - Matrix toMatrix() const; - Matrix toPlayerPerspective(const States state) const; + RowVectorXd toMatrix() const; + RowVectorXd toPlayerPerspective(const States state) const; States getBoardAtPosition(const int position) const; void setBoardAtPosition(const int position, const States state); - vector<unsigned int> bestMoves(const vector<double>& input) const; + RowVectorXi bestMoves(const RowVectorXd& input) const; void printBoard() const; bool hasWon() const; @@ -104,28 +107,24 @@ bool TicTacToe<T1, T2>::isFull() const{ //Returns a vector of the preferred moves starting with most preferred template <class T1, class T2> -vector<unsigned int> TicTacToe<T1, T2>::bestMoves( - const vector<double>& input) const{ - vector<unsigned int> temp; +RowVectorXi TicTacToe<T1, T2>::bestMoves(const RowVectorXd& input) const{ + Matrix<int, 1, 9> ret; vector< pair<double, unsigned int> > inputPair; - - temp.resize(NUM_OUTPUTS, -1); + inputPair.reserve(9); //Populate inputPair for(unsigned int i = 0; i < NUM_OUTPUTS; ++i){ - inputPair.push_back(make_pair(input[i], i)); + inputPair.push_back(make_pair(input(i), i)); } sort(inputPair.begin(), inputPair.end()); - //Populate temp + //Populate ret for(unsigned int i = 0; i < NUM_OUTPUTS; ++i){ - temp[i] = inputPair[i].second; + ret(8 - i) = inputPair[i].second; } - //Reverse temp - reverse(temp.begin(), temp.end()); - return temp; + return ret; } //Prints the current board to the console @@ -154,13 +153,11 @@ void TicTacToe<T1, T2>::printBoard() const{ * representation so it can be passed into other methods. */ template <class T1, class T2> -Matrix TicTacToe<T1, T2>::toMatrix() const{ - Matrix temp(1, NUM_OUTPUTS); +RowVectorXd TicTacToe<T1, T2>::toMatrix() const{ + RowVectorXd temp(NUM_OUTPUTS); - for(int i = 0; i < 3; ++i){ - for(int j = 0; j < 3; ++j){ - temp(0, 3 * i + j) = (float)getBoardAtPosition(3 * i + j); - } + for(int i = 0; i < 9; ++i){ + temp(i) = (double)getBoardAtPosition(i); } return temp; } @@ -172,19 +169,17 @@ Matrix TicTacToe<T1, T2>::toMatrix() const{ - empty squares = 0 */ template <class T1, class T2> -Matrix TicTacToe<T1, T2>::toPlayerPerspective(const States state) const{ - Matrix temp(toMatrix()); +RowVectorXd TicTacToe<T1, T2>::toPlayerPerspective(const States state) const{ + RowVectorXd temp = toMatrix(); - for(unsigned int i = 0; i < temp.numRows(); ++i){ - for(unsigned int j = 0; j < temp.numCols(); ++j){ - States cur = static_cast<States>(temp(i, j)); - if(cur == States::empty){ - temp(i, j) = 0.0; - } else if(cur == state){ - temp(i, j) = 1.0; - } else{ - temp(i, j) = -1.0; - } + for(unsigned int i = 0; i < 9; ++i){ + States cur = static_cast<States>((int)temp(i)); + if(cur == States::empty){ + temp(i) = 0.0; + } else if(cur == state){ + temp(i) = 1.0; + } else{ + temp(i) = -1.0; } } return temp; @@ -258,7 +253,7 @@ bool TicTacToe<T1, T2>::hasWon() const{ template <class T1, class T2> bool TicTacToe<T1, T2>::takeTurn(const States state, const int turn){ //holds the list of desired moves in order of preference - vector<unsigned int> moves; + RowVectorXi moves; //Diagnostics if(m_verbose){ @@ -266,7 +261,7 @@ bool TicTacToe<T1, T2>::takeTurn(const States state, const int turn){ } //player 1 controls 'X' squares, player 2 controls 'O' squares - Matrix playerPerspective = toPlayerPerspective(state); + RowVectorXd playerPerspective = toPlayerPerspective(state); if(state == States::playerX){ moves = bestMoves(m_player1.player.getMove(playerPerspective)); } else{ @@ -275,8 +270,8 @@ bool TicTacToe<T1, T2>::takeTurn(const States state, const int turn){ //Make the best move from available squares for(int i = 0; i < NUM_OUTPUTS; ++i){ - if(getBoardAtPosition(moves[i]) == States::empty){ - setBoardAtPosition(moves[i], state); + if(getBoardAtPosition(moves(i)) == States::empty){ + setBoardAtPosition(moves(i), state); break; } } diff --git a/TicTacToeMachineLearning.sln b/TicTacToeMachineLearning.sln new file mode 100644 index 0000000..61f2553 --- /dev/null +++ b/TicTacToeMachineLearning.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2035 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TicTacToeMachineLearning", "TicTacToeMachineLearning.vcxproj", "{AE943583-6E21-47EC-BFC2-F37CA248C5A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Debug|x64.ActiveCfg = Debug|x64 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Debug|x64.Build.0 = Debug|x64 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Debug|x86.ActiveCfg = Debug|Win32 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Debug|x86.Build.0 = Debug|Win32 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Release|x64.ActiveCfg = Release|x64 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Release|x64.Build.0 = Release|x64 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Release|x86.ActiveCfg = Release|Win32 + {AE943583-6E21-47EC-BFC2-F37CA248C5A9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7CBB95EE-B334-49D0-B4E3-EB36EAE13774} + EndGlobalSection +EndGlobal diff --git a/TicTacToeMachineLearning.vcxproj b/TicTacToeMachineLearning.vcxproj new file mode 100644 index 0000000..5e818ca --- /dev/null +++ b/TicTacToeMachineLearning.vcxproj @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{AE943583-6E21-47EC-BFC2-F37CA248C5A9}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>D:/MinGW/include/eigen-eigen-5a0156e40feb/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + </ClCompile> + <Link> + <TargetMachine>MachineX86</TargetMachine> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>D:/MinGW/include/eigen-eigen-5a0156e40feb/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <TargetMachine>MachineX86</TargetMachine> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Genetic.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="Matrix.cpp" /> + <ClCompile Include="NeuralNet.cpp" /> + <ClCompile Include="Player.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Genetic.h" /> + <ClInclude Include="main.h" /> + <ClInclude Include="Matrix.h" /> + <ClInclude Include="NeuralNet.h" /> + <ClInclude Include="Player.h" /> + <ClInclude Include="Population.h" /> + <ClInclude Include="TicTacToe.h" /> + <ClInclude Include="UltimateTTT.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/TicTacToeMachineLearning.vcxproj.filters b/TicTacToeMachineLearning.vcxproj.filters new file mode 100644 index 0000000..4feca21 --- /dev/null +++ b/TicTacToeMachineLearning.vcxproj.filters @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Genetic.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Matrix.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="NeuralNet.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Player.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Genetic.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Matrix.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="NeuralNet.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Player.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Population.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="TicTacToe.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="UltimateTTT.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/Todo.txt b/Todo.txt index 3ec2b32..b39e9ec 100644 --- a/Todo.txt +++ b/Todo.txt @@ -1,7 +1,8 @@ TODO List - Code formatting -- Improve Matrix class functionality/cleanliness +- XXXXXXXXXXXXX Improve Matrix class functionality/cleanliness XXXXXXXXXXXXX +- Use Eigen matrix library - Ultimate Tic Tac Toe - Random Player (chooses moves randomly) - Timekeeping (execution time) diff --git a/Training Times.xlsx b/Training Times.xlsx new file mode 100644 index 0000000..fe8cf0b Binary files /dev/null and b/Training Times.xlsx differ diff --git a/UltimateTTT.h b/UltimateTTT.h index 5f47f14..45cb8fa 100644 --- a/UltimateTTT.h +++ b/UltimateTTT.h @@ -133,10 +133,11 @@ bool UltimateTTT<T1, T2>::subBoardTied(const int subBoard) const{ template <class T1, class T2> vector<unsigned int> UltimateTTT<T1, T2>::bestMoves( const vector<double>& input) const{ - vector<unsigned int> temp; - temp.resize(NUM_OUTPUTS, -1); - - vector< pair<double, unsigned int> > inputPair; + + vector<unsigned int> ret; + vector< pair<double, unsigned int> > inputPair; + ret.reserve(NUM_OUTPUTS); + inputPair.reserve(NUM_OUTPUTS); //Populate inputPair for(unsigned int i = 0; i < NUM_OUTPUTS; ++i){ @@ -147,12 +148,12 @@ vector<unsigned int> UltimateTTT<T1, T2>::bestMoves( //Populate temp for(unsigned int i = 0; i < NUM_OUTPUTS; ++i){ - temp[i] = inputPair[i].second; + ret.push_back(inputPair[i].second); } //Reverse temp - reverse(temp.begin(), temp.end()); - return temp; + reverse(ret.begin(), ret.end()); + return ret; } //Prints the current board to the console diff --git a/main.cpp b/main.cpp index 81926da..4b1da79 100644 --- a/main.cpp +++ b/main.cpp @@ -2,16 +2,17 @@ #include "main.h" #include "Population.h" +#include <Eigen/Dense> int main(){ - srand(time(NULL)); - + srand((unsigned int)time(NULL)); + //Where your player log files are stored string path = "data/"; Population<TicTacToe> pop; - + /* ManualPlayer tempHuman1(cin, cout, 10, 9); playerContainer<ManualPlayer> human1(tempHuman1); @@ -26,7 +27,7 @@ int main(){ UltimateTTT<NeuralPlayer, NeuralPlayer> ttt(machine1, machine2, true); ttt.playGame(); - + */ char loadPlayer; cout << "Do you want to load a trained player? (y/n): "; @@ -36,8 +37,10 @@ int main(){ if(loadPlayer == 'y' || loadPlayer == 'Y'){ pop.loadBest(path); } else{ - pop.init(time(NULL)); - pop.train(false); + pop.init((unsigned int)time(NULL)); + time_t trainingTime = pop.train(false); + + cout << "Time to train: " << trainingTime << endl; char savePlayer; cout << "Do you want to save the best player to a file? (y/n): "; diff --git a/makefile b/makefile index 8167680..9100c15 100644 --- a/makefile +++ b/makefile @@ -5,21 +5,22 @@ Warnings = -Wall -Wextra -Wdouble-promotion -Wswitch-default -Wfloat-equal \ Sanitize = -fsanitize=address -fsanitize=undefined TestingFlags = -Og -g ReleaseFlags = -O3 -Targets = main.cpp Matrix.cpp NeuralNet.cpp Player.cpp Genetic.cpp +Targets = main.cpp NeuralNet.cpp Player.cpp Genetic.cpp +Include = -isystem d:/MinGW/include/eigen-eigen-5a0156e40feb/ all: $(Targets) $(RM) a - g++ $(CompilerFlags) $(Warnings) $(TestingFlags) $(Targets) + g++ $(CompilerFlags) $(Warnings) $(TestingFlags) $(Targets) $(Include) run: $(Targets) $(RM) a - g++ $(CompilerFlags) $(Warnings) $(TestingFlags) $(Targets) + g++ $(CompilerFlags) $(Warnings) $(TestingFlags) $(Targets) $(Include) ./a.exe fast: $(Targets) $(RM) a - g++ $(CompilerFlags) $(Warnings) $(ReleaseFlags) $(Targets) + g++ $(CompilerFlags) $(Warnings) $(ReleaseFlags) $(Targets) $(Include) clean: $(RM) a
1 parent 685e59a commit b2075ff

20 files changed

+741
-476
lines changed

.gitignore

Lines changed: 362 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,362 @@
1-
# Prerequisites
2-
*.d
3-
4-
# Compiled Object files
5-
*.slo
6-
*.lo
7-
*.o
8-
*.obj
9-
10-
# Precompiled Headers
11-
*.gch
12-
*.pch
13-
14-
# Compiled Dynamic libraries
15-
*.so
16-
*.dylib
17-
*.dll
18-
19-
# Fortran module files
20-
*.mod
21-
*.smod
22-
23-
# Compiled Static libraries
24-
*.lai
25-
*.la
26-
*.a
27-
*.lib
28-
29-
# Executables
30-
*.exe
31-
*.out
32-
*.app
33-
34-
# Log files for saved players
35-
*.log
1+
# Prerequisites
2+
*.d
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
9+
# Precompiled Headers
10+
*.gch
11+
12+
# Compiled Dynamic libraries
13+
*.so
14+
*.dylib
15+
*.dll
16+
17+
# Fortran module files
18+
*.mod
19+
*.smod
20+
21+
# Compiled Static libraries
22+
*.lai
23+
*.la
24+
*.a
25+
*.lib
26+
27+
# Executables
28+
*.exe
29+
*.out
30+
*.app
31+
32+
33+
34+
## Ignore Visual Studio temporary files, build results, and
35+
## files generated by popular Visual Studio add-ons.
36+
##
37+
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
38+
39+
# User-specific files
40+
*.suo
41+
*.user
42+
*.userosscache
43+
*.sln.docstates
44+
45+
# User-specific files (MonoDevelop/Xamarin Studio)
46+
*.userprefs
47+
48+
# Build results
49+
[Dd]ebug/
50+
[Dd]ebugPublic/
51+
[Rr]elease/
52+
[Rr]eleases/
53+
x64/
54+
x86/
55+
bld/
56+
[Bb]in/
57+
[Oo]bj/
58+
[Ll]og/
59+
60+
# Visual Studio 2015/2017 cache/options directory
61+
.vs/
62+
# Uncomment if you have tasks that create the project's static files in wwwroot
63+
#wwwroot/
64+
65+
# Visual Studio 2017 auto generated files
66+
Generated\ Files/
67+
68+
# MSTest test Results
69+
[Tt]est[Rr]esult*/
70+
[Bb]uild[Ll]og.*
71+
72+
# NUNIT
73+
*.VisualState.xml
74+
TestResult.xml
75+
76+
# Build Results of an ATL Project
77+
[Dd]ebugPS/
78+
[Rr]eleasePS/
79+
dlldata.c
80+
81+
# Benchmark Results
82+
BenchmarkDotNet.Artifacts/
83+
84+
# .NET Core
85+
project.lock.json
86+
project.fragment.lock.json
87+
artifacts/
88+
89+
# StyleCop
90+
StyleCopReport.xml
91+
92+
# Files built by Visual Studio
93+
*_i.c
94+
*_p.c
95+
*_i.h
96+
*.ilk
97+
*.meta
98+
*.obj
99+
*.iobj
100+
*.pch
101+
*.pdb
102+
*.ipdb
103+
*.pgc
104+
*.pgd
105+
*.rsp
106+
*.sbr
107+
*.tlb
108+
*.tli
109+
*.tlh
110+
*.tmp
111+
*.tmp_proj
112+
*.log
113+
*.vspscc
114+
*.vssscc
115+
.builds
116+
*.pidb
117+
*.svclog
118+
*.scc
119+
120+
# Chutzpah Test files
121+
_Chutzpah*
122+
123+
# Visual C++ cache files
124+
ipch/
125+
*.aps
126+
*.ncb
127+
*.opendb
128+
*.opensdf
129+
*.sdf
130+
*.cachefile
131+
*.VC.db
132+
*.VC.VC.opendb
133+
134+
# Visual Studio profiler
135+
*.psess
136+
*.vsp
137+
*.vspx
138+
*.sap
139+
140+
# Visual Studio Trace Files
141+
*.e2e
142+
143+
# TFS 2012 Local Workspace
144+
$tf/
145+
146+
# Guidance Automation Toolkit
147+
*.gpState
148+
149+
# ReSharper is a .NET coding add-in
150+
_ReSharper*/
151+
*.[Rr]e[Ss]harper
152+
*.DotSettings.user
153+
154+
# JustCode is a .NET coding add-in
155+
.JustCode
156+
157+
# TeamCity is a build add-in
158+
_TeamCity*
159+
160+
# DotCover is a Code Coverage Tool
161+
*.dotCover
162+
163+
# AxoCover is a Code Coverage Tool
164+
.axoCover/*
165+
!.axoCover/settings.json
166+
167+
# Visual Studio code coverage results
168+
*.coverage
169+
*.coveragexml
170+
171+
# NCrunch
172+
_NCrunch_*
173+
.*crunch*.local.xml
174+
nCrunchTemp_*
175+
176+
# MightyMoose
177+
*.mm.*
178+
AutoTest.Net/
179+
180+
# Web workbench (sass)
181+
.sass-cache/
182+
183+
# Installshield output folder
184+
[Ee]xpress/
185+
186+
# DocProject is a documentation generator add-in
187+
DocProject/buildhelp/
188+
DocProject/Help/*.HxT
189+
DocProject/Help/*.HxC
190+
DocProject/Help/*.hhc
191+
DocProject/Help/*.hhk
192+
DocProject/Help/*.hhp
193+
DocProject/Help/Html2
194+
DocProject/Help/html
195+
196+
# Click-Once directory
197+
publish/
198+
199+
# Publish Web Output
200+
*.[Pp]ublish.xml
201+
*.azurePubxml
202+
# Note: Comment the next line if you want to checkin your web deploy settings,
203+
# but database connection strings (with potential passwords) will be unencrypted
204+
*.pubxml
205+
*.publishproj
206+
207+
# Microsoft Azure Web App publish settings. Comment the next line if you want to
208+
# checkin your Azure Web App publish settings, but sensitive information contained
209+
# in these scripts will be unencrypted
210+
PublishScripts/
211+
212+
# NuGet Packages
213+
*.nupkg
214+
# The packages folder can be ignored because of Package Restore
215+
**/[Pp]ackages/*
216+
# except build/, which is used as an MSBuild target.
217+
!**/[Pp]ackages/build/
218+
# Uncomment if necessary however generally it will be regenerated when needed
219+
#!**/[Pp]ackages/repositories.config
220+
# NuGet v3's project.json files produces more ignorable files
221+
*.nuget.props
222+
*.nuget.targets
223+
224+
# Microsoft Azure Build Output
225+
csx/
226+
*.build.csdef
227+
228+
# Microsoft Azure Emulator
229+
ecf/
230+
rcf/
231+
232+
# Windows Store app package directories and files
233+
AppPackages/
234+
BundleArtifacts/
235+
Package.StoreAssociation.xml
236+
_pkginfo.txt
237+
*.appx
238+
239+
# Visual Studio cache files
240+
# files ending in .cache can be ignored
241+
*.[Cc]ache
242+
# but keep track of directories ending in .cache
243+
!*.[Cc]ache/
244+
245+
# Others
246+
ClientBin/
247+
~$*
248+
*~
249+
*.dbmdl
250+
*.dbproj.schemaview
251+
*.jfm
252+
*.pfx
253+
*.publishsettings
254+
orleans.codegen.cs
255+
256+
# Including strong name files can present a security risk
257+
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
258+
#*.snk
259+
260+
# Since there are multiple workflows, uncomment next line to ignore bower_components
261+
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
262+
#bower_components/
263+
264+
# RIA/Silverlight projects
265+
Generated_Code/
266+
267+
# Backup & report files from converting an old project file
268+
# to a newer Visual Studio version. Backup files are not needed,
269+
# because we have git ;-)
270+
_UpgradeReport_Files/
271+
Backup*/
272+
UpgradeLog*.XML
273+
UpgradeLog*.htm
274+
ServiceFabricBackup/
275+
*.rptproj.bak
276+
277+
# SQL Server files
278+
*.mdf
279+
*.ldf
280+
*.ndf
281+
282+
# Business Intelligence projects
283+
*.rdl.data
284+
*.bim.layout
285+
*.bim_*.settings
286+
*.rptproj.rsuser
287+
288+
# Microsoft Fakes
289+
FakesAssemblies/
290+
291+
# GhostDoc plugin setting file
292+
*.GhostDoc.xml
293+
294+
# Node.js Tools for Visual Studio
295+
.ntvs_analysis.dat
296+
node_modules/
297+
298+
# Visual Studio 6 build log
299+
*.plg
300+
301+
# Visual Studio 6 workspace options file
302+
*.opt
303+
304+
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
305+
*.vbw
306+
307+
# Visual Studio LightSwitch build output
308+
**/*.HTMLClient/GeneratedArtifacts
309+
**/*.DesktopClient/GeneratedArtifacts
310+
**/*.DesktopClient/ModelManifest.xml
311+
**/*.Server/GeneratedArtifacts
312+
**/*.Server/ModelManifest.xml
313+
_Pvt_Extensions
314+
315+
# Paket dependency manager
316+
.paket/paket.exe
317+
paket-files/
318+
319+
# FAKE - F# Make
320+
.fake/
321+
322+
# JetBrains Rider
323+
.idea/
324+
*.sln.iml
325+
326+
# CodeRush
327+
.cr/
328+
329+
# Python Tools for Visual Studio (PTVS)
330+
__pycache__/
331+
*.pyc
332+
333+
# Cake - Uncomment if you are using it
334+
# tools/**
335+
# !tools/packages.config
336+
337+
# Tabs Studio
338+
*.tss
339+
340+
# Telerik's JustMock configuration file
341+
*.jmconfig
342+
343+
# BizTalk build output
344+
*.btp.cs
345+
*.btm.cs
346+
*.odx.cs
347+
*.xsd.cs
348+
349+
# OpenCover UI analysis results
350+
OpenCover/
351+
352+
# Azure Stream Analytics local run output
353+
ASALocalRun/
354+
355+
# MSBuild Binary and Structured Log
356+
*.binlog
357+
358+
# NVidia Nsight GPU debugger configuration file
359+
*.nvuser
360+
361+
# MFractors (Xamarin productivity tool) working folder
362+
.mfractor/

0 commit comments

Comments
 (0)