---
# System prepended metadata

title: Solidity練習 - 猜數字遊戲
tags: [Block Chain]

---

###### tags: `Block Chain`
# Solidity練習 - 猜數字遊戲


## 簡介
猜數字遊戲，玩法跟終極密碼一樣，
猜的數字只要沒有答對都會縮小數字範圍，
比較不同的是猜數字的方式，
每次猜數字都須支付1 finney,
所以猜中的人可以拿到contract裡面所有參與者投入的錢


```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.14;

contract GuessNumber{
    /* Feature
    猜數字遊戲，玩法其實就跟終極密碼一樣，
    猜的數字只要沒有答對都會縮小數字範圍，
    比較不同的是猜數字的方式，
    每次猜數字都須支付1 finney,
    所以猜中的人可以拿到contract裡面所有參與者投入的錢
    */

    // 答案
    uint256 answer;
    // 上限
    uint256 public MaxRange;
    // 下限
    uint256 public MinRange;
    // 擁有者
    address owner;
    // 猜中事件
    event Winner(address indexed _winner, uint256 _answer);

    constructor () {
        // 產生數字
        genrate();
        // 設定合約擁有者
        owner = msg.sender;
        // 設定上下限
        MaxRange = 100;
        MinRange = 1;
    }

    // 檢查數字須在區間內
    modifier checkNum(uint num){
        require(num > MinRange,"you have to guess higher");
        require(num < MaxRange,"you have to guess lower");
        _;
    }
    // 檢查是否有投入適當的eth
    modifier checkValue() {
        require(msg.value == 1 * 10**15,"need more eth");
        _;

    }

    // 產生數字
    function genrate() private {
        answer = uint(sha256(abi.encodePacked(block.difficulty, block.timestamp))) % 100;
    }


    // 合約擁有者可以查看答案
    function giveMeAnswer() public view returns(uint){  
        require(msg.sender == owner,"you are not owner!");
        return answer; 
    }

    // 查看目前獎金總數
    function award() public view returns(uint){
        return address(this).balance;
    }


    // 猜數字
    function guess(uint num) public checkNum(num) checkValue() payable{

        // 猜的數字 > answer
        if (num > answer) {
           MaxRange = num;
           return;
        }
        
        // 猜的數字 < answer
        if (num < answer) {
            MinRange = num;
            return;
        }

        // 猜中
        if (num == answer) {
            winner(num);
        }

    }

    // 贏家可獲得所有獎金
    function winner(uint num) private {
        // 轉帳的語法
        payable(msg.sender).transfer(address(this).balance);
        // 重新開始
        restart();
   
        emit Winner(msg.sender,num);
    }

    // 重新開始
    function restart() private {
        // 產生數字
        genrate();
        
        // 設定上下限
        MaxRange = 100;
        MinRange = 1;
    }

}
```

{%hackmd theme-dark %}