Git Product home page Git Product logo

blackjack's Introduction

Singleplayer / Multiplayer Blackjack in Python, Flask-API, SocketIO and HTML/CSS

Blackjack / Twenty-One

Blackjack or Twenty-One is a game, where a player tries to reach 21 points without going over and the ace values 1 or 11. The game seems to be quite old, as the spanish version (veintiuna) was first mentioned by Miguel de Cervantes between 1601-1602 source: wikipedia, so it had probably been played even before that time. The rules can be found on many web site, I found this one to be nicely written: Bicyclecards - How to Play Blackjack

The code is free and you can download it here: blackjack

You can play around with the live demo here: Blackjack live demo

multiplayer version

Application

You play as one player against the dealer or with another person against the dealer (backend should support N players but the UI supports only 2 players). Rules were implemented according to description on Bicyclecards - How to Play Blackjack. Not all of the game options were implemented, eg there is no split, double-down or insurance and the UI lacks the logic for taking the bets in every round and it just reuses the initial bet value for each of the player - but these are trivial to add to the existing framework.

Singleplayer

Simply enter your name and an amount you want to bet (each player starts with 1000โ‚ฌ by default) and press the button Play.

Multiplayer (2 players)

One player has to start the game and then other players can join:

  • First player: check the Multiplayer checkbox and press the button Start new game then wait ...
  • Second player: check the Multiplayer checkbox and click the button Join existing game. You should see a list of all the active multiplayer games with names of the players, that had started them. After you select one of them, the game will start by giving turn to the player who had started the multiplayer game. You will know that it is your turn when two buttons popup (Hit or Stand).

After each round the game will restart automatically (using the previous bet amount). You will see the result of previous game on the right side in a simple text log output.

Requirements & Installation

Python 3.6 (flask, flask_socketio, jsonpickle, json, glob, random, uuid)

Dev environment

Simply download the files and run python main.py to play the command line vesion or run python blackjack_api.py to start the Flask server and then hit 127.0.0.1:88 from any web browser. You should see an empty bootstrap page template with a simple form to start the game. You can change the url to whatever you want, but you have to do it in two places, in blackjack_api.py and in templates/cards.html.

Note: if you are tired of always running dev environment, it is also possible to wrap it as a service, but it is not reccommended to run it like this in production environment (I have included an example config at the end of this document)

Production - Nginx as reverse proxy and Flask-API via Gunicorn

For production environment you can use Nginx as reverse proxy and then a Gunicorn/uWSGI server on the backend. I will post examples of config files at the end of this readme.

Note: I am using Python 3 and I think at the moment if you install Gunicorn it will use Python 2 by default, but you can install gunicorn3 package and it will use the correct version

Note: I had also tried with uWSGI but I had problems with SSL handshake, for which there supposedly is a solution but I didn't try it out.

The code

I was thinking about some simple way to add UI and since I had just recently discovered SocketIO I wanted to try that. The basic architecture is a Python backend exposed with Flask-API with SocketIO support and a simple web page with SocketIO to exchange messages between the client and the server. I was very lucky to have found HTML+CSS code for drawing the cards from Juha Lindtstedt for which I am very grateful.

  • blackjack.py - game logic split in the following classes:
    • GameBlackJack
    • Player, PlayerBlackJack, PlayerBlackJackHouse
    • Decks: stores N decks of cards and shuffling
    • CardBlackJack
  • main.py - logic for playing game via a command line interface
  • blackjack_api.py - logic for playing game via a web interface
  • templates/cards.html - web game UI using JQuery and SocketIO for communication with the backend. The code for the communication is embedded inside HTML and is a total mess (TODO: refactoring)
  • blackjack/static - all the static CSS and *js files for displaying the cards + generic bootstrap files

Unit tests have not been implemented yet and there is no error handling and (almost) zero input validation. Any bad input will break the game.

Web interface

In the beginning I wanted to completely avoid using server memory for state persistence, so my plan was to have a unique id for each new game and store the game state somewhere on disk and later switch to a db, thus avoiding any ugly in-memory session. Client would store game id in some hidden input field and send it with every request. This would have worked out nicely had I not decided to use SocketIO, which has to have a session. In their documentation on scaling they explicitly say: " ... requests associated with a particular session id must connect to the process that originated them". SocketIO assigns a session id to every user that connects. So obviously scaling is not SocketIO's strong point. But on the other hand it supports nice things like broadcasting, multicasting messages, which fit perfectly to implementing a game room, and it gives a nice responsive feel to it. The basic logic thus is like this:

  • when a new client connects to the backend, SocketIO assigns it a new sessionid
  • this sessionid is then used to store the game state somewhere (disk,db)
  • any subsequent requests from this user use this sessionid to identify a game and load its state
  • in multiplayer game the sessionid of the first player is used to create a room, to which all other players join
  • each player is identified with a name, so names are unique

SocketIO and sending a message to a "game room

A game room is a way to send a certain message to some list of recipients (instead of everybody or one person). Sending a message to clients with SocketIO is as simple as:

  ...
  socketio.emit('game_start', json.dumps(payload), callback=messageReceived)
  ...

however this is broadcasting and this message will be received by everone with an active session. Most of the time we want to notify a specific client or a group of clients. This is where the concept of rooms come handy. A room is just some identifier you can send a message to:

  from flask_socketio import SocketIO

  ...
  socketio.emit('game_start', payload, callback=messageReceived, room=game.gameid) # received by all the users in the room game.gameid
  ...

and any user can join a room simply by calling join_room:

  from flask_socketio import SocketIO, join_room
  ...
  join_room(game.gameid) # currently connected user joins the room with id game.gameid
  ...

So once the user has joined the room any message sent to this room will be received by him as well. In the case of singleplayer game a room only has one player so (almost) the same logic applies.

Example config files

Nginx as reverse proxy:

  
    listen [::]:80;
    listen 80;
    server_name mydomain.org www.mydomain.org;
    root /home/myusername/blackjack;
    
    proxy_connect_timeout       605;
    proxy_send_timeout          605;
    proxy_read_timeout          605;
    send_timeout                605;
    keepalive_timeout           605;
    
    location = / {        
        proxy_pass http://127.0.0.1:1234;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400s;
    }
}

via Gunicorn3: prerequisites:

    [Unit]
    Description=Gunicorn instance to serve myproject
    After=network.target

    [Service]
    User=myusername
    Group=www-data
    WorkingDirectory=/home/myusername/blackjack    
    ExecStart=/usr/bin/gunicorn3 --workers 3 --bind unix:blackjack.sock -m 007 wsgi:app

    [Install]
    WantedBy=multi-user.target

If you want to simplify things as much as possible it is also possible to directly run Flask as service but this is not reccomended for a production environment:

    [Unit]
    Description=Blackjack Flask web server
    After=network.target
    
    [Install]
    WantedBy=multi-user.target
    
    [Service]
    User=myusername
    PermissionsStartOnly=true
    WorkingDirectory=/home/myusername/blackjack
    ExecStart=/usr/bin/python3 blackjack_api.py
    TimeoutSec=600
    Restart=on-failure
    RuntimeDirectoryMode=755
   

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.