diff --git a/Test/Test.vcxproj b/Test/Test.vcxproj
new file mode 100644
index 0000000..8cf43da
--- /dev/null
+++ b/Test/Test.vcxproj
@@ -0,0 +1,135 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {5CCBC659-08ED-4279-A5C4-6F16FB1FCC20}
+ Test
+ 8.1
+
+
+
+ Application
+ true
+ v140
+ MultiByte
+
+
+ Application
+ false
+ v140
+ true
+ MultiByte
+
+
+ Application
+ true
+ v140
+ MultiByte
+
+
+ Application
+ false
+ v140
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+
+
+
+
+ Level3
+ Disabled
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ MultiThreaded
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Test/Test.vcxproj.filters b/Test/Test.vcxproj.filters
new file mode 100644
index 0000000..32a8145
--- /dev/null
+++ b/Test/Test.vcxproj.filters
@@ -0,0 +1,25 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Test/main.cpp b/Test/main.cpp
new file mode 100644
index 0000000..d34662f
--- /dev/null
+++ b/Test/main.cpp
@@ -0,0 +1,29 @@
+#include
+#include
+
+int main(void)
+{
+ std::cout << "Start" << std::endl;
+
+ sf::TcpSocket socket;
+ sf::Socket::Status status = socket.connect("93.201.163.184", 30000);
+ std::cout << "Verbindunsaufbau..." << std::endl;
+ if (status != sf::Socket::Done) {
+ std::cout << "Error while trying to connect to IP" << std::endl;
+ return 0;
+ }
+
+ std::cout << "Bereit Verbindung aufzubauen" << std::endl;
+ char data[20];
+ std::size_t received;
+
+ if (socket.receive(data, 20, received) != sf::Socket::Done) {
+ std::cout << "Failed to receive package" << std::endl;
+ return 0;
+ }
+
+ std::cout << data << std::endl;
+ getchar();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/Test/packages.config b/Test/packages.config
new file mode 100644
index 0000000..a21dd09
--- /dev/null
+++ b/Test/packages.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tic Tac Toe.sln b/Tic Tac Toe.sln
new file mode 100644
index 0000000..c80de8c
--- /dev/null
+++ b/Tic Tac Toe.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tic Tac Toe", "Tic Tac Toe\Tic Tac Toe.vcxproj", "{271F58BA-B409-47FD-8EBE-D6202A17DAE6}"
+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
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Debug|x64.ActiveCfg = Debug|x64
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Debug|x64.Build.0 = Debug|x64
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Debug|x86.ActiveCfg = Debug|Win32
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Debug|x86.Build.0 = Debug|Win32
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Release|x64.ActiveCfg = Release|x64
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Release|x64.Build.0 = Release|x64
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Release|x86.ActiveCfg = Release|Win32
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tic Tac Toe/Button.cpp b/Tic Tac Toe/Button.cpp
new file mode 100644
index 0000000..74ad5c2
--- /dev/null
+++ b/Tic Tac Toe/Button.cpp
@@ -0,0 +1,78 @@
+#include "Button.hpp"
+
+
+Button::Button(std::string text, int x, int y)
+{
+ default = ColorPalette(sf::Color(70, 70, 70), sf::Color(130, 130, 130), sf::Color(255, 255, 255));
+ hover = ColorPalette(sf::Color(70, 70, 70), sf::Color(160, 160, 160), sf::Color(255, 255, 255));
+ clicked = ColorPalette(sf::Color(130, 130, 130), sf::Color(70, 70, 70), sf::Color(255, 255, 255));
+ disabled = ColorPalette(sf::Color(10, 10, 10), sf::Color(40, 40, 40), sf::Color(120, 120, 120));
+
+ background.setFillColor(default.background);
+ background.setOutlineColor(default.frame);
+ background.setOutlineThickness(15);
+ background.setSize(sf::Vector2f(400, 150));
+ background.setPosition(sf::Vector2f(x, y));
+
+ font = new sf::Font();
+ font->loadFromFile("C:/Windows/Fonts/lucon.ttf");
+
+ label.setFont(*font);
+ label.setColor(default.label);
+ label.setCharacterSize(48);
+ label.setString(text);
+ label.setOrigin(sf::Vector2f(label.getLocalBounds().width / 2, label.getLocalBounds().height));
+ label.setPosition(sf::Vector2f(background.getGlobalBounds().left + background.getLocalBounds().width / 2,
+ background.getGlobalBounds().top + background.getLocalBounds().height / 2));
+
+ isDisabled = false;
+}
+
+void Button::Update(int mouseX, int mouseY)
+{
+ if (mouseX > background.getGlobalBounds().left && mouseX < background.getGlobalBounds().left + background.getLocalBounds().width &&
+ mouseY > background.getGlobalBounds().top && mouseY < background.getGlobalBounds().top + background.getLocalBounds().height)
+ {
+ background.setFillColor(hover.background);
+ background.setOutlineColor(hover.frame);
+ label.setFillColor(hover.label);
+
+ }
+
+ else
+ {
+ background.setFillColor(default.background);
+ background.setOutlineColor(default.frame);
+ label.setFillColor(default.label);
+ }
+
+ if (isDisabled)
+ {
+ background.setFillColor(disabled.background);
+ background.setOutlineColor(disabled.frame);
+ label.setFillColor(disabled.label);
+ }
+}
+
+void Button::Render(sf::RenderWindow& target)
+{
+ target.draw(background);
+ target.draw(label);
+}
+
+bool Button::isClicked(int mouseX, int mouseY)
+{
+ if (isDisabled) return false;
+
+ if (mouseX > background.getGlobalBounds().left && mouseX < background.getGlobalBounds().left + background.getLocalBounds().width &&
+ mouseY > background.getGlobalBounds().top && mouseY < background.getGlobalBounds().top + background.getLocalBounds().height)
+ {
+ background.setFillColor(default.background);
+ background.setOutlineColor(default.frame);
+ label.setFillColor(default.label);
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/Tic Tac Toe/Button.hpp b/Tic Tac Toe/Button.hpp
new file mode 100644
index 0000000..168f8c6
--- /dev/null
+++ b/Tic Tac Toe/Button.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include
+#include
+
+#include "Util.h"
+
+struct ColorPalette
+{
+ ColorPalette() {}
+ ColorPalette(sf::Color _frame, sf::Color _background, sf::Color _label)
+ {
+ frame = _frame;
+ background = _background;
+ label = _label;
+ }
+
+ sf::Color frame, background, label;
+};
+
+class Button
+{
+public:
+ Button() {}
+ Button(std::string text, int x, int y);
+
+ void Update(int mouseX, int mouseY);
+ void Render(sf::RenderWindow& target);
+
+ bool isClicked(int mouseX, int mouseY);
+ void disable() {
+ isDisabled = true;
+ }
+ void enable()
+ {
+ isDisabled = false;
+ }
+
+private:
+ sf::RectangleShape background;
+ sf::Text label;
+ sf::Font* font;
+
+ ColorPalette default, hover, clicked, disabled;
+
+ bool isDisabled;
+};
\ No newline at end of file
diff --git a/Tic Tac Toe/Field.cpp b/Tic Tac Toe/Field.cpp
new file mode 100644
index 0000000..0690722
--- /dev/null
+++ b/Tic Tac Toe/Field.cpp
@@ -0,0 +1,130 @@
+#include "Field.hpp"
+
+#include
+
+Field::Field()
+{
+ tiles[0] = new Tile(50, 50);
+ tiles[1] = new Tile(300, 50);
+ tiles[2] = new Tile(550, 50);
+ tiles[3] = new Tile(50, 300);
+ tiles[4] = new Tile(300, 300);
+ tiles[5] = new Tile(550, 300);
+ tiles[6] = new Tile(50, 550);
+ tiles[7] = new Tile(300, 550);
+ tiles[8] = new Tile(550, 550);
+
+ for (int i = 0; i < 4; i++)
+ {
+ lines[i].setFillColor(sf::Color(170, 170, 170));
+ }
+
+ lines[0].setPosition(250, 50);
+ lines[0].setSize(sf::Vector2f(50, 700));
+
+ lines[1].setPosition(500, 50);
+ lines[1].setSize(sf::Vector2f(50, 700));
+
+ lines[2].setPosition(50, 250);
+ lines[2].setSize(sf::Vector2f(700, 50));
+
+ lines[3].setPosition(50, 500);
+ lines[3].setSize(sf::Vector2f(700, 50));
+}
+
+char Field::Update()
+{
+ if (tiles[0]->what() == 'x' && tiles[1]->what() == 'x' && tiles[2]->what() == 'x')
+ return 'x';
+ if (tiles[0]->what() == 'o' && tiles[1]->what() == 'o' && tiles[2]->what() == 'o')
+ return 'o';
+
+ if (tiles[3]->what() == 'x' && tiles[4]->what() == 'x' && tiles[5]->what() == 'x')
+ return 'x';
+ if (tiles[3]->what() == 'o' && tiles[4]->what() == 'o' && tiles[5]->what() == 'o')
+ return 'o';
+
+ if (tiles[6]->what() == 'x' && tiles[7]->what() == 'x' && tiles[8]->what() == 'x')
+ return 'x';
+ if (tiles[6]->what() == 'o' && tiles[7]->what() == 'o' && tiles[8]->what() == 'o')
+ return 'o';
+
+
+
+
+ if (tiles[0]->what() == 'x' && tiles[3]->what() == 'x' && tiles[6]->what() == 'x')
+ return 'x';
+ if (tiles[0]->what() == 'o' && tiles[3]->what() == 'o' && tiles[6]->what() == 'o')
+ return 'o';
+
+ if (tiles[1]->what() == 'x' && tiles[4]->what() == 'x' && tiles[7]->what() == 'x')
+ return 'x';
+ if (tiles[1]->what() == 'o' && tiles[4]->what() == 'o' && tiles[7]->what() == 'o')
+ return 'o';
+
+ if (tiles[2]->what() == 'x' && tiles[5]->what() == 'x' && tiles[8]->what() == 'x')
+ return 'x';
+ if (tiles[2]->what() == 'o' && tiles[5]->what() == 'o' && tiles[8]->what() == 'o')
+ return 'o';
+
+
+
+
+ if (tiles[0]->what() == 'x' && tiles[4]->what() == 'x' && tiles[8]->what() == 'x')
+ return 'x';
+ if (tiles[0]->what() == 'o' && tiles[4]->what() == 'o' && tiles[8]->what() == 'o')
+ return 'o';
+
+ if (tiles[2]->what() == 'x' && tiles[4]->what() == 'x' && tiles[6]->what() == 'x')
+ return 'x';
+ if (tiles[2]->what() == 'o' && tiles[4]->what() == 'o' && tiles[6]->what() == 'o')
+ return 'o';
+
+ bool tied = true;
+ for (int i = 0; i < 9; i++)
+ if (tiles[i]->what() == ' ')
+ tied = false;
+
+ if (tied) return 't';
+
+ return ' ';
+}
+
+
+bool Field::Click(int mouseX, int mouseY, char turn)
+{
+ for (int i = 0; i < 9; i++)
+ {
+ if (tiles[i]->what() == ' ')
+ {
+ if (tiles[i]->isClicked(mouseX, mouseY))
+ {
+ //printf("Clicked Tile %i", i);
+
+ sf::Vector2f pos = tiles[i]->getPosition();
+ if (turn == 'x')
+ tiles[i] = new Cross(pos.x, pos.y);
+ else
+ tiles[i] = new Circle(pos.x, pos.y);
+
+ return true;
+ }
+ }
+ //else {
+ // std::cout << "Mein Schwanz hurtet" << std::endl;
+ //}
+ }
+
+ return false;
+}
+
+void Field::Render(sf::RenderWindow& target)
+{
+ for (int i = 0; i < 4; i++)
+ target.draw(lines[i]);
+
+ for (int i = 0; i < 9; i++)
+ tiles[i]->Render(target);
+
+ // std::cout << std::endl;
+}
\ No newline at end of file
diff --git a/Tic Tac Toe/Field.hpp b/Tic Tac Toe/Field.hpp
new file mode 100644
index 0000000..3dff9b7
--- /dev/null
+++ b/Tic Tac Toe/Field.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include "Tile.hpp"
+
+class Field
+{
+public:
+ Field();
+
+ void Render(sf::RenderWindow& target);
+ char Update();
+ bool Click(int mouseX, int mouseY, char turn);
+
+private:
+ sf::RectangleShape lines[4];
+ Tile* tiles[9];
+};
+
diff --git a/Tic Tac Toe/Framework.cpp b/Tic Tac Toe/Framework.cpp
new file mode 100644
index 0000000..f7ea6ef
--- /dev/null
+++ b/Tic Tac Toe/Framework.cpp
@@ -0,0 +1,540 @@
+#include "Framework.hpp"
+
+#include
+#include
+
+Framework::Framework(uint width, uint height, std::string title)
+{
+ font = new sf::Font();
+ font->loadFromFile("C:/Windows/Fonts/lucon.ttf");
+
+ turn.setFont(*font);
+ turn.setString("Opponent's Turn");
+ turn.setCharacterSize(18);
+ turn.setPosition(10, 10);
+ turn.setFillColor(sf::Color::White);
+
+ winner.setFont(*font);
+ winner.setString("Placeholder");
+ winner.setCharacterSize(140);
+ winner.setStyle(sf::Text::Style::Bold);
+ winner.setPosition(100, 100);
+ winner.setFillColor(sf::Color(10, 255, 10));
+
+ m_width = width;
+ m_height = height;
+ m_title = title;
+
+ m_window = new sf::RenderWindow(sf::VideoMode(width, height), title, sf::Style::Close);
+ m_window->setFramerateLimit(120);
+
+ m_event = sf::Event();
+ m_clock = sf::Clock();
+
+ m_frametime = -1.0;
+
+ m_gameState = MAIN_MENU;
+ m_role = UNKNOWN;
+
+ m_host = Button("Host Game", 200, 200);
+ m_join = Button("Join Game", 200, 450);
+ m_newGame = Button("New Game", 200, 450);
+
+ m_ipField = InputField();
+
+ m_field = Field();
+
+ m_winner = ' ';
+
+ m_ip = "";
+
+ m_connected = false;
+ m_packageReceived = false;
+ m_myTurn = false;
+ m_mySymbol = 'o';
+ m_ready = true;
+ m_otherReady = true;
+
+ listener.setBlocking(false);
+
+ engine = std::default_random_engine{ static_cast(time(0)) };
+ range = std::uniform_int_distribution(0, 1);
+
+ m_clock.restart();
+
+}
+
+Framework::~Framework()
+{
+ delete m_window;
+ m_window = nullptr;
+}
+
+bool Framework::Run()
+{
+ if (m_window == nullptr)
+ {
+ std::cerr << "Framework was not initialized." << std::endl;
+ return false;
+ }
+
+ while (m_window->isOpen())
+ {
+ if (!HandleEvents())
+ return false;
+
+ if (!Update())
+ return false;
+
+ if (!Render())
+ return false;
+ }
+
+ return true;
+}
+
+
+void Framework::StartGame()
+{
+ m_gameState = IN_GAME;
+
+ // If host, determine who begins.
+ // if client, wait for host to call who begins
+
+ // If it is host's turn -> Let Host make turn, send client turn result
+ // If it is client's turn -> Let client make turn, send host turn result
+}
+
+
+bool Framework::HostGame()
+{
+ if (!m_connected)
+ {
+ m_role = HOST;
+
+ sf::Font font;
+ font.loadFromFile("C:/Windows/Fonts/lucon.ttf");
+
+ sf::Text text;
+ text.setFont(font);
+ text.setCharacterSize(48);
+ text.setFillColor(sf::Color::White);
+ text.setString("Waiting for connection...");
+ text.setOrigin(text.getLocalBounds().left + text.getLocalBounds().width / 2, text.getLocalBounds().top + text.getLocalBounds().height / 2);
+ text.setPosition(sf::Vector2f(400, 400));
+
+ sf::Text ip;
+ ip.setFont(font);
+ ip.setCharacterSize(24);
+ ip.setFillColor(sf::Color::White);
+ ip.setString("Your IP: " + m_ip.getPublicAddress().toString());
+ ip.setOrigin(ip.getLocalBounds().left + ip.getLocalBounds().width / 2, ip.getLocalBounds().top + ip.getLocalBounds().height / 2);
+ ip.setPosition(sf::Vector2f(400, 550));
+
+ m_window->draw(text);
+ m_window->draw(ip);
+
+
+
+ if (listener.accept(socket) == sf::Socket::Done)
+ {
+ m_connected = true;
+ m_gameState = READY;
+ socket.setBlocking(false);
+ }
+
+ return true;
+
+ }
+ else
+ {
+ if (m_gameState == READY)
+ {
+ int starter = range(engine);
+ std::cout << starter << std::endl;
+ /*LPCWSTR who = L"Nobody";
+ if (starter == true)
+ {
+ who = L"Opponent";
+ }
+ if (starter != true)
+ {
+ who = L"My turn";
+ }*/
+
+ // MessageBox(NULL, who, L"Host", MB_OK);
+
+ sf::Packet data;
+ data << starter;
+ if (socket.send(data) == sf::Socket::Done)
+ {
+ m_gameState = IN_GAME;
+
+ if (starter == 0) {
+ m_myTurn = true;
+ m_mySymbol = 'x';
+ turn.setString("Your Turn");
+ }
+ else
+ {
+ m_myTurn = false;
+ m_mySymbol = 'o';
+ turn.setString("Opponent's Turn");
+ }
+ }
+ }
+
+ if (m_gameState == IN_GAME)
+ {
+ // If not my turn, wait for package
+ sf::Packet data;
+ if (socket.receive(data) == sf::Socket::Done)
+ {
+ m_myTurn = true;
+ turn.setString("Your Turn");
+
+ int mouseX, mouseY;
+ int symb;
+
+ data >> mouseX >> mouseY >> symb;
+
+ m_field.Click(mouseX, mouseY, (char)symb);
+
+ printInfo(mouseX, mouseY, (char)symb);
+ }
+ }
+
+ if (m_gameState == GAME_OVER)
+ {
+ sf::Packet data;
+ if (socket.receive(data) == sf::Socket::Done)
+ {
+ m_otherReady = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+void Framework::printInfo(int x, int y, char turn)
+{
+ // std::cout << turn << " set piece at (" << x << ", " << y << ")" << std::endl;
+}
+
+
+bool Framework::JoinGame()
+{
+ if (!m_connected)
+ {
+ m_role = CLIENT;
+
+ if (socket.connect(m_ip, 30000, sf::Time(sf::seconds(3))) != sf::Socket::Done)
+ {
+ std::cerr << "Could not connect to " << m_ip << ":30000. Is the IP correct and port 30000 open on the host's PC?" << std::endl;
+ return false;
+ }
+
+ socket.setBlocking(false);
+
+ m_connected = true;
+ m_gameState = READY;
+ return true;
+ }
+ else
+ {
+ if (m_gameState == READY)
+ {
+ m_winner = ' ';
+ // Wait for Host to send data about who starts
+ sf::Packet data;
+ if (socket.receive(data) == sf::Socket::Done)
+ {
+ m_gameState = IN_GAME;
+ int starter;
+ data >> starter;
+ //LPCWSTR who = (starter) ? L"Me" : L"Other";
+ //MessageBox(NULL, who, L"Client", MB_OK);
+
+ std::cout << starter << std::endl;
+
+ if (starter == true)
+ {
+ m_myTurn = true;
+ m_mySymbol = 'x';
+ turn.setString("Your Turn");
+ }
+ else
+ {
+ m_myTurn = false;
+ m_mySymbol = 'o';
+ turn.setString("Opponent's Turn");
+ }
+ }
+ }
+
+ if (m_gameState == IN_GAME)
+ {
+ // If not my turn, wait for package
+ sf::Packet data;
+ if (socket.receive(data) == sf::Socket::Done)
+ {
+ m_myTurn = true;
+ turn.setString("Your Turn");
+
+ int mouseX, mouseY;
+ int symb;
+
+ data >> mouseX >> mouseY >> symb;
+
+ m_field.Click(mouseX, mouseY, (char)symb);
+
+ printInfo(mouseX, mouseY, (char)symb);
+ }
+ }
+
+ if (m_gameState == GAME_OVER)
+ {
+ sf::Packet data;
+ if (socket.receive(data) == sf::Socket::Done)
+ {
+ m_gameState = READY;
+ m_field = Field();
+ m_newGame.enable();
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool Framework::HandleEvents()
+{
+ while (m_window->pollEvent(m_event))
+ {
+ switch (m_event.type)
+ {
+ case sf::Event::Closed:
+ m_window->close();
+ break;
+
+ case sf::Event::MouseButtonReleased:
+ {
+ if (m_gameState == MAIN_MENU)
+ {
+ if (m_host.isClicked(sf::Mouse::getPosition(*m_window).x, sf::Mouse::getPosition(*m_window).y))
+ {
+ m_gameState = CONNECTING;
+ m_role = HOST;
+
+ if (listener.listen(30000) != sf::Socket::Done)
+ {
+ std::cerr << "Could not listen for incoming requests at port 30000" << std::endl;
+ return false;
+ }
+ }
+
+ if (m_join.isClicked(sf::Mouse::getPosition(*m_window).x, sf::Mouse::getPosition(*m_window).y))
+ {
+ m_gameState = JOIN_GAME;
+ }
+ }
+
+
+ if (m_gameState == IN_GAME && m_myTurn)
+ {
+ if (!m_field.Click(sf::Mouse::getPosition(*m_window).x, sf::Mouse::getPosition(*m_window).y, m_mySymbol))
+ break;
+
+ m_myTurn = false;
+ turn.setString("Opponent's Turn");
+
+ sf::Packet data;
+ data << sf::Mouse::getPosition(*m_window).x << sf::Mouse::getPosition(*m_window).y << m_mySymbol;
+ socket.send(data);
+ }
+
+
+ if (m_gameState == GAME_OVER)
+ {
+ if (m_newGame.isClicked(sf::Mouse::getPosition(*m_window).x, sf::Mouse::getPosition(*m_window).y))
+ {
+ if (m_role == HOST) {
+ m_ready = true;
+ m_newGame.disable();
+ }
+
+ if (m_role == CLIENT)
+ {
+ m_newGame.disable();
+
+ sf::Packet data;
+ data << true;
+ if (socket.send(data) == sf::Socket::Done)
+ break;
+ }
+ }
+
+ }
+ } break;
+
+ case sf::Event::KeyPressed:
+ {
+ if (m_gameState == JOIN_GAME)
+ {
+ if (m_event.key.code == sf::Keyboard::Return) {
+ m_ip = sf::IpAddress(m_ipField.Enter());
+ m_role = CLIENT;
+ m_gameState = CONNECTING;
+ }
+
+ if (m_event.key.code == sf::Keyboard::BackSpace)
+ m_ipField.Backspace();
+
+ if (m_event.key.code == sf::Keyboard::Period)
+ m_ipField.Type('.');
+
+ for (int key = sf::Keyboard::Num0; key <= sf::Keyboard::Num9; key++)
+ {
+ if(m_event.key.code == key)
+ m_ipField.Type(key + 22);
+ }
+ }
+ } break;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool Framework::Update()
+{
+ m_window->clear(sf::Color::Black);
+ CalculateFrametime();
+
+ int FPS = floor(1 / m_frametime);
+ m_window->setTitle(m_title + " | " + std::to_string(FPS) + " FPS");
+
+ int mouseX = sf::Mouse::getPosition(*m_window).x;
+ int mouseY = sf::Mouse::getPosition(*m_window).y;
+
+ if (m_gameState == MAIN_MENU)
+ {
+ m_host.Update(mouseX, mouseY);
+ m_join.Update(mouseX, mouseY);
+ }
+
+ if (m_gameState == IN_GAME || m_gameState == READY || m_gameState == GAME_OVER || m_gameState == CONNECTING)
+ {
+ if (m_role == HOST)
+ HostGame();
+
+ if (m_role == CLIENT)
+ JoinGame();
+
+
+ }
+
+ if (m_gameState == GAME_OVER)
+ {
+ m_myTurn = false;
+
+ if (m_winner == m_mySymbol) {
+ winner.setString("You won!");
+ winner.setOrigin(winner.getLocalBounds().left + winner.getLocalBounds().width / 2, winner.getLocalBounds().top + winner.getLocalBounds().height / 2);
+ winner.setPosition(m_window->getSize().x / 2, m_window->getSize().y / 4);
+ }
+
+ if (m_winner != m_mySymbol) {
+ if (m_winner == 't')
+ {
+ winner.setString("Tie!");
+ winner.setOrigin(winner.getLocalBounds().left + winner.getLocalBounds().width / 2, winner.getLocalBounds().top + winner.getLocalBounds().height / 2);
+ winner.setPosition(m_window->getSize().x / 2, m_window->getSize().y / 4);
+ }
+ else {
+ winner.setString("You lost!");
+ winner.setOrigin(winner.getLocalBounds().left + winner.getLocalBounds().width / 2, winner.getLocalBounds().top + winner.getLocalBounds().height / 2);
+ winner.setPosition(m_window->getSize().x / 2, m_window->getSize().y / 4);
+ }
+
+ }
+
+
+ m_newGame.Update(mouseX, mouseY);
+
+ if (m_ready && m_otherReady)
+ {
+ m_gameState = READY;
+ m_ready = false;
+ m_otherReady = false;
+
+ m_field = Field();
+
+ m_newGame.enable();
+
+ sf::Packet data;
+ data << true;
+ socket.send(data) == sf::Socket::Done;
+ }
+
+ // std::cout << "Host: " << m_ready << std::endl << "Client: " << m_otherReady << std::endl << std::endl;
+
+ }
+
+ if (m_gameState != GAME_OVER)
+ {
+ m_winner = m_field.Update();
+
+ if (m_winner != ' ') {
+ m_gameState = GAME_OVER;
+ m_ready = false;
+ m_otherReady = false;
+ }
+ }
+
+
+ return true;
+}
+
+
+bool Framework::Render()
+{
+
+ if (m_gameState == MAIN_MENU)
+ {
+ m_host.Render(*m_window);
+ m_join.Render(*m_window);
+ }
+
+ if (m_gameState == JOIN_GAME)
+ {
+ m_ipField.Render(*m_window);
+ }
+
+ if (m_gameState == IN_GAME || m_gameState == GAME_OVER)
+ {
+ m_field.Render(*m_window);
+ m_window->draw(turn);
+ }
+
+ if (m_gameState == GAME_OVER)
+ {
+ m_window->draw(winner);
+ m_newGame.Render(*m_window);
+ }
+
+ m_window->display();
+ return true;
+}
+
+void Framework::CalculateFrametime()
+{
+ m_frametime = m_clock.getElapsedTime().asSeconds();
+ m_clock.restart();
+}
\ No newline at end of file
diff --git a/Tic Tac Toe/Framework.hpp b/Tic Tac Toe/Framework.hpp
new file mode 100644
index 0000000..db6840d
--- /dev/null
+++ b/Tic Tac Toe/Framework.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "Button.hpp"
+#include "InputField.hpp"
+#include "Field.hpp"
+#include "Tile.hpp"
+#include "Util.h"
+
+typedef unsigned short uint;
+
+struct Packet
+{
+ int mouseX, mouseY;
+ bool winCondition;
+};
+
+class Framework
+{
+public:
+ Framework(uint width, uint height, std::string title);
+ ~Framework();
+
+ bool Run();
+
+private:
+ bool HandleEvents();
+ bool Update();
+ bool Render();
+
+ void CalculateFrametime();
+
+ bool HostGame();
+ bool JoinGame();
+
+ void StartGame();
+
+ void printInfo(int x, int y, char turn);
+
+private:
+ sf::RenderWindow* m_window;
+ sf::Event m_event;
+ sf::Clock m_clock;
+
+ uint m_width;
+ uint m_height;
+ std::string m_title;
+
+ Button m_host, m_join, m_newGame;
+ InputField m_ipField;
+ Field m_field;
+
+ sf::IpAddress m_ip;
+
+ GameState m_gameState;
+ Role m_role;
+
+ sf::TcpListener listener;
+ sf::TcpSocket socket;
+
+ sf::Text turn;
+ sf::Text winner;
+ sf::Font* font;
+
+ std::default_random_engine engine;
+ std::uniform_int_distribution range;
+
+ bool m_packageReceived;
+ bool m_connected;
+ bool m_myTurn;
+ char m_winner;
+ char m_mySymbol;
+ bool m_ready, m_otherReady;
+
+ long double m_frametime;
+};
+
diff --git a/Tic Tac Toe/InputField.cpp b/Tic Tac Toe/InputField.cpp
new file mode 100644
index 0000000..4a63e48
--- /dev/null
+++ b/Tic Tac Toe/InputField.cpp
@@ -0,0 +1,63 @@
+#include "InputField.hpp"
+
+
+
+InputField::InputField()
+{
+ value = "";
+
+ font = new sf::Font();
+ font->loadFromFile("C:/Windows/Fonts/lucon.ttf");
+
+ field.setFillColor(sf::Color(10, 10, 10));
+ field.setOutlineThickness(5);
+ field.setOutlineColor(sf::Color(60, 60, 60));
+ field.setSize(sf::Vector2f(450, 50));
+ field.setPosition(sf::Vector2f(250, 350));
+
+ input.setFont(*font);
+ input.setString(value);
+ input.setCharacterSize(32);
+ input.setPosition(sf::Vector2f(260, 350));
+
+ info.setFont(*font);
+ info.setString("Enter IP:");
+ info.setCharacterSize(32);
+ info.setPosition(sf::Vector2f(50, 350));
+}
+
+
+InputField::~InputField()
+{
+}
+
+void InputField::updateText()
+{
+ input.setString(value);
+}
+
+void InputField::Type(char letter)
+{
+ value += letter;
+ updateText();
+}
+
+std::string InputField::Enter()
+{
+ return value;
+}
+
+void InputField::Backspace()
+{
+ if(value != "")
+ value.pop_back();
+
+ updateText();
+}
+
+void InputField::Render(sf::RenderWindow& target)
+{
+ target.draw(field);
+ target.draw(input);
+ target.draw(info);
+}
diff --git a/Tic Tac Toe/InputField.hpp b/Tic Tac Toe/InputField.hpp
new file mode 100644
index 0000000..961d892
--- /dev/null
+++ b/Tic Tac Toe/InputField.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+
+class InputField
+{
+public:
+ InputField();
+ ~InputField();
+
+ void Type(char letter);
+ std::string Enter();
+ void Backspace();
+
+ void Render(sf::RenderWindow& target);
+
+private:
+ void updateText();
+
+ std::string value;
+
+ sf::Text info;
+ sf::Text input;
+ sf::Font* font;
+
+ sf::RectangleShape field;
+};
+
diff --git a/Tic Tac Toe/Tic Tac Toe.vcxproj b/Tic Tac Toe/Tic Tac Toe.vcxproj
new file mode 100644
index 0000000..83eeeb5
--- /dev/null
+++ b/Tic Tac Toe/Tic Tac Toe.vcxproj
@@ -0,0 +1,191 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {271F58BA-B409-47FD-8EBE-D6202A17DAE6}
+ Win32Proj
+ TicTacToe
+ 8.1
+
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDebug
+
+
+ Windows
+ true
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDebug
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tic Tac Toe/Tic Tac Toe.vcxproj.filters b/Tic Tac Toe/Tic Tac Toe.vcxproj.filters
new file mode 100644
index 0000000..fecb67a
--- /dev/null
+++ b/Tic Tac Toe/Tic Tac Toe.vcxproj.filters
@@ -0,0 +1,66 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {17b14c9e-62d8-40e8-888e-f41312f89b60}
+
+
+ {f29d80d9-034f-463e-b7fc-a5979facd64d}
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files\GUI
+
+
+ Source Files\GUI
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files\GUI
+
+
+ Header Files
+
+
+ Header Files\GUI
+
+
+ Header Files
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tic Tac Toe/Tile.cpp b/Tic Tac Toe/Tile.cpp
new file mode 100644
index 0000000..191210d
--- /dev/null
+++ b/Tic Tac Toe/Tile.cpp
@@ -0,0 +1,101 @@
+#include "Tile.hpp"
+
+#include
+
+Tile::Tile()
+{
+}
+
+Tile::Tile(int posX, int posY)
+{
+ size = sf::Vector2f(200, 200);
+ active = false;
+
+ position = sf::Vector2f(posX, posY);
+
+ frame.setFillColor(sf::Color::Black);
+ frame.setOutlineThickness(-5);
+ frame.setOutlineColor(sf::Color::Green);
+ frame.setSize(size);
+ frame.setPosition(position);
+}
+
+
+Tile::~Tile()
+{
+}
+
+bool Tile::isClicked(int mouseX, int mouseY)
+{
+ if (mouseX > position.x && mouseX < position.x + size.x && mouseY > position.y && mouseY < position.y + size.y)
+ return true;
+
+ return false;
+}
+
+void Tile::Render(sf::RenderWindow& target)
+{
+ // target.draw(frame);
+}
+
+
+
+Cross::Cross()
+{
+
+}
+
+Cross::Cross(int posX, int posY) :
+ Tile(posX, posY)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ lines[i].setFillColor(sf::Color(255, 50, 50));
+ lines[i].setSize(sf::Vector2f(180, 10));
+ lines[i].setOrigin(sf::Vector2f(lines[i].getGlobalBounds().left + lines[i].getLocalBounds().width / 2,
+ lines[i].getGlobalBounds().top + lines[i].getLocalBounds().height / 2));
+ lines[i].setPosition(posX + 100, posY + 100);
+
+ }
+
+ lines[0].rotate(45);
+ lines[1].rotate(-45);
+}
+
+void Cross::Render(sf::RenderWindow& target)
+{
+ Tile::Render(target);
+
+ target.draw(lines[0]);
+ target.draw(lines[1]);
+}
+
+
+
+
+
+
+
+Circle::Circle()
+{
+
+}
+
+Circle::Circle(int posX, int posY) :
+ Tile(posX, posY)
+{
+ cir.setRadius(90);
+ cir.setOutlineThickness(-10);
+ cir.setOutlineColor(sf::Color(10, 10, 255));
+ cir.setOrigin(sf::Vector2f(cir.getGlobalBounds().left + cir.getLocalBounds().width / 2,
+ cir.getGlobalBounds().top + cir.getLocalBounds().height / 2));
+ cir.setPosition(posX + 100, posY + 100);
+ cir.setFillColor(sf::Color::Black);
+}
+
+void Circle::Render(sf::RenderWindow& target)
+{
+ Tile::Render(target);
+
+ target.draw(cir);
+}
\ No newline at end of file
diff --git a/Tic Tac Toe/Tile.hpp b/Tic Tac Toe/Tile.hpp
new file mode 100644
index 0000000..63ca1c6
--- /dev/null
+++ b/Tic Tac Toe/Tile.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include
+
+class Tile
+{
+public:
+ Tile();
+ Tile(int posX, int posY);
+ ~Tile();
+
+ virtual void Render(sf::RenderWindow& target);
+ virtual char what() { return ' '; }
+ bool isClicked(int mouseX, int mouseY);
+
+ bool isActive() { return active; }
+
+ sf::Vector2f getPosition() { return position; }
+
+private:
+ bool active;
+
+ sf::RectangleShape frame;
+
+protected:
+ sf::Vector2f position;
+ sf::Vector2f size;
+};
+
+
+
+class Cross : public Tile
+{
+public:
+ Cross();
+ Cross(int posX, int posY);
+
+ void Render(sf::RenderWindow& target) override;
+ char what() { return 'x'; }
+
+private:
+ sf::RectangleShape lines[2];
+};
+
+
+class Circle : public Tile
+{
+public:
+ Circle();
+ Circle(int posX, int posY);
+
+ void Render(sf::RenderWindow& target) override;
+ char what() { return 'o'; }
+
+private:
+ sf::CircleShape cir;
+};
\ No newline at end of file
diff --git a/Tic Tac Toe/Util.h b/Tic Tac Toe/Util.h
new file mode 100644
index 0000000..e14597c
--- /dev/null
+++ b/Tic Tac Toe/Util.h
@@ -0,0 +1,19 @@
+#pragma once
+
+enum GameState
+{
+ MAIN_MENU,
+ READY,
+ IN_GAME,
+ GAME_OVER,
+ HOST_GAME,
+ JOIN_GAME,
+ CONNECTING
+};
+
+enum Role
+{
+ UNKNOWN,
+ HOST,
+ CLIENT
+};
\ No newline at end of file
diff --git a/Tic Tac Toe/main.cpp b/Tic Tac Toe/main.cpp
new file mode 100644
index 0000000..8db8999
--- /dev/null
+++ b/Tic Tac Toe/main.cpp
@@ -0,0 +1,20 @@
+#include
+#include
+#include "Framework.hpp"
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nShowCmd)
+{
+ Framework frmwrk(800, 800, "Tic Tac Toe, x64");
+
+ if (!frmwrk.Run())
+ {
+ std::cerr << "Runtime Error." << std::endl;
+ return 1;
+ }
+
+
+ return 0;
+}
\ No newline at end of file
diff --git a/Tic Tac Toe/packages.config b/Tic Tac Toe/packages.config
new file mode 100644
index 0000000..3468d45
--- /dev/null
+++ b/Tic Tac Toe/packages.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file