Skip to content

svrem/quizzy

Repository files navigation

Quizzy

A continuous quiz game made with GoLang and React.

Features

  • Real-time multiplayer quiz game
  • Questions
  • Score and Streak
  • Protocol
  • TimeSync
  • User authentication
  • PoW (Proof of Work) for anti-spam
  • Docker CI

Real-time Multiplayer Quiz Game

Quizzy is a real-time multiplayer quiz game where users can join and compete against each other in various categories. This real-time functionality is achieved using WebSockets. The websocket messages are generated by the GoLang backend and sent to the React Frontend using ProtocolBuffers, which are like JSON but more memory efficient. The game consists of rounds of questions, where each round contains 10 questions of one category selected by the players. The category is chosen before the round starts. The players can choose from three randomly selected categories.

Questions

I made a Go program that fetched all the questions from the Open Trivia Database using their API. The questions are stored in a SQLite database. Before I put the questions in the database, I had to normalize them a bit, because the API returns the questions in subcategories, but I needed them in categories. The questions are stored in the database with their category and difficulty level. The questions are then fetched from the database and sent to the client when a round starts. The questions are sent in a random order, so that the players don't get the same questions in the same order.

Score and Streak

The base score increment is 10 points for each question answered correctly, but the user's streaks exponetially increases their score. The actual score is calculated as follows:

score += 10 ** (1 + 0.1 * streak)

Protocol

The 'protocol' for the WebSocket message are:

Client - Server:

<- QuestionData (Containing the question and its category and difficulty) <- PossibleAnswers (Containing the possible answers for the question) -> AnswerSelection (The user selects an answer. This message can be sent multiple times, so that the user can change their answer) <- RightAnswer (Containing the right answer to the question) <- ScoreUpdate (Containing the updated score for the user)

After 10 questions

<- CategorySelection (Containing the categories for the next round) -> CategorySelection (The user selects the categories for the next round)

TimeSync

I noticed an issue where sometimes the users' clocks were not in sync. Their system clocks would be a few seconds off, which caused the game timer to show the remaining time incorrectly. To solve this, I implemented a time synchronization mechanism. The server sends the current time to the client when the game starts. The client then calculates the difference between the server time and the client time. This difference is then used to adjust the game timer on the client side.

User Authentication

The authentication is done using OAuth2. The users can log in using their Google or Discord accounts. After the user authenticates, a JWT token is generated and sent to the client. The client stores the token in the cookies. The server can then verify the token and authenticate the user, linking their account to the current session. 

PoW (Proof of Work)

This was entirely unnecessary, but I wanted to implement it anyway. PoW is used to prevent spam in the game. The implementation is pretty simple. The client send a challenge request to the server. This returns a challenge string along with a JWT signed object, so that the server can verify that the client used a server generated challenge. The challenge is then solved by the client. This is done by hashing the challenge string with a nonce until the hash starts with 3 zeros. The client then sends the solution back to the server, which verifies it and allows the user to connect to the WebSocket.

Docker CI

I own a server and it's not best practice to compile applications on a server. That's why I use Docker to build an image for this application. The Docker CI I set up for this project allows me to create a Docker image for every release I make. I can then pull this image and run it on my server.

Installation

To run the application locally, you need to have Go and Node.js installed on your machine. Follow these steps:

  1. Clone the repository:

    git clone https://github.com/yourusername/quizzy.git
    cd quizzy
  2. Install the Go dependencies:

    go mod tidy
  3. Generate the ProtocolBuffers:

    chmod +x scripts/make-proto.sh
    ./scripts/make-proto.sh
  4. Install the Node.js dependencies:

    cd website
    npm install
    npm run build
  5. Start the Go backend:

    cd ..
    go run cmd/quizzy/quizzy.go

Dev

To run the application in development mode, you can use the following command:

ENV=development go run cmd/quizzy/quizzy.go

This will start the server in development mode, which enables a reverse proxy for the React frontend. The frontend will be served on http://localhost:3000 and the backend on http://localhost:8080. So, you have to also start the React frontend in development mode:

cd website
npm run start

About

Are you feeling Rizzy? Cause you might want to play some Quizzy!

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors