Skip to content

Commit

Permalink
Started simplifying and trying to debug TicTacToeBoard.tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
luloxi committed Jan 12, 2024
1 parent bf96e68 commit f5d112a
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 67 deletions.
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@ dApp for betting on the outcome of a Tic Tac Toe game.
- Board (pending development by BuidlGuidl members)
- Game idea by [freeCodeCamp Frontend Web Development Tutorial](https://www.youtube.com/watch?v=MsnQ5uepIaE)

## How can I contribute?

### Requirements

- 🐣 Make sure you know the ETH Tech Stack and understand [how to make a dApp using Scaffold-ETH 2](https://lulox.notion.site/Newbie-s-Lounge-68ea7c4c5f1a4ec29786be6a76516878).

### How to contribute:
## How can I contribute to this build?

- 👷‍♀️ To view current development tasks, [join this Trello board](https://trello.com/invite/b/s0vot1BA/ATTI366c508087a404ccf9343def4d76d1ce6F7899AA/newbies-lounge) and check the list "TicTacToe".
- 🧰 To chat with other buidlers about this project, [join our Telegram group](https://t.me/+FwCZPG51UhwzOTZh)
- 🛠️ To submit a PR (Pull Request), [fork and pull](https://github.com/susam/gitpr) a request to this repo.
- 🐣 Make sure you know the ETH Tech Stack and understand [how to make a dApp using Scaffold-ETH 2](https://lulox.notion.site/Newbie-s-Lounge-68ea7c4c5f1a4ec29786be6a76516878).

## Quickstart

Expand Down Expand Up @@ -95,12 +90,12 @@ Win scenarios:

Run smart contract test with `yarn hardhat:test`

## About Scaffold-ETH 2

See [SE2-DOCUMENTATION.md](./SE2-DOCUMENTATION.md)

### Disabling Github Workflow

We have github workflow setup checkout `.github/workflows/lint.yaml` which runs types and lint error checks every time code is **pushed** to `main` branch or **pull request** is made to `main` branch

To disable it, **delete `.github` directory**

## About Scaffold-ETH 2

See [SE2-DOCUMENTATION.md](./SE2-DOCUMENTATION.md)
111 changes: 94 additions & 17 deletions packages/hardhat/contracts/TicTacToe.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
pragma solidity ^0.8.17;

/**
* @title TicTacToe
* @author Lulox
* @notice A betting TicTacToe contract.
* @dev Currently for using with one transaction per move,
* in a future may be replaced with signatures
* in a future may be replaced with signatures
or other gas efficient mechanism
*/

contract TicTacToe {
Expand Down Expand Up @@ -57,15 +58,6 @@ contract TicTacToe {

/* MODIFIERS */

modifier onlyPlayers(uint256 gameId) {
require(
msg.sender == games[gameId].player1 ||
msg.sender == games[gameId].player2,
"Not a player"
);
_;
}

modifier onlyValidMove(uint256 _gameId, uint8 position) {
// Store the game in memory to use less storage reads
Game memory game = games[_gameId];
Expand Down Expand Up @@ -160,6 +152,55 @@ contract TicTacToe {
checkWin(_gameId, position, msg.sender);
}

// Function to withdraw the prize based on game state
function withdrawPrize(uint256 _gameId) external {
Game storage game = games[_gameId];

// Ensure the game is in the correct state for prize withdrawal
require(
game.state == GameState.PLAYER1WON ||
game.state == GameState.PLAYER2WON ||
game.state == GameState.TIE,
"Invalid game state for prize withdrawal"
);

// Ensure the caller is one of the players or has not withdrawn yet
require(
msg.sender == game.player1 || msg.sender == game.player2,
"Not a player"
);

// Ensure the player has not withdrawn yet
if (msg.sender == game.player1) {
require(
game.state == GameState.PLAYER1WON,
"You haven't won this game!"
);
require(
!game.player1Withdrawn,
"You have already withdrawn the prize!"
);
game.player1Withdrawn = true;
} else {
require(
game.state == GameState.PLAYER2WON,
"You haven't won this game!"
);
require(
!game.player2Withdrawn,
"You have already withdrawn the prize!"
);
game.player2Withdrawn = true;
}

// Calculate and transfer the prize based on the game state
uint256 prize = calculatePrize(_gameId);
require(prize > 0, "Invalid prize amount");

// Transfer the prize to the player
payable(msg.sender).transfer(prize);
}

/* INTERNAL FUNCTIONS */

function checkWin(
Expand Down Expand Up @@ -215,13 +256,49 @@ contract TicTacToe {
}

function finishGame(uint256 gameId, address winner) internal {
// Incliude a check for state assuming the winner will be the msg.sender
// In the case of a tie call with address(0) as the winner, add a condition for that too
Game storage game = games[gameId];

// Add conditions to determine which state will the game be finished with, according to this info ^
// These come from the enum GameState PLAYER1WON, PLAYER2WON, TIE
GameState state = games[gameId].state;
emit GameFinished(gameId, winner, state);
// Ensure the game is in the PLAYING state before finishing
require(
game.state == GameState.PLAYING,
"Game is not in PLAYING state"
);

// Determine the result based on the winner and update game state accordingly
if (winner == address(0)) {
// It's a tie
game.state = GameState.TIE;
} else if (winner == game.player1) {
// Player 1 won
game.state = GameState.PLAYER1WON;
} else if (winner == game.player2) {
// Player 2 won
game.state = GameState.PLAYER2WON;
} else {
// Winner address is not valid
revert("Invalid winner address");
}

// Emit GameFinished event
emit GameFinished(gameId, winner, game.state);
}

// Function to calculate the prize based on the game state
function calculatePrize(uint256 _gameId) internal view returns (uint256) {
Game storage game = games[_gameId];
uint256 totalBet = game.bet * 2; // Total amount bet in the game

if (game.state == GameState.PLAYER1WON) {
return totalBet;
} else if (game.state == GameState.PLAYER2WON) {
return totalBet;
} else if (game.state == GameState.TIE) {
// In the case of a tie, split the total bet equally between players
return totalBet / 2;
} else {
// Invalid game state
revert("Invalid game state");
}
}

/* VIEW AND PURE FUNCTIONS */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const CreateChallengeBox = ({}) => {
value: betAmount ? ethers.parseEther(betAmount) : undefined,
});

console.log("Bet amount: ", betAmount);
// console.log("Bet amount: ", betAmount);

return (
<Card
Expand Down
58 changes: 24 additions & 34 deletions packages/nextjs/components/tictactoe/TicTacToeBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,10 @@ import { Address } from "../scaffold-eth";
import { Button, Flex, Grid } from "@chakra-ui/react";
import { ethers } from "ethers";
import { useScaffoldContractRead, useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
import { MoveMadeProps, TicTacToeBoardProps } from "~~/types/TicTacToeTypes";
import { TicTacToeBoardProps } from "~~/types/TicTacToeTypes";

const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({
game,
isGameAccepted,
movesList,
movesAmount,
isGameFinished,
}) => {
const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({ game, isGameAccepted, movesAmount, isGameFinished }) => {
const [position, setPosition] = useState<number>(0);
const [betPayment, setBetPayment] = useState<number>(game.bet);
const [board, setBoard] = useState<number[]>(Array(9).fill(0)); // Initialize an empty board

const { data: getBoard } = useScaffoldContractRead({
Expand All @@ -22,42 +15,33 @@ const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({
args: [BigInt(game.gameId)],
});

console.log("getBoard reads for #", game.gameId, ": ", getBoard);
console.log("getBoard reads: ", getBoard);

useEffect(() => {
// Update the local board based on the latest data from the contract
if (getBoard) {
setBoard(getBoard.map(Number));
}
}, [getBoard]);

const { writeAsync: makeMove } = useScaffoldContractWrite({
contractName: "TicTacToe",
functionName: "makeMove",
args: [BigInt(game.gameId), position],
value: BigInt(betPayment),
});

useEffect(() => {
// Update the board based on the movesList
const updatedBoard = Array(9).fill(0);

movesList.forEach((move: MoveMadeProps) => {
const currentPlayerSymbol = move.player === game.player1 ? 1 : 2;
updatedBoard[move.position] = currentPlayerSymbol;
});

setBoard(updatedBoard);
}, [game.player1, movesList]);
const { writeAsync: acceptGame } = useScaffoldContractWrite({
contractName: "TicTacToe",
functionName: "acceptGame",
args: [BigInt(game.gameId)],
value: BigInt(game.bet),
});

const handleMakeMove = async () => {
try {
if (movesAmount > 0) {
setBetPayment(0);
}
await makeMove();

// Update the local board based on the latest move
const currentPlayerSymbol = movesAmount % 2 === 0 ? 1 : 2;
const updatedBoard = [...board];
updatedBoard[position] = currentPlayerSymbol;
setBoard(updatedBoard);
} catch (error) {
console.error("Error making move:", error);
// Handle error as needed
}
};

Expand All @@ -74,13 +58,19 @@ const TicTacToeBoard: React.FC<TicTacToeBoardProps> = ({
Player 2: <Address address={game.player2} />
</p>
<p>
Bet: <br /> {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
Each player bets: <br /> {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
</p>
</Flex>
<Flex direction="row" justifyContent={"space-around"} gap={6}>
<p>
Is game accepted?: <br />
{isGameAccepted ? "Yes" : "No"}
{isGameAccepted ? (
"Yes"
) : (
<Button colorScheme={"red"} onClick={() => acceptGame()}>
Accept game
</Button>
)}
</p>
<p>
# of moves made: <br />
Expand Down
34 changes: 30 additions & 4 deletions packages/nextjs/contracts/deployedContracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";
const deployedContracts = {
31337: {
TicTacToe: {
address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
abi: [
{
anonymous: false,
Expand Down Expand Up @@ -115,6 +115,19 @@ const deployedContracts = {
name: "MoveMade",
type: "event",
},
{
inputs: [
{
internalType: "uint256",
name: "_gameId",
type: "uint256",
},
],
name: "acceptGame",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [
{
Expand Down Expand Up @@ -220,9 +233,9 @@ const deployedContracts = {
name: "getCurrentPlayer",
outputs: [
{
internalType: "uint256",
internalType: "uint8",
name: "",
type: "uint256",
type: "uint8",
},
],
stateMutability: "view",
Expand All @@ -243,7 +256,20 @@ const deployedContracts = {
],
name: "makeMove",
outputs: [],
stateMutability: "payable",
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "_gameId",
type: "uint256",
},
],
name: "withdrawPrize",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
],
Expand Down

0 comments on commit f5d112a

Please sign in to comment.