# Guess the number game , not working

I am trying to write a game on smart contract which is a game in which the player has to type in 5 guesses, and based on how close they were to the actual number, they would receive ether as prize.

GuessTheNumber:

``````// SPDX-License-Identifier: MIT
pragma solidity >= 0.7.0 < 0.9.0;

contract Oracle {

uint public variableRand;

constructor () {
owner = msg.sender;
}

function setRandomVariable (uint _varRand) external {
require (msg.sender == owner);
variableRand = _varRand;
}

}

contract Play {

// Saves the value of what you have won in the session
uint public currentPrize = 0;
int[] public currentGuess;
uint[] public randNum;

event Log(uint gas);

function showPoolBalance() public view returns(uint) {
}

function randMod() public view returns(uint) {
// grab information from the blockchain randomly to generate random numbers - we need something dynamically changing
// abi.encodePacked concatonates arguments nicely
return uint(keccak256(abi.encodePacked(oracle.variableRand, block.timestamp, block.difficulty, msg.sender))) % 1000;
}

function inputGuess(int _guess) public {
// Adds the guesses to the array
currentGuess.push(_guess);
}

function clearGuesses() public {
for (uint i = 0; i < currentGuess.length; i++) {
//removes all of the guesses in the array
currentGuess.pop();
}
}

function abs(int x) private pure returns (int) {
//returns the abolute value of the input
return x >= 0 ? x : -x;
}

function game() private returns (int, uint) {

for (uint i = 0; i <= 5; i++) {
randNum[i] = randMod();
int absv = abs(int(randNum[i]) - currentGuess[i]);
if (absv < 6 && absv > 0) {
currentPrize += 2;
}
else if (absv == 0) {
currentPrize += 4;
}
else if (absv < 16 && absv > 5) {
currentPrize += 1;
}
return (absv , randNum[i]);
}

}

function play() public payable returns (int, uint) {

require(msg.value == (10 ether), "You must pay with 10 ethers!");
game();

}

function chargePool() public payable {
require (msg.value >= 10 ether);
}

function withdrawPrize() public payable {

payable(msg.sender).transfer(currentPrize);

}

fallback () external payable {
emit Log(gasleft());
}

Oracle oracle;

owner = msg.sender;
}

}
``````

The Oracle contract deploys correctly. and the Play contract would deploy as well. The guessed numbers would be pushed in the array correctly but when I wanna call the play function with 10 ether the following error comes up :

[vm]from: 0x5B3...eddC4to: Play.play() 0xf8e...9fBe8value: 10000000000000000000 weidata: 0x93e...84cd9logs: 0hash: 0xfd3...dcad2 transact to Play.play errored: VM error: revert.

revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

Any help would be appreciated.

I figured out what might be going wrong in your code.

It's the use of the `randNum` array. It's dynamic, so you can use `.push()` to add elements to it, but you have not specified a size, so you cannot use `randNum[i]` because those indices might not exist yet. I changed the declaration to:

``````uint[] public randNum = new uint[](5);
``````

Take a look:

``````//SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

contract Oracle {

uint public variableRand;

constructor () {
owner = msg.sender;
}

function setRandomVariable (uint _varRand) external {
require (msg.sender == owner, "Not owner");
variableRand = _varRand;
}

}

contract Play {

// Saves the value of what you have won in the session
uint public currentPrize = 0;
int[] public currentGuess;
uint[] public randNum = new uint[](5);
Oracle oracle;

constructor(Oracle _oracle) {
oracle = _oracle;
}

event Log(uint gas);

function showPoolBalance() public view returns(uint) {
}

function randMod() public view returns(uint) {
// grab information from the blockchain randomly to generate random numbers - we need something dynamically changing
// abi.encodePacked concatonates arguments nicely
return uint(keccak256(abi.encodePacked(oracle.variableRand(), block.timestamp, block.difficulty, msg.sender))) % 1000;
}

function inputGuess(int _guess) public {
// Adds the guesses to the array
currentGuess.push(_guess);
}

function clearGuesses() public {
for (uint i = 0; i < currentGuess.length; i++) {
//removes all of the guesses in the array
currentGuess.pop();
}
}

function abs(int x) private pure returns (int) {
//returns the abolute value of the input
return x >= 0 ? x : -x;
}

function game() private returns (int, uint) {

for (uint i = 0; i <= 5; i++) {
randNum[i] = randMod();
int absv = abs(int(randNum[i]) - currentGuess[i]);
if (absv < 6 && absv > 0) {
currentPrize += 2;
}
else if (absv == 0) {
currentPrize += 4;
}
else if (absv < 16 && absv > 5) {
currentPrize += 1;
}
return (absv , randNum[i]);
}

}

function play() public payable returns (int, uint) {

require(msg.value == (10 ether), "You must pay with 10 ethers!");
game();
}
}
``````

Besides that, I see that your code could really be improved in many areas.

For example, what is that `return (absv , randNum[i]);` doing inside the loop at the end of it and outside any `if`? The loop will only run once and then return. Maybe that is not what you want.

