Commit 377e1b40 authored by bbguimaraes's avatar bbguimaraes
Browse files

sockets

parent 74983e80
......@@ -7,5 +7,7 @@ for details/demos/screenshots.
and filtering.
- mem_manager: best-fit memory allocator simluation.
- nqueens: n-queens solver and graphical display.
- sockets: an implementation of the game Jungle ("Dou Shou Qi", in Chinese)
with graphics and network communication.
- sudoku: Sudoku solver library/GUI using genetic algorithms.
- tablut: ANSI C / ncurses implementation of the game Tablut.
An implementation of the game [Jungle ("Dou Shou Qi", in Chinese)](jungle) that
uses sockets for communication.
[jungle]: https://en.wikipedia.org/wiki/Jungle_%28board_game%29
# Compilation
The GUI is done using the qt toolkit and opengl. Standard unix sockets are
used for the communication. After installing qt, execute:
$ qmake
$ make
# Running
The generated binary is both a client and a server. The only difference is the
server must be running before the client tries to make a connection.
Additionally, the server always gets the first move.
The program can be executed in two ways: with no arguments, a little GUI window
is used to configure the player name and the server address/port (for listening
or for connecting). These arguments can also be provided as arguments to the
program. In that case, the configuration window is not displayed.
$ ./sockets billy &
$ ./sockets bob 127.0.0.1 &
& wait
# Communication
The protocol is really simple, and consists of an initial value indicating the
type of message followed by the message value. This value can be a "quit",
indicating the other player has left the game, or either a "movement" or
"victory" message. These two last types are followed by the movement from the
other player.
There are very few checks made on the communication channel, so a malicious
player can do almost anything: move the other player's characters, crashing the
game, etc.
# Testing
The `test` directory contains some scripts that are useful for testing. The
file `test/single.c` can be compiled into a program that will try to connect on
`127.0.0.1:8000` and will loop moving its rat between its original spot and the
spot next to it.
It also has some options to run both a client and a server on the same
terminal, with the possibility to run one of them in gdb.
#ifndef COLOR_H
#define COLOR_H
class Color {
float m_r, m_g, m_b, m_a;
public:
Color(float r, float g, float b, float a = 1.0f) :
m_r(r),
m_g(g),
m_b(b),
m_a(a) {}
Color() : Color(0.0f, 0.0f, 0.0f, 1.0f) {}
Color(int r, int g, int b, int a = 255) : Color(
(r / 255.0f),
(g / 255.0f),
(b / 255.0f),
(a / 255.0f)) {}
float r() const {return m_r;}
float g() const {return m_g;}
float b() const {return m_b;}
float a() const {return m_a;}
};
#endif // COLOR_H
#ifndef GAME_CONTROLLER_H
#define GAME_CONTROLLER_H
#include <algorithm>
#include <list>
#include <QObject>
#include "model/Game.h"
class Character;
class Tile;
class TcpSocket;
class GameController : public QObject {
Q_OBJECT
public:
enum class Message {MOVEMENT, VICTORY, QUIT};
GameController(Game * game, TcpSocket * socket);
Game::State state() const {return this->m_game->state();}
Point highlighted() {return this->m_highlighted;}
const Point selected() {return this->m_selected;}
bool has_selected() {return this->m_selected != Point(-1, -1);}
bool has_highlighted() {return this->m_highlighted != Point(-1, -1);}
void set_socket(TcpSocket * socket) {this->m_socket = socket;}
void set_selected(const Point & p);
void set_highlighted(const Point & p) {this->m_highlighted = p;}
void clear_selected();
void clear_highlighted() {this->set_highlighted({-1, -1});}
const Character * character_at(const Point & p) const;
bool move_possible(const Point & p);
void click(const Point & p);
void check_for_other();
void send_quit_message();
void update();
signals:
void character_select(const Character * c);
void character_moved(const Character * c, const Point & orig);
void character_attacked(const Character * c, const Point & orig);
private:
void popup_on_gl_error();
void handle_selection(const Point & p);
void handle_move(const Point & p);
void handle_attack(const Point & p);
void send_move_message(const Point & orig, const Point & dest);
void send_victory_message(const Point & orig, const Point & dest);
Game * m_game;
Point m_highlighted;
Point m_selected;
std::list<Point> m_possible_moves;
TcpSocket * m_socket;
};
#endif // GAME_CONTROLLER_H
#ifndef GAME_DISPLAY_H
#define GAME_DISPLAY_H
#include <vector>
#include <QGLWidget>
class Character;
class Color;
class GameController;
class Point;
class Texture;
class Tile;
class GameDisplay : public QGLWidget {
Q_OBJECT
public:
GameDisplay(QWidget * parent = nullptr);
~GameDisplay();
void set_game_controller(GameController * c) {m_controller = c;}
void send_quit_message();
public slots:
void update_display();
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
virtual void mouseMoveEvent(QMouseEvent * event);
virtual void mousePressEvent(QMouseEvent * event);
virtual void mouseReleaseEvent(QMouseEvent * event);
private:
struct Texture {
enum {
RAT, CAT, DOG, WOLF, PANTHER, TIGER, LION, ELEPHANT,
GRASS, WATER, TRAP, DEN,
};
};
std::vector<::Texture *> load_textures();
std::vector<Tile *> create_tiles();
void pick(const QPoint & position);
void draw_grid();
void draw_objects();
void draw_tile(const Tile * t, const Color & c, const Point & p);
void draw_character(const Character * t, const Point & p);
bool should_highlight(const Point & p);
static const float GRID_SIZE;
static const float WIDTH;
static const float HEIGHT;
GameController * m_controller;
GLenum m_mode;
float m_angles[3];
std::vector<::Texture *> m_textures;
std::vector<Tile *> m_tiles;
std::vector<Tile *> m_character_tiles;
};
#endif
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <QWidget>
class QListWidget;
class QTimer;
class GameDisplay;
class SelectedPanel;
class Character;
class Point;
class MainWindow : public QWidget {
Q_OBJECT
public:
MainWindow(QWidget * parent, GameDisplay * display);
QTimer * timer() const {return this->m_timer;}
public slots:
void character_select(const Character * c);
void character_move(const Character * c, const Point & orig);
void character_attack(const Character * c, const Point & orig);
protected:
virtual void closeEvent(QCloseEvent * event);
private:
void init();
GameDisplay * m_display;
SelectedPanel * m_selected_panel;
QListWidget * m_list;
QTimer * m_timer;
};
#endif // MAIN_WINDOW_H
#ifndef OPEN_DIALOG_H
#define OPEN_DIALOG_H
#include <string>
#include <QDialog>
class QCheckBox;
class QLineEdit;
class QPushButton;
class OpenDialog : public QDialog {
Q_OBJECT
public:
OpenDialog(QWidget * parent = nullptr);
std::string name() const;
bool is_server() const;
std::string addr() const;
public slots:
void set_server_mode();
private:
void init();
QLineEdit * m_name_edit;
QCheckBox * m_is_server_check;
QLineEdit * m_addr_edit;
QPushButton * m_ok_button;
};
#endif // OPEN_DIALOG_H
#ifndef SELECTED_PANEL_H
#define SELECTED_PANEL_H
#include <QWidget>
class Character;
class QLabel;
class SelectedPanel : public QWidget {
Q_OBJECT
public:
SelectedPanel(QWidget * parent = 0);
public slots:
void set_selected(const Character * selected);
private:
void init();
void clear_fields();
QLabel * m_name_label;
QLabel * m_value_label;
};
#endif // SELECTED_PANEL_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment