Skip to content

Commit

Permalink
minor updates
Browse files Browse the repository at this point in the history
- added a bird for the player to control which has red outline and a yellow filled color.

- added methods for saving and loading the current fittest bird's neural network.

- increase the frame limit to 60.

- updated the build.yml github actions workflow.
  • Loading branch information
mrdcvlsc committed Oct 27, 2023
1 parent 8511b2c commit a260a4d
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 16 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
platform:
- { name: Linux Clang, os: ubuntu-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: ubuntu-exec.zip , zipper: zip, flags: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ }
- { name: Linux Clang, os: ubuntu-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: ubuntu-executable.zip , zipper: zip, flags: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ }
config:
- { name: Static, flags: -DBUILD_SHARED_LIBS=FALSE }

Expand Down Expand Up @@ -61,12 +61,12 @@ jobs:
fail-fast: false
matrix:
platform:
- { name: Windows VS2019, os: windows-2019, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-exec-VS19.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
- { name: Windows VS2022, os: windows-2022, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-exec-VS22.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
- { name: Windows Clang, os: windows-latest, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-exec-clang.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ }
- { name: Windows GCC, os: windows-latest, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-exec-gcc.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ }
- { name: MacOS XCode, os: macos-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: mac-exec.zip, zipper: zip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
# - { name: Linux GCC, os: ubuntu-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: mac-exec.zip, zipper: zip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
- { name: Windows VS2019, os: windows-2019, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-executable-VS19.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
- { name: Windows VS2022, os: windows-2022, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-executable-VS22.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
- { name: Windows Clang, os: windows-latest, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-executable-clang.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ }
- { name: Windows GCC, os: windows-latest, font: .\\build\\calibril.ttf, bin: .\\build\\Release\\flappy_ffnn_ga.exe, zip: windows-executable-gcc.zip, zipper: 7z a -tzip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ }
- { name: MacOS XCode, os: macos-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: mac-executable.zip, zipper: zip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
# - { name: Linux GCC, os: ubuntu-latest, font: ./build/calibril.ttf, bin: ./build/flappy_ffnn_ga, zip: mac-executable.zip, zipper: zip, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
config:
- { name: Static, flags: -DBUILD_SHARED_LIBS=FALSE -DCMAKE_BUILD_TYPE=Release }
# - { name: Shared, flags: -DBUILD_SHARED_LIBS=TRUE -DCMAKE_BUILD_TYPE=Release }
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
src/tmp
build
*.nn
*.tmp

# Prerequisites
*.d
Expand Down
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

A Flappy Bird like game that uses a feedforward neural network to play the game, and a genetic algorithm to learn how to play the game.

The player's bird which is actually just a box (has a red colored outline and filled with yellow color inside) can be controlled by the human player by pressing the `space` key in the keyboard.

A human player can compete with the each generated birds controlled by their own neural network.

Anyone can [download the released executables (click here to download)](https://github.com/mrdcvlsc/flappy-ffnn-ga/releases) and extract it then run the program, these release executables are only supported on x86-64 or 64-bit systems.

In windows, one might need to install the [Microsoft Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2015-2017-2019-and-2022) in their system if the release versions of the executables is not working.
38 changes: 37 additions & 1 deletion src/ffnn.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#include <ios>
#include <fstream>
#include <array>

#include "ffnn.hpp"

std::uniform_int_distribution<size_t> FFNN::random_chance(0U, 100U);
Expand Down Expand Up @@ -97,4 +101,36 @@ void FFNN::combine(FFNN const &net1, FFNN const &net2)
}
}
}
}
}

bool FFNN::save_network(std::string const &output_filename)
{
std::ofstream nn_file(output_filename, std::ios::binary | std::ios::trunc);

nn_file.write(reinterpret_cast<char *>(w1.data()), w1.size() * sizeof(float));
nn_file.write(reinterpret_cast<char *>(w2.data()), w2.size() * sizeof(float));
nn_file.close();

std::cout << "------------ saved ------------\n";
std::cout << "w1 = \n\n" << w1 << "\n\nw2 = \n\n" << w2 << "\n\n";

return nn_file.good();
}

bool FFNN::load_network(std::string const &filename)
{
std::ifstream nn_file(filename, std::ios::binary);

if (!nn_file.good()) {
return false;
}

nn_file.read(reinterpret_cast<char *>(w1.data()), w1.size() * sizeof(float));
nn_file.read(reinterpret_cast<char *>(w2.data()), w2.size() * sizeof(float));
nn_file.close();

std::cout << "------------ loaded ------------\n";
std::cout << "w1 = \n\n" << w1 << "\n\nw2 = \n\n" << w2 << "\n\n";

return nn_file.good();
}
8 changes: 7 additions & 1 deletion src/ffnn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
#define MRDCVLSC_FFNN_HPP

#include <iostream>
#include <cinttypes>
#include <fstream>
#include <chrono>
#include <random>

#include <stddef.h>

#include <cinttypes>
#include <cmath>

#include <Eigen/Core>
Expand Down Expand Up @@ -54,6 +57,9 @@ struct FFNN

/// \brief overwrite the old weights with the weights of either network1 or network2 (50/50 random selection).
void combine(FFNN const &net1, FFNN const &net2);

bool save_network(std::string const &output_filename);
bool load_network(std::string const &filename);
};

#endif
2 changes: 1 addition & 1 deletion src/gamestats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class GameStats : public sf::Drawable
{
public:

static constexpr size_t FRAME_LIMIT = 30;
static constexpr size_t FRAME_LIMIT = 60;
static constexpr size_t FONT_SIZE = 12;

static const sf::Time TIME_PER_FRAME;
Expand Down
39 changes: 33 additions & 6 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,20 @@ int main()

sf::Color background(19, 235, 220);

Bird player_bird;
player_bird.setOutlineColor(sf::Color::Red);
player_bird.setFillColor(sf::Color::Yellow);

Birds birds;
Pipes pipes;
GeneticAlgorithm genetic_algorithm;

if (!birds.collection[0].neural_net.load_network("fittest.nn")) {
std::cout << "error loading the fittest network\n";
} else {
std::cout << "the previous fittests network is loaded\n";
}

while (window.isOpen()) {
sf::Time dt = game_statistics->clock_fps.restart();
game_statistics->update_time_elapsed += dt;
Expand All @@ -59,41 +69,43 @@ int main()
// cam up
if (event.key.scancode == sf::Keyboard::Scan::Up) {
game_view.move(0.f, -VIEW_MOVE_DISTANCE);
window.setView(game_view);
}

// cam down
if (event.key.scancode == sf::Keyboard::Scan::Down) {
game_view.move(0.f, VIEW_MOVE_DISTANCE);
window.setView(game_view);
}

// cam left
if (event.key.scancode == sf::Keyboard::Scan::Left) {
game_view.move(-VIEW_MOVE_DISTANCE, 0.f);
window.setView(game_view);
}

// cam right
if (event.key.scancode == sf::Keyboard::Scan::Right) {
game_view.move(VIEW_MOVE_DISTANCE, 0.f);
window.setView(game_view);
}

// zoom in cam
if (event.key.scancode == sf::Keyboard::Scan::Equal) {
game_view.zoom(0.99f);
window.setView(game_view);
}

// zoom out cam
if (event.key.scancode == sf::Keyboard::Scan::Hyphen) {
game_view.zoom(1.01f);
window.setView(game_view);
}

// bird jumps
if (event.key.scancode == sf::Keyboard::Scan::Space) {
for (auto &bird: birds.collection) {
bird.jump();
}
player_bird.jump();
}

window.setView(game_view);
}
}

Expand All @@ -104,26 +116,41 @@ int main()

pipes.update(GameStats::TIME_PER_FRAME.asSeconds());
birds.update(GameStats::TIME_PER_FRAME.asSeconds());
player_bird.update(GameStats::TIME_PER_FRAME.asSeconds());

game_statistics->record_deaths(birds_collisions(birds, pipes));
bird_collision(player_bird, pipes);
}

window.clear(background);

window.draw(game_area);
window.draw(birds);

if (!player_bird.dead) {
window.draw(player_bird);
}

window.draw(pipes);
window.draw(*game_statistics);

window.display();

if (birds.population == 0ULL) {
if (birds.population == 0ULL && player_bird.dead) {
genetic_algorithm.rank_fitness(birds);

if (birds.collection[0].neural_net.save_network("fittest.nn")) {
std::cout << "fittest network saved\n";
} else {
std::cout << "failed to save the fittest network\n";
}

genetic_algorithm.apply_mutations(birds);

game_statistics->new_generation();
pipes.new_generation();
birds.reset();
player_bird.reset();
}

game_statistics->update();
Expand Down

0 comments on commit a260a4d

Please sign in to comment.