Take a look at `playv2` and `playv3`, especially `playv3`, which saves a record `SenderGuess` into the `senderGuesses` mapping which can help you debug. It's an idea, you can modify it as you need.

``````//SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

contract Contract {

function sendPayment(address from, address payable to, string memory recipientName) public payable {
to.transfer(msg.value);
emit Payment(from, to, recipientName);
}

}

contract Oracle {

uint public variableRand;

constructor () {
owner = msg.sender;
}

function setRandomVariable (uint _varRand) external {
require (msg.sender == owner, "Not owner");
variableRand = _varRand;
}

}

contract Play {

// Saves the value of what you have won in the session
uint public currentPrize = 0;
int[] public currentGuess;
uint[] public randNum = new uint[](5);
Oracle oracle;

struct SenderGuess {
uint256 blockNumber;
uint256[] guesses;
uint256 diff;
uint256 prize;
}

constructor(Oracle _oracle) {
oracle = _oracle;
}

event Log(uint gas);

function showPoolBalance() public view returns(uint) {
}

function randMod() public view returns(uint) {
// grab information from the blockchain randomly to generate random numbers - we need something dynamically changing
// abi.encodePacked concatonates arguments nicely
return uint(keccak256(abi.encodePacked(oracle.variableRand(), block.timestamp, block.difficulty, msg.sender))) % 1000;
}

function inputGuess(int _guess) public {
// Adds the guesses to the array
currentGuess.push(_guess);
}

function clearGuesses() public {
for (uint i = 0; i < currentGuess.length; i++) {
//removes all of the guesses in the array
currentGuess.pop();
}
}

function abs(int x) private pure returns (int) {
//returns the abolute value of the input
return x >= 0 ? x : -x;
}

function game() private returns (int, uint) {

for (uint i = 0; i <= 5; i++) {
randNum[i] = randMod();
int absv = abs(int(randNum[i]) - currentGuess[i]);
if (absv < 6 && absv > 0) {
currentPrize += 2;
}
else if (absv == 0) {
currentPrize += 4;
}
else if (absv < 16 && absv > 5) {
currentPrize += 1;
}
return (absv , randNum[i]);
}

}

function play() public payable returns (int, uint) {

require(msg.value == (10 ether), "You must pay with 10 ethers!");
game();
}

// v2
// This version gets closest guess and and assigns the prize multiple times.
function playv2(uint256[] memory guesses) public payable returns (uint256) {
require(msg.value == (10 ether), "You must pay with 10 ethers!");
require(guesses.length == 5, "You need to send 5 guesses");

uint256 _currentPrize = 10;

// Getting the 'random' mod number only once because if the call to oracle.variableRand() does not return
// a different "random" number, then the randMod function will return the same thing anyways.
uint256 randNumber = randMod();

for(uint256 i = 0; i < guesses.length; i++) {

uint256 guess = guesses[i];
uint256 min = randNumber > guess ? randNumber : guess;
uint256 max = guess > randNumber ? guess : randNumber;

uint256 diff = max - min;

if (diff == 0) {
_currentPrize += 4;
} else if (diff < 6) {
_currentPrize += 2;
} else if (diff < 16) {
_currentPrize += 1;
}

}

return _currentPrize;

}

// v3
// This version gets closest guess and and assigns the prize only once.
function playv3(uint256[] memory guesses) public payable {
require(msg.value == (10 ether), "You must pay with 10 ethers!");
require(guesses.length == 5, "You need to send 5 guesses");

uint256 _currentPrize = 10;

// Getting the 'random' mod number only once because if the call to oracle.variableRand() does not return
// a different "random" number, then the randMod function will return the same thing anyways.
uint256 randNumber = randMod();

uint256 smallestDiff = 16;

for(uint256 i = 0; i < guesses.length; i++) {

uint256 guess = guesses[i];
uint256 min = randNumber > guess ? randNumber : guess;
uint256 max = guess > randNumber ? guess : randNumber;

uint256 diff = max - min;

if(diff < smallestDiff) {
smallestDiff = diff;
}

}

if (smallestDiff == 0) {
_currentPrize += 4;
} else if (smallestDiff < 6) {
_currentPrize += 2;
} else if (smallestDiff < 16) {
_currentPrize += 1;
}

SenderGuess memory senderGuess = SenderGuess(msg.sender, block.number, guesses, smallestDiff, _currentPrize);

senderGuesses[msg.sender].push(senderGuess);

}

}
``````
• Thanks a lot brother. The contract did actually work thanks to your suggestion. I used that return to print out the random number and guesses for the player to check their answers, which now seems so dumb to myself as well,do you think I should use event and emit for such purpose?!
– Rjey
Sep 3, 2022 at 15:48
• Yes. Or you could use hardhat console.log to debug. Sep 3, 2022 at 16:01
• Take a look at he update of my answer. I added a new `play3` implementation example showing a new logic and saving a record of the result in a mapping so you can debug better. Sep 3, 2022 at 18:09