Let's play Blackjack!

Overview

  • Blackjack rules
  • Game demo
  • Java bot client
  • PHP server

Don't play Blackjack in real life - you will most certainly lose.

Demo time!

Source code

Basics

  • Players get dealt 2 face up cards each
  • Dealer gets dealt 2 cards, but only one is face up
  • Get closer to 21 than the dealer
  • Over 21? Sorry, you lose.

Basics

  • Hit me - get another card
  • Stand - next player gets to play
  • Split - split a pair or two cards of the same value (except aces)
  • Double down - double your bet, but receive only 1 more card

Example

Blackjack!

Not

Example

Split

bet $20

bet $20

bet $20

Example

Double down

bet $20

bet $40

Make your own bot!

public interface BotInterface {
    /**
     * Bet at the start of the hand.
     *
     * @param minimum Minimum allowed bet. If you bet less than this, your bet will
     *                be ignored.
     * @param maximum Maximum allowed bet. If you bet more than this, your bet will
     *                be ignored.
     * @param money   Available bot funds.
     * @return
     */
    int bet(int minimum, int maximum, int money);
public interface BotInterface {
    /**
     * Analyze the current hand and dealer's face up card, and return an Action.
     * If you return an invalid action, it will count as standing.
     *
     * @param money            Available bot funds.
     * @param hand             Bot hand.
     * @param dealerFaceUpCard Dealer's face up card.
     * @return
     */
    Action play(int money, Hand hand, Card dealerFaceUpCard);
package me.nemanjamiljkovic.blackjack.Bot;

public enum Action {
    STAND,
    HIT,
    SPLIT,
    DOUBLE_DOWN
}
    @Override
    public Action play(int money, Hand hand, Card dealerFaceUpCard) {
        // Double down and hope for a 10...
        if (hand.getValue() >= 9 && hand.getValue() <= 11) {
            return Action.DOUBLE_DOWN;
        }
        
        // Split hands if the pairs are 4+
        if (hand.canSplit() && hand.getValue() > 8) {
            return Action.SPLIT;
        }
        
        // Hit if less than 16
        if (hand.getValue() < 16) {
            return Action.HIT;
        }

        return Action.STAND;
    }
public class Card {
    public static final int RANK_ACE = 1;
    public static final int RANK_JACK = 12;
    public static final int RANK_QUEEN = 13;
    public static final int RANK_KING = 14;

    public enum Suit {
        HEARTS, CLUBS, SPADES, DIAMONDS
    }

    public int getRank() { ... }
    public Suit getSuit() { ... }
    public int getValue() { ... }
}
public class Hand {
    public List<Card> getCards() { ... }
    public boolean canSplit() { ... }
    public boolean isBlackjack() { ... }
    public boolean is21() { ... }
    public int getValue() { ... }
}

Running the bot

package me.nemanjamiljkovic.blackjack;

import java.net.Socket;

import me.nemanjamiljkovic.blackjack.Bot.Communicator;
import me.nemanjamiljkovic.blackjack.Bot.SimpleBot;

public class Main {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("blackjack.nemanjamiljkovic.me", 8000);
            
            Communicator.createAndRun(socket, new SimpleBot());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Bot competition

Send your bots to

 

nemanja.miljkovic@devana.rs

 

before 1. Nov 2015.

All programming languages allowed.

Under the hood

PHP

Java Bot

Browser

Browser

Browser

Java Bot

Java Bot

Communication

{
    "alias": "request_bet",
    "data": {
        "minimumBet": 50,
        "maximumBet": 150,
        "money": 5000
    }
}

Communication

{
    "data": {
        "money": 4692,
        "playerHand": {
            "cards": [{
                "rank": 7,
                "suit": "H"
            }, {
                "rank": 3,
                "suit": "S"
            }],
            "canSplitHand": false,
            "value": 10
        },
        "dealerCard": {
            "rank": 2,
            "suit": "S"
        }
    },
    "alias": "request_action"
}

Java and JSON

JSONObject message = new JSONObject(stringMessage);
String alias = message.getString("alias");
JSONObject data = message.getJSONObject("data");

int minimum = data.getInt("minimumBet");
int maximum = data.getInt("maximumBet");
int money = data.getInt("money");
{
    "alias": "request_bet",
    "data": {
        "minimumBet": 50,
        "maximumBet": 150,
        "money": 5000
    }
}

Java and JSON

JSONObject response = new JSONObject();
JSONObject data = new JSONObject();
data.put("amount", 67);

response.put("alias", "bet");
response.put("data", data);

response.toString(); // {"data":{"amount":67},"alias":"bet"}
{
    "data": {
        "amount": 67
    },
    "alias": "bet"
}

The loop

while (socket.isConnected()) {
    String stringMessage = in.readLine();
    if (stringMessage == null) {
        return;
    }

    try {
        JSONObject message = new JSONObject(stringMessage);
        this.parseMessage(message);
    } catch (JSONException exception) {
        continue;
    }
}
{
    "alias": "request_bet",
    "data": {
        "minimumBet": 50,
        "maximumBet": 150,
        "money": 5000
    }
}

PHP to Java

Java to PHP

{
    "data": {
        "amount": 67
    },
    "alias": "bet"
}

Betting

phase

Java Bot

Java Bot

Java Bot

Allow 3 seconds to respond

What if

someone responds after 3 seconds?

someone sends an invalid message?

ignore the message

kick the bot

someone doesn't respond or message is ignored?

skip the round

in competition mode, kick the bot

Playing phase

phase

Java Bot

Java Bot

Java Bot

Serially communicate with bots

i.e. finish with bot 1 before communicating with bot 2

What if

someone responds after 3 seconds?

someone sends an invalid message?

ignore the message

kick the bot

someone doesn't respond or message is ignored?

count as Action.STAND

PHP Server

  • Up and running for non-stop
  • Accepts socket and websocket connections
  • Runs game logic and notifies observers of any game changes in real time

PHP Server

public function startNewHand()
{
    if (!$this->running) {
        return;
    }

    $this->resetTable()
        ->then(function () {
            return $this->requestBets();
        })
        ->then(function () {
            return $this->dealInitialCards();
        })
        ->then(function () {
            return $this->playHand();
        })
        ->then(function () {
            return $this->playDealerHand();
        })
        ->then(function () {
            return $this->distributeWinnings();
        })
        ->always(function () {
            return \Blackjack\Promise\timedResolve(self::LONGEST_PAUSE_SPEED)
                ->then(function () {
                    $this->startNewHand();
                });
        });
}

Single threaded event loop

Multiple threads

Single thread

Q&A

Send your bots or questions to

nemanja.miljkovic@devana.rs

Thanks!

Let's play Blackjack!

By binary

Let's play Blackjack!

  • 330