⬆️ ⬇️

Mafia on Go, Vanila JS and WebSocket





It's about the web-implementation of the popular card game " Mafia ". It was written for fun and experience in game development. The first version was written in two weeks of free time from work and for the same time was rewritten before the second version. Plus this game - the absence of a lead.



Based on the development goals, I made decisions on the implementation / non-implementation of features.

What exactly needed to be done:





What was not planned or could be postponed:

')



Backend



https://github.com/mrsuh/mafia-backend

Written on Go. Keeps the state of the game and is responsible for its logic.



During the game, you can contact the server to find out the full information:



curl 'http://127.0.0.1:8000/info?game=23' | python -m json.tool 


Display information about the game
{

"event": "greet_mafia",

"event_status": 2,

"id": 23,

"is_over": false,

"iter": 1,

"players": [

{

"addr": "172.18.0.1:51438",

"createdAt": "2018-09-23T14:39:29.631475779Z",

"id": 33309,

"name": "Anton",

"role": 4

},

{

"addr": "172.18.0.1:51440",

"createdAt": "2018-09-23T14:39:32.867080927Z",

"id": 5457,

"name": "username:0",

"role": 2

},

{

"addr": "172.18.0.1:51442",

"createdAt": "2018-09-23T14:39:32.882463945Z",

"id": 14214,

"name": "username:2",

"role": 1

},

{

"addr": "172.18.0.1:51444",

"createdAt": "2018-09-23T14:39:32.895209072Z",

"id": 63759,

"name": "username:1",

"role": 3

}

],

"win": 0

}




Or find out the status of the server:



 curl 'http://127.0.0.1:8000/health' | python -m json.tool 


Displays server status information
{

"runtime.MemStats.Alloc": 764752,

"runtime.MemStats.NumGC": 0,

"runtime.MemStats.Sys": 4165632,

"runtime.MemStats.TotalAlloc": 764752,

"runtime.NumGoroutine": 14

}




To determine if the player is still active, the backend sends heartbeat. If the player does not answer after a certain interval, then he leaves the game. At the same time, if a player reconnects before the end of the interval (the network is gone), then he can continue the game.



For stable operation, the backend was covered by Unit tests with the standard Go library , where the main work scenarios are checked.



 go test mafia-backend/src -cover ok mafia-backend/src 1.315s coverage: 70.7% of statements 


Frontend



https://github.com/mrsuh/mafia-frontend

Written in pure JS and compiled using Grunt .

Does not carry any logic.



When an event occurs with a backend, it renders the necessary page, displays the data that was sent to it and plays the sound of a new event.



Frontend stores the game ID and player ID in LocalStorage or the browser's request bar (if you need to run multiple tabs for different players in one browser). The complete absence of logic, as well as the storage of the basic parameters of the game, make it possible, even after reloading the page, to restore the state of the game.



The browser prohibits the autoplay of sounds without user intervention (for example, pressing a button). In order to play sounds for each event, only 1 JavaScript Audio object was made with the backend. Each player must press the button to start the game and at this point the Audio object becomes active (available for playback), and subsequently it can change the src parameter to play different sounds without user intervention.



Also to test the work of the game was written "bot", which can play with itself.

Just open the browser tab, where the parameters indicate that you need to run the test



 http://127.0.0.1?master=1&test=1&sound=0&testUsersCount=5 


and allow opening new tabs from javascript for this domain.

After the start of the game, 5 more tabs with players will open and they will start playing among themselves.



Interaction protocol



The WebSocket protocol was chosen because of the need for constant two-way data exchange between the backend and frontend and its support in both languages.



Game events



The whole game is divided into events:



Developments
  • game

    • create
    • join
    • start
    • over
    • reconnect


  • day

    • start


  • night

    • start


  • citizens-greeting

    • start
    • role
    • end


  • mafia-greeting

    • start
    • players
    • end


  • court

    • start
    • players
    • end


  • mafia

    • start
    • players
    • end


  • doctor

    • start
    • players
    • end


  • girl

    • start
    • players
    • end


  • sherif

    • start
    • players
    • end






Events have a beginning, an end and a meaningful part.

At the beginning and end of the event, a notification is sent to all active players that needs to be confirmed. The game continues only after the confirmation of this event by all active players (for example, only after the sound file is played).



Docker



The whole game can be raised using Docker :

docker-compose.yml



 version: '3' services: mafia-frontend: image: mrsuh/mafia-frontend:latest container_name: mafia_frontend ports: - 9080:80 mafia-backend: image: mrsuh/mafia-backend:latest container_name: mafia_backend ports: - 8000:8000 


It is enough to install Docker (if you have not already done this), copy the docker-compose.yml text to yourself and execute the command:



 docker-compose up 


After that, you can open the tab with the game in the browser:



 http://127.0.0.1:9080 


Conclusion



Here you can see what happened (playback speed increased by 1.5 times).





After nearly a month of development in my spare time, I got a fairly stable game that you can play with friends. The game can withstand page reload or temporary network loss. Voice events on the devices works, albeit without time synchronization. Further development of the game is not planned.



PS: Thanks Lera for the voice acting of the game.

Source: https://habr.com/ru/post/423821/



All Articles