智能合约 Solidity 梭哈
•
区块链
pragma solidity ^0.4.21; /** * https://zh.pokerstrategy.com/strategy/various-poker/566/ * 开局 * 1. 各下底注 * 2. 发底牌 * * 每个回合 x4 * 1、发牌,判断该谁说话 * 2、轮流行动(下注、加注、过、丢牌),判断是否行动结束 * 3、判断游戏是否结束,结束则开牌结账,没结束则继续下一回合 * */ contract ShowHand { address private constant dealer = 0x124a983ce7472AB6507347C30984A358Adb7c2E1; uint private constant timeToReact = 3 minutes; uint private gameValidUntil; bytes32 seed; uint public bringInBet = 1 wei; uint public minimalBet = 1 wei; address public activePlayer; address public hostPlayer; address public guestPlayer; address public winner; mapping(address=>uint8[5]) public cards; mapping(address=>uint) public totalBalance; mapping(address=>uint) public roundBalance; mapping(address=>bool) public isPlayerActioned; uint8 public round; bool isGameFinished; event OnGameCreated(); event OnPlayerJoin(address player); event OnPlayerBet(address player, uint amount); event OnPlayerCheck(address player); event OnPlayerFold(address player); event OnPlayerWin(address winner); event OnCardDeal(address player, uint8 card); event OnPlayerTurn(address player); event OnNextRound(uint8 round); event OnPayoutSuccess(address player, uint amount); event OnRefundSuccess(address player, uint amount); event OnLog(address msg); function ShowHand(uint _bringInBet, uint _minimalBet) public { bringInBet = _bringInBet; minimalBet = _minimalBet; hostPlayer = msg.sender; gameValidUntil = now + timeToReact; seed = block.blockhash(block.number - 1); } function Join() public { assert(guestPlayer == address(0)); guestPlayer = msg.sender; emit OnPlayerJoin(msg.sender); gameValidUntil = now + timeToReact; } // 下底注 function BringIn() public payable { assert(round == 0); assert(totalBalance[msg.sender] == 0); // 玩家之前没有下过注 require(msg.value == bringInBet); // 筹码等于底注大小 totalBalance[msg.sender] = msg.value; isPlayerActioned[msg.sender] = true; // 如果所有玩家都下完底注 if (isAllPlayerActioned()) { // 发底牌 cards[hostPlayer][0] = DealCard(); cards[guestPlayer][0] = DealCard(); // 发明牌 cards[hostPlayer][1] = DealCard(); emit OnCardDeal(hostPlayer, cards[hostPlayer][1]); cards[guestPlayer][1] = DealCard(); emit OnCardDeal(guestPlayer, cards[guestPlayer][1]); nextRound(); } gameValidUntil = now + timeToReact; } // 下注 function Bet() public payable { assert(round > 0 && !isGameFinished); require(msg.sender == activePlayer); require(msg.value >= minimalBet); // 当前回合,下注后的总和要大于对手 if (activePlayer == hostPlayer) { require(roundBalance[hostPlayer] + msg.value >= roundBalance[guestPlayer]); } else { require(roundBalance[guestPlayer] + msg.value >= roundBalance[hostPlayer]); } isPlayerActioned[msg.sender] = true; roundBalance[msg.sender] += msg.value; totalBalance[msg.sender] += msg.value; emit OnPlayerBet(msg.sender, msg.value); nextMove(); gameValidUntil = now + timeToReact; } // 过牌 function Check() public { assert(round > 0 && !isGameFinished); require(msg.sender == activePlayer); require(roundBalance[hostPlayer] == roundBalance[guestPlayer]); isPlayerActioned[msg.sender] = true; emit OnPlayerCheck(msg.sender); nextMove(); gameValidUntil = now + timeToReact; } // 弃牌 function Fold() public { assert(round > 0 && !isGameFinished); require(msg.sender == activePlayer); emit OnPlayerFold(msg.sender); nextPlayer(); setWinner(activePlayer); } // 发牌 function DealCard() public returns (uint8) { return uint8Rand(52); } function nextMove() private { assert(round > 0); if (!isAllPlayerActioned() || roundBalance[hostPlayer] != roundBalance[guestPlayer]) { nextPlayer(); return; } // 下注结束,判断是否是最后一轮下注,是则开牌 if (round == 4) { if (CompareCards(0, cards[hostPlayer], cards[guestPlayer]) >= 0) { setWinner(hostPlayer); } else { setWinner(guestPlayer); } return; } // 不是最后一轮,继续发牌,然后判定谁发言 cards[hostPlayer][round] = DealCard(); emit OnCardDeal(hostPlayer, cards[hostPlayer][round]); cards[guestPlayer][round] = DealCard(); emit OnCardDeal(guestPlayer, cards[guestPlayer][round]); nextRound(); } // 开始下一回合 function nextRound() private { round++; resetRoundData(); emit OnNextRound(round); // 根据牌面判定谁发言 determineActivePlayer(); } // 重置回合数据 function resetRoundData() private { activePlayer = address(0); roundBalance[hostPlayer] = 0; roundBalance[guestPlayer] = 0; isPlayerActioned[hostPlayer] = false; isPlayerActioned[guestPlayer] = false; } // 根据牌面判定谁发言 function determineActivePlayer() public { if (CompareCards(1, cards[hostPlayer], cards[guestPlayer]) >= 0) { activePlayer = hostPlayer; } else { activePlayer = guestPlayer; } emit OnPlayerTurn(activePlayer); } // 切换到另外一个玩家行动 function nextPlayer() private { if (activePlayer == hostPlayer) { activePlayer = guestPlayer; } else { activePlayer = hostPlayer; } emit OnPlayerTurn(activePlayer); } function setWinner(address player) private { assert(!isGameFinished); assert(winner == address(0)); isGameFinished = true; winner = player; emit OnPlayerWin(winner); } // 判断是否所有玩家都行动过了 function isAllPlayerActioned() public view returns(bool) { return isPlayerActioned[hostPlayer] && isPlayerActioned[guestPlayer]; } //比较卡牌的大小,简化版本 function CompareCards(uint8 start, uint8[5] cards1, uint8[5] cards2) private pure returns(int) { // uint - uint = uint,所以 sum 必须声明为 int int sum1 = 0; int sum2 = 0; for (uint8 i = start; i < 5; i++) { sum1 += cards1[i] % 13; sum2 += cards2[i] % 13; } return sum1 - sum2; } // 玩家拖延,呼叫裁判判定 function CallReferee() public { require(!isGameFinished); if (gameValidUntil < now) { if (activePlayer == hostPlayer) { setWinner(guestPlayer); } else { setWinner(hostPlayer); } } } // 用户提款 function Withdraw() public payable { assert(winner == msg.sender); assert(isGameFinished); uint total = totalBalance[hostPlayer] + totalBalance[guestPlayer]; uint winnerReward = uint(total * 9 / 10); uint hostPlayerRefund = totalBalance[hostPlayer]; uint guestPlayerRefund = totalBalance[guestPlayer]; totalBalance[hostPlayer] = 0; totalBalance[guestPlayer] = 0; if (winner.send(winnerReward)) { emit OnPayoutSuccess(winner, winnerReward); // send rest balance to dealer uint dealerReward = address(this).balance; if (dealer.send(dealerReward)) { emit OnPayoutSuccess(dealer, dealerReward); } } else { // refunds money to player if (hostPlayer.send(hostPlayerRefund)) { emit OnRefundSuccess(hostPlayer, hostPlayerRefund); } if (guestPlayer.send(guestPlayerRefund)) { emit OnRefundSuccess(guestPlayer, guestPlayerRefund); } } } // fallback function function() public payable { if (msg.value > 0) { dealer.transfer(msg.value); } } function uint8Rand(uint8 range) public returns(uint8) { seed = sha256(seed); return uint8(seed) % range; } }