Skip to main content

二十一点

以下文档演示了在 Sui 上实现流行的赌场游戏二十一点的示例。本指南详细介绍了其组件,提供了对模块的函数、结构、常量以及它们在整体游戏机制中的重要性的详细查看。

构建链上的二十一点游戏与硬币翻转游戏有很多相似之处。因此,此示例仅涵盖智能合约(Move 模块)和前端逻辑。

info

有关构建后端并部署到 Sui 的更多详细信息,请查看硬币翻转应用示例

你还可以在此示例的完整存储库中找到。

游戏玩法

在这个单人版本的二十一点中,玩家与由系统自动操作的庄家竞争。庄家配备了一个在游戏机制中发挥关键作用的公共 BLS 密钥。玩家通过与屏幕上的鼠标交互生成游戏的随机性,然后下注开始游戏。启动游戏后,庄家的后端主动监听启动交易,通过签名并随后向玩家发放两张牌,向自己发放一张牌。

玩家可以选择'要牌'或'停牌'。选择'停牌'将触发庄家抽取牌直到总数达到 17 或更高。在庄家停牌后,通常在总和为 17 或更多时,智能合约介入比较总数并宣布获胜者。另一方面,选择'要牌'将提示庄家为玩家抽取一张额外的牌。

智能合约

游戏模块

single_player_blackjack.move 模块包括定义游戏状态并帮助跟踪游戏进度的多个常量:

  • IN_PROGRESS
  • PLAYER_WON_STATUS
  • HOUSE_WON_STATUS
  • TIE_STATUS

还有一些用于错误处理的常量,例如 EInvalidBlsSigEInsufficientBalance 等,确保强大的游戏机制。

GameCreatedEventGameOutcomeEventHitRequestedStandRequested 这样的结构捕捉游戏中的各种事件和操作。HouseAdminCapHouseData 对于维护房屋数据至关重要,包括余额和公钥,而 Game 结构包含有关每个游戏的所有必要信息,如玩家数据、卡片和当前状态。

该模块的函数可以广泛分为初始化、游戏管理和实用程序函数。init 函数设置房屋管理员权限,而 initialize_house_data 通过设置余额和公钥为游戏准备房屋。place_bet_and_create_game 是玩家启动新游戏的入口点,涉及投注和随机输入。first_dealhitstand 函数管理核心游戏玩法,处理牌的发放和玩家选择。

get_next_random_cardget_card_sum 这样的实用程序函数对于游戏机制至关重要,它们生成随机卡片并计算手牌值。该模块还包括用于检索各种游戏和房屋数据的访问器。

出于测试目的,该模块提供了一些特殊函数,例如 set_init_hash_for_testingget_house_admin_cap_for_testingdestroy_for_testing,确保开发人员可以彻底测试游戏机制和房屋数据处理。

计数器模块

下一个模块,counter_nft.move,引入了计数器 NFT,这是游戏机制中的关键组件。它充当 可验证随机函数(VRF) 输入,确保每场新游戏的唯一性。计数器 NFT 的值在每次使用后增加,保持其对于每场新游戏的独特性。对于第一次玩家,创建计数器 NFT 是强制性的。为了增强用户体验,用户界面可以通过将计数器 NFT 的创建与游戏启动集成到单个事务块中,自动完成此过程。这种无缝集成简化了玩家的流程,使他们可以专注于游戏玩法。此计数器与 硬币翻转示例 中的计数器具有相同的目的。

前端

BlackjackBoard 组件 是二十一点游戏前端模块的核心元素,旨在创建交互式和响应式的游戏体验。使用 React 编写,它集成了多个功能和函数,以有效处理游戏逻辑和用户交互。

