> For the complete documentation index, see [llms.txt](https://docs.seismic.systems/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.seismic.systems/tutorials/understanding-the-clown-beatdown-contract/building-the-cli/chapter-3-bringing-it-all-together.md).

# Ch 3: Bringing It All Together

Now that we've built the core logic for interacting with the ClownBeatdown contract, it's time to tie everything together into a CLI that runs a multiplayer game session with two players — **Alice and Bob.** In this chapter, you'll set up the environment variables for multiple players and write `index.ts` to simulate gameplay. *Estimated time: \~20 minutes*

### Set Up Environment Variables

Before running the game, we need to define environment variables that store important configurations such as the RPC URL, chain ID, and player private keys.

Create a `.env` in `packages/cli`:

```bash
touch .env
```

Open `.env` and paste the following:

```properties
CHAIN_ID=31337
VITE_CHAIN_ID=31337
RPC_URL=http://127.0.0.1:8545
ALICE_PRIVKEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
BOB_PRIVKEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
```

**What's Happening Here?**

* `CHAIN_ID=31337`: Used to locate the deployment broadcast file for the correct chain.
* `VITE_CHAIN_ID=31337`: Used for chain selection (`sanvil` vs testnet). `31337` is the default chain ID for `sanvil` (your local Seismic node).
* `RPC_URL=http://127.0.0.1:8545`: This is the RPC URL for interacting with the local Seismic node.
* `ALICE_PRIVKEY` and `BOB_PRIVKEY`: These are Alice and Bob's private keys, allowing them to play the game. (These are standard test keys provided by `sanvil`)

### Write index.ts

Now, we'll create the main entry point for our game session. This file will simulate gameplay, initializing players and having them interact with the ClownBeatdown contract. Open `packages/cli/src/index.ts` and follow these steps:

#### Import Dependencies

Import the required libraries to read environment variables, define network configurations, and interact with the ClownBeatdown contract.

```typescript
import dotenv from "dotenv";
import { join } from "path";
import { sanvil, seismicTestnet } from "seismic-viem";

import { CONTRACT_DIR, CONTRACT_NAME } from "../lib/constants";
import { readContractABI, readContractAddress } from "../lib/utils";
import { App } from "./app";

// Load environment variables from .env file
dotenv.config();
```

#### Define the main() function

This function initializes the contract and player wallets, then runs the game session.

```typescript
async function main() {
  if (!process.env.CHAIN_ID || !process.env.RPC_URL) {
    console.error('Please set your environment variables.')
    process.exit(1)
  }
```

#### Read Contract Details

The contract's ABI and deployed address are read from files generated during deployment.

```typescript
const broadcastFile = join(
  CONTRACT_DIR,
  "broadcast",
  `${CONTRACT_NAME}.s.sol`,
  process.env.CHAIN_ID,
  "run-latest.json",
);
const abiFile = join(
  CONTRACT_DIR,
  "out",
  `${CONTRACT_NAME}.sol`,
  `${CONTRACT_NAME}.json`,
);
```

#### Select the blockchain network

Determine whether to use the local `sanvil` node (31337) or the Seismic testnet.

```typescript
const chain =
  process.env.VITE_CHAIN_ID === sanvil.id.toString() ? sanvil : seismicTestnet;
```

#### Define players

Assign Alice and Bob as players with private keys stored in `.env`.

```typescript
const players = [
  { name: "Alice", privateKey: process.env.ALICE_PRIVKEY! },
  { name: "Bob", privateKey: process.env.BOB_PRIVKEY! },
];
```

#### Initialize the Game App

Create an `App` instance to interact with the ClownBeatdown contract.

```typescript
const app = new App({
  players,
  wallet: {
    chain,
    rpcUrl: process.env.RPC_URL!,
  },
  contract: {
    abi: readContractABI(abiFile),
    address: readContractAddress(broadcastFile),
  },
});

await app.init();
```

#### Simulate the game round by round

The following logic executes two rounds of gameplay between Alice and Bob.

**Round 1 — Alice Plays**

Alice hits the clown three times (stamina starts at 3), knocking it out, then robs a secret.

```typescript
console.log("=== Round 1 ===");
await app.hit("Alice");
await app.hit("Alice");
await app.hit("Alice");

// Alice robs the clown's secret in round 1
await app.rob("Alice");
```

**Round 2 — Bob Plays**

Bob resets the clown, hits it three more times, then robs his own secret.

```typescript
console.log("=== Round 2 ===");
await app.reset("Bob");
await app.hit("Bob");
await app.hit("Bob");
await app.hit("Bob");

// Bob robs the clown's secret in round 2
await app.rob("Bob");
```

**Alice Tries to Rob in Round 2 (we expect this to fail since she contributed in round 1 but not round 2)**

```typescript
  // Alice tries to rob in round 2, should fail by reverting
  console.log('=== Testing Access Control ===')
  console.log("Attempting Alice's rob() in Bob's round (should revert)")
  try {
    await app.rob('Alice')
    console.error('Expected rob() to revert but it succeeded')
    process.exit(1)
  } catch (error) {
    console.log('Received expected revert')
  }
}
```

### Execute the main() function

This ensures that the script runs when executed.

```typescript
main();
```

### Running the CLI

Now, run the CLI from `packages/cli` by running:

```bash
bun dev
```

You should see something like this as the output:

```
=== Round 1 ===
- Player Alice writing hit()
- Player Alice writing hit()
- Player Alice writing hit()
- Player Alice reading rob()
- Player Alice robbed secret: The cake is a lie
=== Round 2 ===
- Player Bob writing reset()
- Player Bob writing hit()
- Player Bob writing hit()
- Player Bob writing hit()
- Player Bob reading rob()
- Player Bob robbed secret: 42 is the answer
=== Testing Access Control ===
Attempting Alice's rob() in Bob's round (should revert)
Received expected revert
```

This output logs the events during two rounds of gameplay in the ClownBeatdown contract, showing interactions by Alice and Bob, along with a revert error when Alice attempts to call `rob()` in Round 2.

Congratulations! You've reached the end of the tutorial.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.seismic.systems/tutorials/understanding-the-clown-beatdown-contract/building-the-cli/chapter-3-bringing-it-all-together.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
