aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/exts/fun/hangman.py182
-rw-r--r--bot/resources/fun/hangman_words.txt877
2 files changed, 1059 insertions, 0 deletions
diff --git a/bot/exts/fun/hangman.py b/bot/exts/fun/hangman.py
new file mode 100644
index 00000000..a2c8c735
--- /dev/null
+++ b/bot/exts/fun/hangman.py
@@ -0,0 +1,182 @@
+from asyncio import TimeoutError
+from pathlib import Path
+from random import choice
+
+from discord import Embed, Message
+from discord.ext import commands
+
+from bot.bot import Bot
+from bot.constants import Colours, NEGATIVE_REPLIES
+
+# Defining all words in the list of words as a global variable
+ALL_WORDS = Path("bot/resources/fun/hangman_words.txt").read_text().splitlines()
+
+# Defining a dictionary of images that will be used for the game to represent the hangman person
+IMAGES = {
+ 6: "https://cdn.discordapp.com/attachments/859123972884922418/888133201497837598/hangman0.png",
+ 5: "https://cdn.discordapp.com/attachments/859123972884922418/888133595259084800/hangman1.png",
+ 4: "https://cdn.discordapp.com/attachments/859123972884922418/888134194474139688/hangman2.png",
+ 3: "https://cdn.discordapp.com/attachments/859123972884922418/888133758069395466/hangman3.png",
+ 2: "https://cdn.discordapp.com/attachments/859123972884922418/888133786724859924/hangman4.png",
+ 1: "https://cdn.discordapp.com/attachments/859123972884922418/888133828831477791/hangman5.png",
+ 0: "https://cdn.discordapp.com/attachments/859123972884922418/888133845449338910/hangman6.png",
+}
+
+
+class Hangman(commands.Cog):
+ """
+ Cog for the Hangman game.
+
+ Hangman is a classic game where the user tries to guess a word, with a limited amount of tries.
+ """
+
+ def __init__(self, bot: Bot):
+ self.bot = bot
+
+ @staticmethod
+ def create_embed(tries: int, user_guess: str) -> Embed:
+ """
+ Helper method that creates the embed where the game information is shown.
+
+ This includes how many letters the user has guessed so far, and the hangman photo itself.
+ """
+ hangman_embed = Embed(
+ title="Hangman",
+ color=Colours.python_blue,
+ )
+ hangman_embed.set_image(url=IMAGES[tries])
+ hangman_embed.add_field(
+ name=f"You've guessed `{user_guess}` so far.",
+ value="Guess the word by sending a message with a letter!"
+ )
+ hangman_embed.set_footer(text=f"Tries remaining: {tries}")
+ return hangman_embed
+
+ @commands.command()
+ async def hangman(
+ self,
+ ctx: commands.Context,
+ min_length: int = 0,
+ max_length: int = 25,
+ min_unique_letters: int = 0,
+ max_unique_letters: int = 25,
+ ) -> None:
+ """
+ Play hangman against the bot, where you have to guess the word it has provided!
+
+ The arguments for this command mean:
+ - min_length: the minimum length you want the word to be (i.e. 2)
+ - max_length: the maximum length you want the word to be (i.e. 5)
+ - min_unique_letters: the minimum unique letters you want the word to have (i.e. 4)
+ - max_unique_letters: the maximum unique letters you want the word to have (i.e. 7)
+ """
+ # Filtering the list of all words depending on the configuration
+ filtered_words = [
+ word for word in ALL_WORDS
+ if min_length < len(word) < max_length
+ and min_unique_letters < len(set(word)) < max_unique_letters
+ ]
+
+ if not filtered_words:
+ filter_not_found_embed = Embed(
+ title=choice(NEGATIVE_REPLIES),
+ description="No words could be found that fit all filters specified.",
+ color=Colours.soft_red,
+ )
+ await ctx.send(embed=filter_not_found_embed)
+ return
+
+ word = choice(filtered_words)
+ # `pretty_word` is used for comparing the indices where the guess of the user is similar to the word
+ # The `user_guess` variable is prettified by adding spaces between every dash, and so is the `pretty_word`
+ pretty_word = ''.join([f"{letter} " for letter in word])[:-1]
+ user_guess = ("_ " * len(word))[:-1]
+ tries = 6
+ guessed_letters = set()
+
+ def check(msg: Message) -> bool:
+ return msg.author == ctx.author and msg.channel == ctx.channel
+
+ original_message = await ctx.send(embed=Embed(
+ title="Hangman",
+ description="Loading game...",
+ color=Colours.soft_green
+ ))
+
+ # Game loop
+ while user_guess.replace(' ', '') != word:
+ # Edit the message to the current state of the game
+ await original_message.edit(embed=self.create_embed(tries, user_guess))
+
+ try:
+ message = await self.bot.wait_for(
+ event="message",
+ timeout=60.0,
+ check=check
+ )
+ except TimeoutError:
+ timeout_embed = Embed(
+ title=choice(NEGATIVE_REPLIES),
+ description="Looks like the bot timed out! You must send a letter within 60 seconds.",
+ color=Colours.soft_red,
+ )
+ await original_message.edit(embed=timeout_embed)
+ return
+
+ # If the user enters a capital letter as their guess, it is automatically converted to a lowercase letter
+ normalized_content = message.content.lower()
+ # The user should only guess one letter per message
+ if len(normalized_content) > 1:
+ letter_embed = Embed(
+ title=choice(NEGATIVE_REPLIES),
+ description="You can only send one letter at a time, try again!",
+ color=Colours.dark_green,
+ )
+ await ctx.send(embed=letter_embed, delete_after=4)
+ continue
+
+ # Checks for repeated guesses
+ elif normalized_content in guessed_letters:
+ already_guessed_embed = Embed(
+ title=choice(NEGATIVE_REPLIES),
+ description=f"You have already guessed `{normalized_content}`, try again!",
+ color=Colours.dark_green,
+ )
+ await ctx.send(embed=already_guessed_embed, delete_after=4)
+ continue
+
+ # Checks for correct guesses from the user
+ elif normalized_content in word:
+ positions = {idx for idx, letter in enumerate(pretty_word) if letter == normalized_content}
+ user_guess = "".join(
+ [normalized_content if index in positions else dash for index, dash in enumerate(user_guess)]
+ )
+
+ else:
+ tries -= 1
+
+ if tries <= 0:
+ losing_embed = Embed(
+ title="You lost.",
+ description=f"The word was `{word}`.",
+ color=Colours.soft_red,
+ )
+ await original_message.edit(embed=self.create_embed(tries, user_guess))
+ await ctx.send(embed=losing_embed)
+ return
+
+ guessed_letters.add(normalized_content)
+
+ # The loop exited meaning that the user has guessed the word
+ await original_message.edit(embed=self.create_embed(tries, user_guess))
+ win_embed = Embed(
+ title="You won!",
+ description=f"The word was `{word}`.",
+ color=Colours.grass_green
+ )
+ await ctx.send(embed=win_embed)
+
+
+def setup(bot: Bot) -> None:
+ """Load the Hangman cog."""
+ bot.add_cog(Hangman(bot))
diff --git a/bot/resources/fun/hangman_words.txt b/bot/resources/fun/hangman_words.txt
new file mode 100644
index 00000000..5e20bfde
--- /dev/null
+++ b/bot/resources/fun/hangman_words.txt
@@ -0,0 +1,877 @@
+abandon
+ability
+able
+about
+above
+accept
+according
+account
+across
+action
+activity
+actually
+address
+administration
+admit
+adult
+affect
+after
+again
+against
+agency
+agent
+agree
+agreement
+ahead
+allow
+almost
+alone
+along
+already
+also
+although
+always
+among
+amount
+analysis
+animal
+another
+answer
+anyone
+anything
+appear
+apply
+approach
+area
+argue
+around
+arrive
+article
+artist
+assume
+attack
+attention
+attorney
+audience
+author
+authority
+available
+avoid
+away
+baby
+back
+ball
+bank
+base
+beat
+beautiful
+because
+become
+before
+begin
+behavior
+behind
+believe
+benefit
+best
+better
+between
+beyond
+bill
+billion
+black
+blood
+blue
+board
+body
+book
+born
+both
+break
+bring
+brother
+budget
+build
+building
+business
+bytecode
+call
+camera
+campaign
+cancer
+candidate
+capital
+card
+care
+career
+carry
+case
+catch
+cause
+cell
+center
+central
+century
+certain
+certainly
+chair
+challenge
+chance
+change
+character
+charge
+check
+child
+choice
+choose
+church
+citizen
+city
+civil
+claim
+class
+clear
+clearly
+close
+coach
+cold
+collection
+college
+color
+come
+commercial
+common
+community
+company
+compare
+computer
+concern
+condition
+conference
+consider
+consumer
+contain
+continue
+control
+cost
+could
+country
+couple
+course
+court
+cover
+create
+crime
+cultural
+culture
+current
+customer
+dark
+data
+daughter
+dead
+deal
+death
+debate
+decade
+decide
+decision
+deep
+defense
+degree
+describe
+design
+despite
+detail
+determine
+develop
+development
+dictionary
+difference
+different
+difficult
+dinner
+direction
+director
+discover
+discuss
+discussion
+disease
+doctor
+door
+down
+draw
+dream
+drive
+drop
+during
+each
+early
+east
+easy
+economic
+economy
+edge
+education
+effect
+effort
+eight
+either
+election
+else
+employee
+energy
+enjoy
+enough
+enter
+entire
+environment
+environmental
+especially
+establish
+even
+evening
+event
+ever
+every
+everybody
+everyone
+everything
+evidence
+exactly
+example
+executive
+exist
+expect
+experience
+expert
+explain
+face
+fact
+factor
+fall
+false
+family
+fast
+father
+fear
+federal
+feel
+feeling
+field
+fight
+figure
+fill
+film
+final
+finally
+financial
+find
+fine
+finger
+finish
+fire
+firm
+first
+fish
+five
+floor
+focus
+follow
+food
+foot
+force
+foreign
+forget
+form
+former
+forward
+four
+free
+friend
+from
+front
+full
+function
+fund
+future
+game
+garden
+general
+generation
+girl
+give
+glass
+goal
+good
+government
+great
+green
+ground
+group
+grow
+growth
+guess
+guido
+hair
+half
+hand
+hang
+happen
+happy
+hard
+have
+head
+health
+hear
+heart
+heat
+heavy
+help
+here
+herself
+high
+himself
+history
+hold
+home
+hope
+hospital
+hotel
+hour
+house
+however
+huge
+human
+hundred
+husband
+idea
+identify
+image
+imagine
+impact
+import
+important
+improve
+include
+including
+increase
+indeed
+indicate
+individual
+industry
+information
+inside
+instead
+institution
+interest
+interesting
+international
+interpreter
+interview
+into
+investment
+involve
+issue
+item
+itself
+join
+just
+keep
+kill
+kind
+kitchen
+know
+knowledge
+land
+lambda
+language
+large
+last
+late
+later
+laugh
+lawyer
+lead
+leader
+learn
+least
+leave
+left
+legal
+less
+letter
+level
+life
+light
+like
+likely
+line
+list
+listen
+little
+live
+local
+long
+look
+loop
+lose
+loss
+love
+machine
+magazine
+main
+maintain
+major
+majority
+make
+manage
+management
+manager
+many
+market
+marriage
+material
+matter
+maybe
+mean
+measure
+media
+medical
+meet
+meeting
+member
+memory
+mention
+message
+method
+middle
+might
+military
+million
+mind
+minute
+miss
+mission
+model
+modern
+moment
+money
+month
+more
+morning
+most
+mother
+mouth
+move
+movement
+movie
+much
+music
+must
+myself
+name
+nation
+national
+natural
+nature
+near
+nearly
+necessary
+need
+network
+never
+news
+newspaper
+next
+nice
+nightnone
+north
+note
+nothing
+notice
+number
+object
+occur
+offer
+office
+officer
+official
+often
+once
+only
+onto
+open
+operation
+opportunity
+option
+order
+organization
+other
+others
+outside
+over
+owner
+page
+pain
+painting
+paper
+parameters
+parent
+part
+participant
+particular
+particularly
+partner
+party
+pass
+past
+patient
+pattern
+peace
+people
+perform
+performance
+perhaps
+period
+person
+personal
+phone
+physical
+pick
+picture
+piece
+place
+plan
+plant
+play
+player
+point
+police
+policy
+political
+politics
+poor
+popular
+population
+position
+positive
+possible
+power
+practice
+prepare
+present
+president
+pressure
+pretty
+prevent
+price
+print
+private
+probably
+problem
+process
+produce
+product
+production
+professional
+professor
+program
+project
+property
+protect
+prove
+provide
+public
+pull
+purpose
+push
+pydis
+pygame
+python
+quality
+question
+quickly
+quite
+race
+radio
+raise
+range
+rate
+rather
+reach
+read
+ready
+real
+reality
+realize
+really
+reason
+receive
+recent
+recently
+recognize
+record
+reduce
+reflect
+region
+relate
+relationship
+remain
+remember
+remove
+report
+represent
+require
+research
+resource
+respond
+response
+responsibility
+rest
+result
+return
+reveal
+rich
+right
+rise
+risk
+road
+rock
+role
+room
+rule
+safe
+same
+save
+scene
+school
+science
+scientist
+score
+season
+seat
+second
+section
+security
+seek
+seem
+sell
+send
+senior
+sense
+series
+serious
+serve
+service
+seven
+several
+shake
+share
+shoot
+short
+shot
+should
+shoulder
+show
+side
+sign
+significant
+similar
+simple
+simply
+since
+sing
+single
+sister
+site
+situation
+size
+skill
+skin
+small
+smile
+social
+society
+soldier
+some
+somebody
+someone
+something
+sometimes
+song
+soon
+sort
+sound
+source
+south
+southern
+space
+speak
+special
+specific
+speech
+spend
+sport
+spring
+staff
+stage
+stand
+standard
+star
+start
+state
+statement
+station
+stay
+step
+still
+stock
+stop
+store
+story
+strategy
+street
+strong
+structure
+student
+study
+stuff
+style
+subject
+success
+successful
+such
+suddenly
+suffer
+suggest
+summer
+support
+sure
+surface
+system
+table
+take
+talk
+task
+teach
+teacher
+team
+technology
+television
+tell
+tend
+term
+test
+than
+thank
+that
+their
+them
+themselves
+then
+theory
+there
+these
+they
+thing
+think
+third
+this
+those
+though
+thought
+thousand
+threat
+three
+through
+throughout
+throw
+thus
+time
+today
+together
+tonight
+total
+tough
+toward
+town
+trade
+traditional
+training
+travel
+treat
+treatment
+tree
+trial
+trip
+trouble
+true
+truth
+turn
+type
+under
+understand
+unit
+until
+upon
+usually
+value
+variable
+various
+very
+victim
+view
+visit
+voice
+vote
+wait
+walk
+wall
+want
+watch
+water
+wear
+week
+weight
+well
+west
+western
+what
+whatever
+when
+where
+whether
+which
+while
+white
+whole
+whom
+whose
+wide
+wife
+will
+wind
+window
+wish
+with
+within
+without
+woman
+wonder
+word
+work
+worker
+world
+worry
+would
+write
+writer
+wrong
+yard
+yield
+yeah
+year
+young
+your
+yourself