状态管理和设置

  • 状态 Hooks: 该模块使用 React 的 useState 来管理各种游戏状态,包括 playerHanddealerHandplayerTotaldealerTotal 等。这些状态对于跟踪当前游戏状态并相应更新 UI 非常重要。

  • 随机数生成: 该组件的一个独特特性是根据用户的鼠标移动(handleMouseMove)生成随机数,用于确保公平的游戏结果。userCreatedRandomness 状态存储此数据,然后将其转换为十六进制字符串(randomnessHex)以在游戏中使用。

  • 游戏初始化的模态框: 实施了一个模态框以便于创建新游戏。它捕获了随机性,并使用来自 useGame 钩子的 handlePlayGame 来启动与后端的游戏。

  • 卡片管理: 该组件生成一副牌,并将其映射到 Map 对象(cards)中,以便轻松检索和显示。

UI 组件和样式

  • 卡片显示: 使用 JSX 和 CSS 的组合来呈现卡片,显示花色符号和值,并根据卡片花色进行条件样式化(getSuitColor)。

  • 游戏状态更新: UI 通过弹出消息框(toast)和加载指示器(react-loader-spinner 中的 Hearts)提供游戏事件的即时反馈,如爆牌或游戏完成。

用户交互和反馈

  • 游戏创建和探索: 玩家可以使用专用按钮开始新游戏,触发 openNewGameModal 函数。还提供了链接,供玩家在 Sui 浏览器上查看游戏详情,增强透明度和参与度。

  • 鼠标移动跟踪: 该模块包括跟踪和利用鼠标移动的功能,有助于生成游戏的随机性,这对于公平游戏和不可预测性至关重要。

比较:二十一点和硬币翻转

相似之处

  • 基于区块链的逻辑: 两个游戏都构建在 Sui 上,利用其用于去中心化应用的能力。每个游戏的核心游戏逻辑都位于 Move 模块中,确保游戏过程安全可验证。

  • 状态管理: 在两个游戏中,状态管理至关重要。对于二十一点,这涉及使用 React 状态钩子管理玩家和庄家的手牌和得分。对于 Satoshi Coin Flip,状态通过像 HouseData 这样的 Move 结构进行管理,该结构跟踪房屋的余额和其他与游戏相关的详细信息。

  • 随机性和公平游戏: 两个游戏强调公平性的随机性。二十一点使用计数器 NFT 和玩家鼠标移动生成随机性,而 Satoshi Coin Flip 仅在每场游戏的 可验证随机函数(VRF) 中使用计数器 NFT 作为唯一输入。

  • 智能合约交互: 每个游戏都涉及智能合约交互,用于执行在区块链上的游戏操作,如下注、发牌(二十一点)或猜测(硬币翻转)。这些交互对于在区块链上执行游戏逻辑至关重要。

不同之处

  • 游戏机制和复杂性: 二十一点是一个更复杂的游戏,有多个操作(要牌、停牌、发牌)和状态更新,需要更动态的前端。相比之下,Satoshi Coin Flip 的机制更简单,集中在单个下注和猜测结果上。

  • 用户界面(UI)复杂性: 二十一点游戏涉及更为复杂的 UI,用于显示卡片、管理游戏状态和玩家交互。Satoshi Coin Flip 在游戏玩法上更简单,需要一个不太复杂的 UI。

  • 后端处理: 在二十一点中,庄家是自动化的(机器),玩家的操作直接影响游戏结果。在硬币翻转游戏中,房屋(智能合约)扮演更被动的角色,主要在初始化和根据玩家的猜测完成游戏时起作用。

  • 模块结构和重点: 二十一点游戏更注重前端交互和实时更新。然而,Satoshi Coin Flip 游戏更深入地探讨后端逻辑,具有诸如 HouseCaphouse_data 之类的结构,用于在区块链上安全地初始化和管理游戏数据。

  • 多版本实现: Satoshi Coin Flip 游戏提到了两个版本 —— 一个容易受到 MEV 攻击,另一个抵抗攻击,显示了对安全性和用户体验变化的关注。这样的变化在二十一点中没有实现。

info

完整的应用示例可以在二十一点 Sui 存储库中找到