Created
January 9, 2020 23:35
-
-
Save Garmelon/e48054a1bb2b04a2ff686f4db2cf119d to your computer and use it in GitHub Desktop.
Ouija board bot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE OverloadedStrings #-} | |
module Haboli.Euphoria.WegaBorad where | |
import Control.Monad | |
import Control.Monad.Trans.Class | |
import Control.Monad.Trans.State | |
import Data.Char | |
import Data.Foldable | |
import Data.List | |
import qualified Data.Map.Strict as Map | |
import qualified Data.Text as T | |
import Haboli.Euphoria.Api | |
import Haboli.Euphoria.Client | |
{- Range stuff -} | |
data Range = Range Char Char | |
deriving (Eq) | |
instance Show Range where | |
show (Range a b) | |
| a == b = [a] | |
| otherwise = "[" ++ [a] ++ ".." ++ [b] ++ "]" | |
fullRange :: Range | |
fullRange = Range 'a' 'z' | |
getRangeChar :: Range -> Maybe Char | |
getRangeChar (Range a b) | |
| a == b = Just a | |
| otherwise = Nothing | |
splitRange :: Int -> Range -> [Range] | |
splitRange steps (Range a b) = | |
let amount = ord b - ord a + 1 | |
width = amount `div` steps | |
leftover = amount `mod` steps | |
widths = zipWith (+) (replicate steps width) (replicate leftover 1 ++ repeat 0) | |
skips = scanl (+) 0 (init widths) | |
in nub $ zipWith (\s w -> Range (chr $ ord a + s) (chr $ ord a + s + w - 1)) skips widths | |
{- Bot logic -} | |
data Search = Search | |
{ searchStartMsg :: Message | |
, searchOptions :: Map.Map Snowflake Range | |
} deriving (Show) | |
data MyState = MyState | |
{ msSplitInto :: Int | |
, msCurrentSearch :: Maybe Search | |
} deriving (Show) | |
defaultState :: MyState | |
defaultState = MyState 3 Nothing | |
type MyClient a = StateT MyState (Client ()) a | |
wegaBot :: MyClient () | |
wegaBot = forever $ do | |
event <- lift $ respondingToPing nextEvent | |
case event of | |
EventSnapshot _ -> void $ lift $ nick "WegaBot" | |
EventSend e -> onMessage (sendMessage e) | |
_ -> pure () | |
runWegaBot :: MyState -> MyClient a -> Client () a | |
runWegaBot start bot = fst <$> runStateT bot start | |
onMessage :: Message -> MyClient () | |
onMessage msg | |
| msgContent msg == "!wega" = startNewWega msg | |
| otherwise = do | |
s <- get | |
for_ (msCurrentSearch s) $ \search -> do | |
let maybeRange = do | |
parent <- msgParent msg | |
searchOptions search Map.!? parent | |
for_ maybeRange $ closeInOn search msg | |
startNewWega :: Message -> MyClient () | |
startNewWega msg = do | |
startMsg <- lift $ reply msg "New character!" | |
closeInOn (Search msg Map.empty) startMsg fullRange | |
-- | @'closeInOn' search msg range@ closes in on the currently running @search@, | |
-- where @msg@ has just selected @range@. | |
closeInOn :: Search -> Message -> Range -> MyClient () | |
closeInOn search msg range = | |
case getRangeChar range of | |
Just char -> do | |
void $ lift $ reply msg $ "You've selected " <> T.pack (show char) | |
startNewWega $ searchStartMsg search | |
Nothing -> do | |
s <- get | |
let possibleRanges = splitRange (msSplitInto s) range | |
rangesWithMessageIds <- mapM (sendRange msg) possibleRanges | |
let options = Map.fromList rangesWithMessageIds | |
put s{msCurrentSearch = Just search{searchOptions = options}} | |
sendRange :: Message -> Range -> MyClient (Snowflake, Range) | |
sendRange msg range = do | |
msg' <- lift $ reply msg $ "Reply to this message to choose " <> T.pack (show range) <> "." | |
pure (msgId msg', range) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment