Skip to content

Commit

Permalink
done with v0.4.0, fix bugs, add open channels. add README instr.
Browse files Browse the repository at this point in the history
  • Loading branch information
tyleryzhu committed Jan 17, 2022
1 parent 1cf8e2d commit b912d1d
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 30 deletions.
47 changes: 42 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,60 @@
<img src="wordlebot.png"/>
</p>

Discord Bot for playing wordle and other word games.
Discord Bot for playing wordle. You can either add my bot (which will be generally running 24/7 outside of bug fixes) or add your own. See below for instructions to both.

I'm storing my bot token in an untracked file ```settings.py```, as well as a quick one-liner to get a list of words.
## How to play

Use the following to install py-cord correctly.
Wordle utilizes slash commands in discord to function. There are a few commands that you can use to play wordle.

* `/start`: Begins a Wordle game for the server in one of three modes: `collab`, where you work together on a Wordle game; `custom`, where one person can provide a custom word for others to guess; and `battle`, a multiplayer mode where multiple people compete on the same world at once.
* `/guess`: Make a guess for Wordle. Words must be real words.
* `/letters`: Get a list of letters that you haven't guessed yet or are in the word.
* `/review`: Get a list of all your previous guesses.
* `/end`: Ends the game regardless of where it is at.

Battle Mode Specific Commands:

* `/join`: Joins an open battle party. Hosts do not need this, as they are automatically in the party.
* `/leave`: Leaves the currently joined battle party. Hosts cannot use this.
* `/ready`: Ready up for the battle, closing the party and starting the game.

## Using my wordle bot (easy)

To add my bot, you can add it to your own discord server using [this link](https://discord.com/api/oauth2/authorize?client_id=928178745209155625&permissions=274878237696&scope=bot). It's running on a server 24/7 and periodically will be reset in case things break. Please file bug reports so I can fix them!

## Setting up your own bot on discord

You can also set up your own bot to run this script by creating a discord application and running this script with your bot token. Follow these steps for that:

1. Follow the steps [here](https://docs.pycord.dev/en/master/discord.html) to create your own bot.
2. Grab your token from the discord application page and store it in a file called ```settings.py``` (mine is untracaked). For your own purposes, your file should look like this.
```python
MYTOKEN = ...
```
3. Clone this repo and setup with
```bash
git clone git@github.com:tyleryzhu/wordle-bot.git
cd wordle-bot
conda env create -f env.yml
conda activate disc
python run_bot.py
```

Note to use the following to install the correct version of pycord.

```bash
pip install py-cord-2.0.0a4758+g1b17e831
```

## Future Features
* Battle mode! Play with a bunch of friends and see who gets the best score.
## Future Features (currently on pause)
* Statistics and tracking. Keep track of how well you do on average, and how many games you've played.
* Hints. When stuck, the bot will remove some of the letters that aren't in the final word for you.

## Version History

* **v0.4**:_(01/16/22)_ Finish fixing battle mode and other bugs, make it so private channels are shared afterwards with people.
* **v0.3.1**:_(01/10/22)_ Added battle mode, multiplayer mode to play all at once with friends.
* **v0.3**:_(01/08/22)_ Rewrite of the bot to use py-cord instead, replacing with slash commands. Also added custom game functionality to suggest your own word to play with.
* **v0.2**:_(01/07/22)_ Add commands for getting all past guesses, for tracking which letters are still left, and for restarting games. Add multi-server support.
* **v0.1**:_(01/06/22)_ Initial release. Basic functionality with text commands.
3 changes: 1 addition & 2 deletions env.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
name: disc
channels:
- pytorch
- defaults
dependencies:
- pip
- python=3.8
- pip:
- py-cord
- py-cord=2.0.0a4758+g1b17e831
72 changes: 50 additions & 22 deletions run_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,20 @@
import logging

import discord
from discord import Guild
from discord.ext import commands
from discord.commands import Option
from discord.user import User

from settings import MYTOKEN
from utils import WORDLEBANK
from utils import WORDLEBANK, GAME_WORDS
from wordle_game import WordleGame
from wordle_bot import WordleBot

WORDS = WORDLEBANK
WORDS_SET = set(WORDS)

# logging.basicConfig(level=logging.INFO)
# logger = logging.getLogger("discord")
# logger.setLevel(logging.DEBUG)
# handler = logging.FileHandler(filename="discord.log", encoding="utf-8", mode="w")
# handler.setFormatter(
# logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s")
# )
# logger.addHandler(handler)
ALL_WORDS = WORDLEBANK
CHOICE_WORDS = GAME_WORDS
WORDS_SET = set(ALL_WORDS)
GAME_SET = set(GAME_WORDS)


intents = discord.Intents(messages=True, guilds=True)
Expand All @@ -36,7 +31,6 @@

# TODO: add in locking so games can't be started over each other
# TODO: implement hardmode
# TODO: let people who are done view other channels


def create_overwrites(ctx, *objects):
Expand Down Expand Up @@ -148,7 +142,7 @@ async def start(
gid = ctx.guild.id
if game_type == "collab":
await ctx.respond("Starting collaborative game of Wordle...")
word = random.choice(WORDS)
word = random.choice(CHOICE_WORDS)

host = ctx.me # TODO: adjust to bot's name
bot.addGame(gid, WordleGame(host, ctx.guild.name, ctx.channel.name, word))
Expand Down Expand Up @@ -242,11 +236,12 @@ async def ready(ctx: commands.Context):
party.closeParty()

await ctx.send(f"Creating private channels for you to battle in...")
for i, member in enumerate(party.getMembers()):
for member in party.getMembers():

overwrites = create_overwrites(ctx, member) # permission is just user, bot

channel = await ctx.guild.create_text_channel(
name="wordle-battle-" + str(i),
name="wordle-battle-" + member.name,
overwrites=overwrites,
topic="Private channel for battlin'. Hush!",
reason="Very secret business.",
Expand All @@ -256,7 +251,7 @@ async def ready(ctx: commands.Context):

# TODO: start games in each channel and update party with them,
# TODO: then handle guesses from each game
word = random.choice(WORDS)
word = random.choice(GAME_WORDS)
members = party.getMembers()
channels = party.getChannels()
host = ctx.me # TODO: adjust to bot's name
Expand Down Expand Up @@ -319,6 +314,12 @@ async def guess(ctx, guess: Option(str, "Enter your 5-letter guess")):
guess = guess.upper()
gid = ctx.guild.id
if bot.isParty(gid):
party = bot.getGame(gid)
channels = party.getChannels()
# Verify person guessing in the channel belongs there
if channels[ctx.author] != ctx.channel:
ctx.respond(f"{ctx.author.name}, this isn't your game! Stop guessing.")
return
game = bot.getGame(gid, ctx.author)
else:
game = bot.getGame(gid)
Expand All @@ -336,11 +337,9 @@ async def guess(ctx, guess: Option(str, "Enter your 5-letter guess")):
if guess_result == -1 or guess_result == 1:
# Game over
if bot.isParty(gid):
await updateMemberFinish(ctx.guild, ctx.author, guess_result)

party = bot.getGame(gid)
await party.base_channel.send(
f"{ctx.author} has finished in {game.turns} turns!"
)
party.deleteGame(ctx.author)
if party.allGamesDone():
await party.base_channel.send(
"All games are over. Ending in 10 seconds..."
Expand All @@ -354,6 +353,35 @@ async def guess(ctx, guess: Option(str, "Enter your 5-letter guess")):
return


async def updateMemberFinish(guild: Guild, member: User, result: int):
"""Updates party given by gid when member finishes a game."""
gid = guild.id
if not bot.isParty(gid):
return
party = bot.getGame(gid)
game = bot.getGame(gid, member)
print(f"{member.name} is done!")

# First send their status to the main channel.
if result == 1:
await party.base_channel.send(
f"{member.name} has finished in {game.turns} turns!"
)
else:
await party.base_channel.send(
f"{member.name} did not finish in {game.turns} turns!"
)
# First allow them to see all the private channels
channels = party.getChannels()
for channel in channels.values():
await channel.set_permissions(
member, overwrite=discord.PermissionOverwrite(view_channel=True)
)

# Then add this member to the done list by deleting the game
party.deleteGame(member)


@bot.slash_command(guild_ids=guild_ids)
@verifyGameStarted
async def end(ctx):
Expand All @@ -366,7 +394,7 @@ async def end(ctx):
for member, channel in channels.items():
await channel.delete()
await party.base_channel.send(f"Game over!")
await bot.deleteGame(gid)
bot.deleteGame(gid)
else:
game = bot.getGame(gid)
word = game.getWord()
Expand Down
3 changes: 3 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
with open("words.txt", "r") as f:
GAME_WORDS = [word.strip().upper() for word in f.readlines()]

with open("sgb-words.txt", "r") as f:
WORDLEBANK = [word.strip().upper() for word in f.readlines()]
1 change: 1 addition & 0 deletions wordle_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ def addParty(
self.games[guild_id] = Party(host, guild_name, base_channel)
print(f"Party in [{guild_name}] w/ host {host.name} added!")
return self.games[guild_id]

1 change: 0 additions & 1 deletion wordle_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,3 @@ def addChannel(self, member: User, channel: GuildChannel) -> bool:
print(f"{self.magic} has added channel [{channel.name}] for {member.name}.")
return True
return False

0 comments on commit b912d1d

Please sign in to comment.