2023-03-25 15:54:23 +01:00
2023-03-25 15:54:23 +01:00
2023-03-25 13:21:07 +01:00
2023-03-25 13:21:07 +01:00
2023-03-25 14:10:33 +01:00
2023-03-25 13:21:07 +01:00
2023-03-25 13:21:07 +01:00
2023-03-25 13:21:07 +01:00
2023-03-25 14:10:33 +01:00
2023-03-25 15:54:23 +01:00

FairHopper

Game

Overview

  • Rectangle board W × H
  • Destination: center of a board (W / 2, H / 2)
  • Initial player position: Random on board border
  • Available moves:
    • left
    • right
    • up
    • down
  • Optional on-board obstacles

Rules

  • Goal: Reach the goal destination
  • Player can't move out of board
  • Player can't move if destination position contains obstacle
  • Move timeout: 10s. Game is finished if timeout ocurrs.

FairHopper Game Server

Requirements:

  • Python 3.10+

Install virtual envirnonment

Project uses Poetry, ultimate dependency management software for Python.

Install Poetry:

pip install poetry

Install virtual environment:

poetry install

Setting up

Copy settings_template.py to settings.py.

Edit settings.py and customize application.

Starting FairHopper Game Server

make run

By default, JFK runs on port 8010. To run on other port, start uvicorn directly:

poetry run uvicorn main:app --host 0.0.0.0 --port 8010 --workers=1

To activate virtual environment:

poetry shell

System overview

Architecture

actor "Player 1" as P1
actor "Player 2" as P2
actor "Player 3" as P3

package Masterpiece {
    usecase JFK as "JFK Game Server"
    usecase WS as "WS Server"
    usecase Vis as "Visualisation\nService"
}

P1 -left-> JFK: REST API
P2 -left-> JFK: REST API
P3 -left-> JFK: REST API
JFK --> WS: WebSockets
WS --> Vis: WebSockets

WebSockets

    participant JFK as "JFK Game Server"
    participant WS as "WS Server"
    participant Client1 as "Visualisation\nClient 1"
    participant Client2 as "Visualisation\nClient 2"

    JFK ->o WS: Server Connect
    activate WS #coral
        WS -> JFK: Get game state
        activate JFK #yellow
            JFK -> WS: Game state
        deactivate
    deactivate

    Client1 ->o WS: Client Connect
    activate WS #coral
        WS -> Client1: Game state
    deactivate

    Client2 ->o WS: Client Connect
    activate WS #coral
        WS -> Client2: Game state
    deactivate

    loop #lightyellow On game state change
    JFK ->o WS: Game state
    activate WS #coral
        WS o-> Client1: Game state
        WS o-> Client2: Game state
    deactivate
end

REST API

  • Start game
  • Move left
  • Move right
  • Move up
  • Move down
  • Get current position
  • Get board info

Check REST API interface on FastAPI docs.

Start game

Endpoint: POST /game

Request body:

{
	"player_name": "Pero"
}

Response body:

{
	"board": {
		"width": 101,
		"height": 101
	},
	"destination": {
		"position": {
			"x": 50,
			"y": 50
		},
	},
	"player": {
		"uuid": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
		"position": {
			"x": 0,
			"y": 10
		},
		"move_count": 0,
		"move_attempt_count": 0
	}
}

Player Move

POST /player/{uuid}/move/left POST /player/{uuid}/move/right POST /player/{uuid}/move/up POST /player/{uuid}/move/down

Request body: None

Response code:

  • 200 OK: Destination reached
  • 201 Created: Player moved successfully
  • 403 Forbidden: Player uuid not valid, probably timeout
  • 409 Conflict: Invalid move, obstacle or position out of board
  • 422 Unprocessable Content: Validation error

Response body:

{
	"player": {
		"uuid": "string",
		"position": {
			"x": 50,
			"y": 50
		},
		"move_count": 10,
		"move_attempt_count": 12
	}
}

Get Player Info

GET /player/{{uuid}}

Request body: None

Response body:

{
	"player": {
		"uuid": "string",
		"position": {
			"x": 50,
			"y": 50
		},
		"move_count": 10,
		"move_attempt_count": 12
	}
}

Get Game Info

GET /game

Response body:

{
	"playerId": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
	"board": {
		"width": 101,
		"height": 101
	},
	"destinationPosition": {
		"x": 50,
		"y": 50
	},
	"playerPosition": {
		"x": 0,
		"y": 10
	}
}

WebSockets

WS Data format

  • json

General data format:

{
	"command": "command",
	"data": {}
}

Game info structure

Command: gameInfo

Data:

{
	"board": {
		"width": 101,
		"height": 101
	},
	"destinationPosition": {
		"x": 50,
		"y": 50
	},
	"players": [
		{
			"id": "75bba7cd-a4c1-4b50-b0b5-6382c2822a25",
			"name": "Pero",
			"position": {
				"x": 0,
				"y": 10
			}
		},
		{
			"id": "04793b36-0785-4bf3-9396-3585c358cbac",
			"name": "Mirko",
			"position": {
				"x": 11,
				"y": 12
			}
		}
	],
	"layers": [
		{
			"name": "obstacles",
			"objects": [
				{
					"type": "obstacle",
					"position": {
						"x": 15,
						"y": 25
					}
				},
				{
					"type": "obstacle",
					"position": {
						"x": 33,
						"y": 44
					}
				}
			]
		}
	]
}
Description
No description provided
Readme 502 KiB
Languages
Python 75.9%
JavaScript 11%
HTML 5%
Dockerfile 2.8%
Makefile 2.6%
Other 2.7%