GithubHelp home page GithubHelp logo

jakubraban / minechaser Goto Github PK

View Code? Open in Web Editor NEW
0.0 2.0 0.0 13.94 MB

Web-based multiplayer game based on mechanics known from the classical Minesweeper

Python 17.92% HTML 1.26% TypeScript 65.32% JavaScript 0.77% SCSS 14.38% CSS 0.35%

minechaser's Introduction

Minechaser is a web-based multiplayer game based on mechanics known from the classical Minesweeper. Instead of clicking on the board though, the players compete in real time by walking around the board and marking mines with flags. Every correctly placed flag is awarded with a point. Placing flags incorrectly results with an increasing penalty. Player who survives and gains most points wins. Bonuses can be collected to boost one's progress or impede the opponents.

Running locally

Prerequisites: Python v3.10, pip v23, Node.js v18, npm v10

npm install
pip install -r requirements.txt
npm start
cd api && gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 --bind 0.0.0.0:5000 app:socketio_app

Then visit http://localhost:3000 in your browser.

Features

  • Three game modes
    • Online game, where player joins a global queue to play with other players on the web
    • Private game, where a link can be shared among a group of friends
    • Single-player game
  • User preferences
    • Username, visible to other players
    • Other preferences taking effect locally: disable music, disable sound effects, enable color-blind mode
  • In-game features:
    • Real-time updates for players' score, elapsed time, remaining mine count
    • Keyboard controls for desktop users and on-screen controls for touch-screen users, detected automatically
    • Players who stepped on a mine can spectate it or play again
  • Game summary screen with players' scores and simple statistics about the game
    • Players in private game are proposed to play against each other again
    • From here players can share the game if they liked it
  • Responsive design for all screen sizes

Implementation

Tech Stack

  • React v18 with React Router v6, TypeScript v4.9 and ESLint v8
  • Build system: Vite v4
  • CSS preprocessors and libraries:
    • SASS
    • PostCSS with Autoprefixer and Preset Env (for converting some of the modern CSS syntax for older browsers)
    • PicoCSS v2 - a minimal CSS library leveraging semantic HTML to apply styles
    • Tippy.js for minimal tooltips
  • Python v3.10
    • Gunicorn - WSGI HTTP Server
    • Gevent - coroutine-based networking library with Websocket support
    • Bottle.py - for minimal HTTP request handling
    • APScheduler library for scheduling game events
  • Websocket communication implemented with socket.io library and its Python counterpart on the server, python-socketio
  • Deployed on a DigitalOcean Droplet (VPS) with Nginx as an HTTP server

Selected implementation details

React, JavaScript

  • State fully managed using built-in React features: useState hook and contexts
  • Component lazy-loading and preloading used to minimize initial bundle size and improve perceived performance (e.g. some components are preloaded during animations)
  • Custom hooks used to abstract separate reusable and/or complex logic away from components
  • Physical/touchscreen keyboard detection implemented by checking time elapsed between keydown and keyup events
  • Player ID and preferences are stored in localStorage, conserving the player's profile for the next time they play
  • Optimistic UI updates used for a smoother user experience, minimizing the impact of latency in response time
  • Integration with Rollbar to view errors, and prerender.io to send pre-built version of the website to web crawlers

CSS

  • Fully responsive design implemented using media queries
  • PicoCSS used to leverage semantic HTML elements (like dialog, article, details, progress, [role]) to apply styles
  • Container queries used to appropriately size elements within a cell during the game
  • OKLCH color space used to pick colors of identical perceived brightness
  • CSS Layers used to keep selector specificity as low as possible, keeping the stylesheets clean

Python

  • Code arranged in views, services and models
  • State of games and information about players is stored in-memory using a dict. In case of server restart (e.g. during a deployment), information about players is serialized, stored and deserialized
  • jsonpickle library is used to serialize parts of the state of the game when it is sent to the client. Inclusion of sensitive information is avoided thanks to implementing custom __getstate__ magic method on the model classes.
  • Very primitive queue algorithm is used in matchmaking. Players are dequeued when there are 4 players in the queue (maximum number in a game) or with at least two players, the longest waiting player is in the queue for at least 15 seconds.
  • APScheduler library is used to schedule future events, like player dequeuing, timing the start of the game, delete finished games, placing bonuses on the board etc.
  • The server runs in a single thread, utilizing gevent for spawning greenlets - lightweight coroutines for in-process concurrent execution

Communication and networking

  • Socket.io is used for communication, providing useful abstractions and mechanisms like broadcasting, rooms, auto-reconnections etc.
  • Difference between client time and server time is calculated when user opens the website and accounted for in further calculations
  • Primitive admin console implemented to remotely access and alter the state (password-protected)

minechaser's People

Contributors

jakubraban avatar

Watchers

 avatar Konstantinos Tsiaras avatar

minechaser's Issues

Screen before start of game

Should show countdown and point to the corner where current user starts. No cells should be visible during this countdown

Improvements to the core logic

  • don't apply any time limit to a singleplayer game
  • don't allow flagging cells at the other side of the board (contrary to moving)

Optimise queue on backend

Every time players leave queue, the current list is replaced with its slice. Test whether the performance would be improved if we used a "queue start" pointer instead and only sliced the list once in a while

Queue and private game lobby are not left when closing the tab

useEffect's cleanup function isn't run when closing the tab. We need to handle leaving queue and private game lobby either with beforeunload event listener which would send an appropriate socket event or on the backend side by doing those things on socket's disconnect event

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.