Your task is to implement battleship game backend using websocket.
Player interface for your battleship backend is here. You should clone or copy this repository and write the code there.
The backend should be able to do the following:
- Start websocket server
- Handle websocket connection
- Handle player requests
- Handle room requests
- Handle ships requests
- Handle game requests
- Create single play bot (optional)
- Task can be implemented on Javascript or Typescript
- Use 22.x.x version (22.9.0 or upper) of Node.js
- Only ws,
cross-env
,typescript
,tsx
,ts-node
,ts-node-dev
,nodemon
,dotenv
,eslint
and its plugins,webpack
and its plugins,prettier
,@types/*
and testing tools (for example, Jest, Mocha, AVA, Jasmine, Cypress, Storybook, Puppeteer) are allowed - The program is started by npm script
start
in following way: - All requests and responses must be sent as JSON string
npm run start
- After starting the program displays websocket parameters
- After program work finished the program should end websocket work correctly
- After each received command program should display the command and result
- personal response
- reg - player registration/login
- response for the game room
- create_game - game id and player id (unique id for user in this game)
- start_game - informationa about game and player's ships positions
- turn - who is shooting now
- attack - coordinates of shot and status
- finish - id of the winner
- response for all
- update_room - list of rooms and players in rooms
- update_winners - send score table to players
- We should have inmemory DB with player data (login and password) storage
- Player can create game room or connect to the game room after login
- Player room data (players, game board, ships positions) storages in the server
- Game starts after 2 players are connected to the room and sent ships positions to the server
- Server sends move order
- Players should shoot in their's turn
- Server send back shot result
- If player hits or kills the ship, player should make one more shoot
- Player wins if he have killed all enemies ships
List of websocket commands (requests/responses) and their syntax (<- - cmd from frontend, -> - answer):
- Player
- Login or create player
<-
{ type: "reg", data: { name: <string>, password: <string>, }, id: 0, }
->
{ type: "reg", data: { name: <string>, index: <number | string>, error: <bool>, errorText: <string>, }, id: 0, }
- Update winners (for all after every winners table update)
->
{ type: "update_winners", data: [ { name: <string>, wins: <number>, } ], id: 0, }
- Login or create player
- Room
- Create new room (create game room and add yourself there)
<-
{ type: "create_room", data: "", id: 0, }
- Add user to room (add youself to somebodys room, then remove the room from available rooms list)
<-
{ type: "add_user_to_room", data: { indexRoom: <number | string>, }, id: 0, }
->
{ type: "create_game", //send for both players in the room, after they are connected to the room data: { idGame: <number | string>, idPlayer: <number | string>, /* generated by server id for player in the game session, not enemy (unique id for every player) */ }, id: 0, }
- Update room state (send rooms list, where only one player inside)
->
{ type: "update_room", data: [ { roomId: <number | string>, roomUsers: [ { name: <string>, index: <number | string>, } ], }, ], id: 0, }
- Create new room (create game room and add yourself there)
- Ships
- Add ships to the game board
<-
{ type: "add_ships", data: { gameId: <number | string>, ships: [ { position: { x: <number>, y: <number>, }, direction: <boolean>, length: <number>, type: "small"|"medium"|"large"|"huge", } ], indexPlayer: <number | string>, /* id of the player in the current game session */ }, id: 0, }
- Start game (only after server receives both player's ships positions)\
->
{ type: "start_game", data: { ships: /* player's ships, not enemy's */ [ { position: { x: <number>, y: <number>, }, direction: <boolean>, length: <number>, type: "small"|"medium"|"large"|"huge", } ], currentPlayerIndex: <number | string>, /* id of the player in the current game session, who have sent his ships */ }, id: 0, }
- Add ships to the game board
- Game
- Attack
<-
{ type: "attack", data: { gameId: <number | string>, x: <number>, y: <number>, indexPlayer: <number | string>, /* id of the player in the current game session */ }, id: 0, }
- Attack feedback (should be sent after every shot, miss and after kill sent miss for all cells around ship too)\
->
{ type: "attack", data: { position: { x: <number>, y: <number>, }, currentPlayer: <number | string>, /* id of the player in the current game session */ status: "miss"|"killed"|"shot", }, id: 0, }
- Random attack
<-
{ type: "randomAttack", data: { gameId: <number | string>, indexPlayer: <number | string>, /* id of the player in the current game session */ }, id: 0, }
- Info about player's turn (send after game start and every attack, miss or kill result)
->
{ type: "turn", data: { currentPlayer: <number | string>, /* id of the player in the current game session */ }, id: 0, }
- Finish game
->
{ type: "finish", data: { winPlayer: <number | string>, /* id of the player in the current game session */ }, id: 0, }
- Attack
Player1 Server Player2
reg -->
<-- reg
<-- update_room
<-- update_winners
create_room -->
<-- update_room
<-- reg
reg -->
<-- update_room -->
<-- update_winners -->
<-- add_user_to_room
<-- update_room -->
<-- create_game -->
add_ships -->
<-- add_ships
<-- start_game -->
<-- turn -->
attack (miss) -->
<-- attack -->
<-- turn -->
<-- randomAttack (shoot)
<-- attack -->
<-- turn -->
<-- randomAttack (kill) - send state for all cells around killed ship
<-- attack -->
<-- turn -->
<-- attack -->
<-- turn -->
<-- attack -->
<-- turn -->
<-- attack -->
<-- turn -->
...
<-- randomAttack (miss)
<-- attack -->
<-- turn -->
attack (miss) -->
<-- attack -->
<-- turn -->
...
<-- finish -->
<-- update_winners -->