
{"id":3431,"date":"2024-09-04T07:38:57","date_gmt":"2024-09-04T07:38:57","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=3431"},"modified":"2024-09-04T07:38:57","modified_gmt":"2024-09-04T07:38:57","slug":"rareskills-solidity-interview-question-48-answered-how-would-you-design-a-game-of","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=3431","title":{"rendered":"RareSkills Solidity Interview Question #48 Answered: How would you design a game of\u2026"},"content":{"rendered":"<h3>RareSkills Solidity Interview Question #48 Answered: How would you design a game of rock-paper-scissors in a smart contract such that players cannot\u00a0cheat?<\/h3>\n<p>This series will provide answers to the list of <a href=\"https:\/\/www.rareskills.io\/post\/solidity-interview-questions\">Solidity interview questions<\/a> that were published by <a href=\"https:\/\/www.rareskills.io\/\">RareSkills.<\/a>.<\/p>\n<p><strong><em>Question #48 (Medium): How would you design a game of rock-paper-scissors in a smart contract such that players cannot\u00a0cheat?<\/em><\/strong><\/p>\n<p><strong>Answer:<\/strong> I would design the smart contract for a game of rock-paper-scissors to require players to submit their choice using a commit-reveal scheme. This design would prevent players from seeing each other\u2019s choice. Also, it would mean that players could not change their choice once it\u2019s committed.<\/p>\n<p><strong>Demonstration:<\/strong><\/p>\n<p>\/\/ SPDX-License-Identifier: MIT<br \/>pragma solidity 0.8.26;<\/p>\n<p>contract RockPaperScissors {<br \/>    enum Move { None, Rock, Paper, Scissors }<\/p>\n<p>    struct Player {<br \/>        bytes32 commitment;<br \/>        Move revealedMove;<br \/>    }<\/p>\n<p>    address public player1;<br \/>    address public player2;<\/p>\n<p>    mapping(address =&gt; Player) public players;<\/p>\n<p>    uint256 public revealDeadline;<\/p>\n<p>    bool public gameStarted;<\/p>\n<p>    modifier onlyPlayers() {<br \/>        require(msg.sender == player1 || msg.sender == player2, &#8220;Not a player&#8221;);<br \/>        _;<br \/>    }<\/p>\n<p>    function startGame(address _player2) external {<br \/>        require(!gameStarted, &#8220;Game already started&#8221;);<\/p>\n<p>        player1 = msg.sender;<br \/>        player2 = _player2;<br \/>        gameStarted = true;<br \/>        revealDeadline = block.timestamp + 1 days;<br \/>    }<\/p>\n<p>    function commitMove(bytes32 _commitment) external onlyPlayers {<br \/>        \/\/ Players can only commit a choice once<br \/>        require(<br \/>            players[msg.sender].commitment == bytes32(0),<br \/>            &#8220;Already committed&#8221;<br \/>        );<\/p>\n<p>        players[msg.sender].commitment = _commitment;<br \/>    }<\/p>\n<p>    function revealMove(Move _move, string memory _nonce) external onlyPlayers {<br \/>        require(<br \/>            players[msg.sender].commitment != bytes32(0),<br \/>            &#8220;No commitment found&#8221;<br \/>        );<br \/>        require(<br \/>            players[msg.sender].revealedMove == Move.None,<br \/>            &#8220;Already revealed&#8221;<br \/>        );<\/p>\n<p>        \/**<br \/>         * NOTE: _move is a uint8. Make sure to pass the correct type to the<br \/>         * commitment hash so that it matches this.<br \/>         *\/<br \/>        bytes32 hash = keccak256(abi.encodePacked(_move, _nonce));<\/p>\n<p>        \/**<br \/>         * If the player tries to submit a different move than the one they<br \/>         * previously committed, the hash would be different from the<br \/>         * commitment hash and thus, this check would fail.<br \/>         *\/<br \/>        require(<br \/>            hash == players[msg.sender].commitment,<br \/>            &#8220;Invalid move or nonce&#8221;<br \/>        );<\/p>\n<p>        players[msg.sender].revealedMove = _move;<br \/>    }<\/p>\n<p>    function determineWinner() external view onlyPlayers returns (string memory) {<br \/>        require(<br \/>            players[player1].revealedMove != Move.None &amp;&amp;<br \/>            players[player2].revealedMove != Move.None,<br \/>            &#8220;Both players must reveal their moves&#8221;<br \/>        );<\/p>\n<p>        Move move1 = players[player1].revealedMove;<br \/>        Move move2 = players[player2].revealedMove;<\/p>\n<p>        if (move1 == move2) {<br \/>            return &#8220;It&#8217;s a draw!&#8221;;<br \/>        } else if (<br \/>            (move1 == Move.Rock &amp;&amp; move2 == Move.Scissors) ||<br \/>            (move1 == Move.Paper &amp;&amp; move2 == Move.Rock) ||<br \/>            (move1 == Move.Scissors &amp;&amp; move2 == Move.Paper))<br \/>        {<br \/>            return &#8220;Player 1 wins!&#8221;;<br \/>        } else {<br \/>            return &#8220;Player 2 wins!&#8221;;<br \/>        }<br \/>    }<\/p>\n<p>    function forceForfeit() external returns (string memory) {<br \/>        require(<br \/>            block.timestamp &gt; revealDeadline,<br \/>            &#8220;Reveal deadline has not passed&#8221;<br \/>        );<\/p>\n<p>        if (<br \/>            players[player1].revealedMove == Move.None &amp;&amp;<br \/>            players[player2].revealedMove == Move.None<br \/>        ) {<br \/>            \/\/ Restart the game if neither player has revealed before the deadline<br \/>            revealDeadline = block.timestamp + 1 days;<br \/>        } else if (players[player1].revealedMove == Move.None) {<br \/>             \/\/ Force player 2 to win<br \/>            return &#8220;Player 2 wins!&#8221;;<br \/>        } else if(players[player2].revealedMove == Move.None) {<br \/>            \/\/ Force player 1 to win<br \/>            return &#8220;Player 1 wins!&#8221;;<br \/>        }<br \/>    }<br \/>}<\/p>\n<p><strong>Further Discussion:<\/strong><\/p>\n<p>The commit-reveal scheme is commonly used in blockchain games to prevent cheating tactics, such as front-running. This is effective because each player\u2019s choice is hashed, along with a secret value, and thus, sufficiently concealed.<\/p>\n<p><strong>Connect with\u00a0me:<\/strong><\/p>\n<p><strong>LinkedIn:<\/strong> <a href=\"https:\/\/www.linkedin.com\/in\/faybianbyrd\/\">https:\/\/www.linkedin.com\/in\/faybianbyrd\/<\/a><strong>Twitter:<\/strong> <a href=\"https:\/\/twitter.com\/FaybianByrd\">https:\/\/twitter.com\/FaybianByrd<\/a><strong>Github:<\/strong> <a href=\"https:\/\/github.com\/FaybianB\">https:\/\/github.com\/FaybianB<\/a><\/p>\n<p><strong>Latest articles:<\/strong><\/p>\n<p><a href=\"https:\/\/medium.com\/@fbyrd\/rareskills-solidity-interview-question-38-answered-what-is-frontrunning-410458d28d1b\"><strong><em>Question #38 (Medium): What is frontrunning?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinmonks\/rareskills-solidity-interview-question-39-answered-what-is-a-commit-reveal-scheme-and-when-would-083cfd3cc24d\"><strong><em>Question #39 (Medium): What is a commit-reveal scheme and when would you use\u00a0it?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinsbench\/rareskills-solidity-interview-question-40-answered-under-what-circumstances-could-abi-encodepacked-e4703aa72758\"><strong><em>Question #40 (Medium): Under what circumstances could abi.encodePacked create a vulnerability?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinmonks\/rareskills-solidity-interview-question-41-answered-how-does-ethereum-determine-the-basefee-in-b99df2a89b87\"><strong><em>Question #41 (Medium): How does Ethereum determine the BASEFEE in EIP-1559?<\/em><\/strong><\/a><a href=\"https:\/\/coinsbench.com\/rareskills-solidity-interview-question-42-answered-what-is-the-difference-between-a-cold-read-and-96cb349b8c57\"><strong><em>Question #42 (Medium): What is the difference between a cold read and a warm\u00a0read?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinmonks\/rareskills-solidity-interview-question-43-answered-how-does-an-amm-price-assets-9fa14aacf346\"><strong><em>Question #43 (Medium): How does an AMM price\u00a0assets?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinsbench\/rareskills-solidity-interview-question-44-answered-what-is-a-function-selector-clash-in-a-proxy-de885dcf0b6d\"><strong><em>Question #44 (Medium): What is a function selector clash in a proxy and how does it\u00a0happen?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinmonks\/rareskills-solidity-interview-question-45-answered-what-is-the-effect-on-gas-of-making-a-function-2730feaa606a\"><strong><em>Question #45 (Medium): What is the effect on gas of making a function\u00a0payable?<\/em><\/strong><\/a><a href=\"https:\/\/medium.com\/coinsbench\/rareskills-solidity-interview-question-46-answered-what-is-a-signature-replay-attack-0d24bd2beecd\"><strong><em>Question #46 (Medium): What is a signature replay\u00a0attack?<\/em><\/strong><\/a><a href=\"https:\/\/blog.blockmagnates.com\/rareskills-solidity-interview-question-47-answered-what-is-gas-griefing-310a373e840d\"><strong><em>Question #47 (Medium): What is gas griefing?<\/em><\/strong><\/a><\/p>\n<p><strong><em>Disclosure:<\/em><\/strong><em> Some content may have been generated with the help of artificial intelligence.<\/em><\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/rareskills-solidity-interview-question-48-answered-how-would-you-design-a-game-of-f6f512de8d8f\">RareSkills Solidity Interview Question #48 Answered: How would you design a game of\u2026<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>RareSkills Solidity Interview Question #48 Answered: How would you design a game of rock-paper-scissors in a smart contract such that players cannot\u00a0cheat? This series will provide answers to the list of Solidity interview questions that were published by RareSkills.. Question #48 (Medium): How would you design a game of rock-paper-scissors in a smart contract such [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-3431","post","type-post","status-publish","format-standard","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/3431"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3431"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/3431\/revisions"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}