Blackjack
The following documentation goes through an example implementation of the popular casino game blackjack on Sui. This guide walks through its components, providing a detailed look at the module's functions, structures, constants, and their significance in the overall gameplay mechanism.
Building an on-chain blackjack game shares a lot of similarities with a coin flip game. For that reason, this example covers only the smart contracts (Move modules) and frontend logic.
For more details on building a backend and deploying to Sui, check out the Coin Flip app example.
You can also find the full repository for this example here.
Gameplay
In this single-player version of blackjack, the player competes against a dealer, which is automated by the system. The dealer is equipped with a public BLS key that plays a central role in the game's mechanics. Players generate randomness for the game by interacting with their mouse on the screen, after which they place their bet to start the game. Upon initiating the game, the dealer's backend, actively listening for the start transaction, processes it by signing and subsequently dealing two cards to the player and one to itself.
The player has the options to 'Hit' or 'Stand.' Selecting 'Stand' triggers the dealer to draw cards until the total reaches 17 or higher. After the dealer stops, typically at a sum of 17 or more, the smart contract steps in to compare the totals and declare the winner. On the other hand, choosing 'Hit' prompts the dealer to draw an additional card for the player.
Smart contracts
Game module
The single_player_blackjack.move
module includes several constants that define game statuses and help track the game's progress:
IN_PROGRESS
PLAYER_WON_STATUS
HOUSE_WON_STATUS
TIE_STATUS
There are also constants for error handling, such as EInvalidBlsSig
, EInsufficientBalance
, and others, ensuring robust game mechanics.
Structs like GameCreatedEvent
, GameOutcomeEvent
, HitRequested
, and StandRequested
capture the various events and actions within a game. HouseAdminCap
and HouseData
are crucial for maintaining the house's data, including balance and public key, while the Game
struct contains all the necessary information about each game, such as player data, cards, and the current status.
The module's functions can be broadly categorized into initialization, game management, and utility functions. The init
function sets up the house admin capability, while initialize_house_data
prepares the house for the game by setting up the balance and public key. place_bet_and_create_game
is the entry point for players to start a new game, involving a bet and random input. The functions first_deal
, hit
, and stand
govern the core gameplay, handling the dealing of cards and player choices.
Utility functions like get_next_random_card
and get_card_sum
are essential for the game's mechanics, generating random cards and calculating hand values. The module also includes accessors for retrieving various pieces of game and house data.
For testing purposes, the module provides special functions like set_init_hash_for_testing
, get_house_admin_cap_for_testing
, and destroy_for_testing
, ensuring that developers can thoroughly test the game mechanics and house data handling.
Counter module
The next module, counter_nft.move
, introduces the Counter NFT, a key component in the game's mechanics. It serves as the Verifiable Random Function (VRF) input, ensuring uniqueness in each game. The Counter NFT's value increases after each use, maintaining its distinctiveness for every new game. For first-time players, the creation of a Counter NFT is mandatory. To enhance user experience, the user interface can automate this process by integrating the Counter NFT's creation with the game initiation in a single transaction block. This seamless integration simplifies the process for the player, allowing them to focus on the gameplay. This counter serves the same purpose as the one in the Coin Flip example.
Frontend
The BlackjackBoard
component, a central element of the blackjack game's frontend module, is structured to create an interactive and responsive gaming experience. Written in React, it integrates several features and functions to handle the game's logic and user interactions effectively.
State management and setup
State Hooks: The module uses React's
useState
to manage various game states, includingplayerHand
,dealerHand
,playerTotal
,dealerTotal
, and more. These states are vital for tracking the current game status and updating the UI accordingly.Randomness Generation: A unique feature of this component is the generation of randomness based on the user's mouse movements (
handleMouseMove
), used to ensure fair game outcomes. TheuserCreatedRandomness
state stores this data, which is then converted to a hexadecimal string (randomnessHex
) for use in the game.Modal for Game Initialization: A modal is implemented to facilitate the creation of a new game. It captures the randomness and uses
handlePlayGame
from theuseGame
hook to initiate the game with the backend.Card Management: The component generates a deck of cards and maps them to a
Map
object (cards
) for easy retrieval and display.
UI components and styling
Card Display: Cards are rendered using a combination of JSX and CSS, displaying the suit symbols and values, with conditional styling (
getSuitColor
) based on the card suit.Game Status Updates: The UI provides immediate feedback on game events, such as a bust or game completion, using toasts (
toast
) and loading indicators (Hearts
fromreact-loader-spinner
).
User interaction and feedback
Game Creation and Exploration: Players can start new games using a dedicated button that triggers the
openNewGameModal
function. Links are also provided for players to view game details on the Sui explorer, enhancing transparency and engagement.Mouse Movement Tracking: The module includes functionality to track and utilize mouse movements, contributing to the game's randomness generation, which is crucial for fair play and unpredictability.
Comparison: Blackjack and Coin Flip
Similarities
Blockchain-Based Logic: Both games are built on Sui, leveraging its capabilities for decentralized applications. The core game logic for each resides in Move modules, ensuring secure and verifiable gameplay.
State Management: In both games, state management is crucial. For blackjack, this involves managing the player and dealer's hands and scores using React state hooks. In Satoshi Coin Flip, the state is managed through Move structs like
HouseData
, which track the house's balance and other game-related details.Randomness and Fair Play: Both games emphasize randomness for fairness. Blackjack uses a Counter NFT and player mouse movements to generate randomness, while Satoshi Coin Flip only uses a Counter NFT as a unique input for the Verifiable Random Function (VRF) in each game.
Smart Contract Interactions: Each game involves smart contract interactions for game actions like placing bets, dealing cards (Blackjack), or making guesses (Coin Flip). These interactions are crucial for executing the game's logic on the blockchain.
Differences
Game Mechanics and Complexity: Blackjack is a more complex game with multiple actions (hit, stand, deal) and state updates, requiring a more dynamic frontend. In contrast, Satoshi Coin Flip has a simpler mechanic centered around a single bet and guess outcome.
User Interface (UI) Complexity: The Blackjack game involves a more intricate UI to display cards, manage game states, and player interactions. Satoshi Coin Flip, being simpler in gameplay, requires a less complex UI.
Backend Processing: In Blackjack, the dealer is automated (the machine), and the player's actions directly influence game outcomes. In the Coin Flip game, the house (smart contract) plays a more passive role, primarily in initializing and finalizing the game based on the player's guess.
Module Structure and Focus: The Blackjack game focuses more on frontend interactions and real-time updates. The Satoshi Coin Flip game, however, delves deeper into backend logic, with structures like
HouseCap
andhouse_data
for initializing and managing game data securely on the blockchain.Multi-Version Implementation: The Satoshi Coin Flip game mentions two versions – one susceptible to MEV attacks and another that is resistant, indicating a focus on security and user experience variations. Such variations aren't implemented in Blackjack.
The complete app example can be found in the balackjack-sui repo.