--important, reminder, Digit ! This is stage4 type, not stage 3 type. -- therefor, mind your pastes from type 3 to type 4 need the " h" taken out of equations -- This is the Father Jack version of daskeb (digit's haskell bot). -- in this version -- its sole feature is to answer any question with: -- "Yes." -- and if pressed (if asked with nickpinged): -- "That would be an ecumenical matter." import Data.List import Network import System.IO import System.Exit import Control.Arrow import Control.Monad.Reader import Control.Exception import Text.Printf import System.Random -- import random, it said, surely they meant import Random, trying System.Random server = "irc.freenode.org" port = 6667 chan = "#fatherjack" nick = "FatherJackBot" -- The 'Net' monad, a wrapper over IO, carrying the bot's immutable state. type Net = ReaderT Bot IO data Bot = Bot { socket :: Handle } -- Set up actions to run on start and end, and run the main loop main :: IO () main = bracket connect disconnect loop where disconnect = hClose . socket loop st = runReaderT run st -- Connect to the server and return the initial bot state connect :: IO Bot connect = notify $ do h <- connectTo server (PortNumber (fromIntegral port)) hSetBuffering h NoBuffering return (Bot h) where notify a = bracket_ (printf "Connecting to %s ... " server >> hFlush stdout) (putStrLn "done.") a -- We're in the Net monad now, so we've connected successfully -- Join a channel, and start processing commands run :: Net () run = do write "NICK" nick write "USER" (nick++" 0 * :DigitsHaskellBot") write "JOIN" chan asks socket >>= listen -- Process each line from the server listen :: Handle -> Net () listen h = forever $ do s <- init `fmap` io (hGetLine h) io (putStrLn s) if ping s then pong s else eval (clean s) where forever a = a >> forever a clean = drop 1 . dropWhile (/= ':') . drop 1 ping x = "PING :" `isPrefixOf` x pong x = write "PONG" (':' : drop 6 x) ---- this is/was/willbe another way of doing it, with the randomised either answer. --let ecumenical = ["yes","that would be an ecumenical matter."] --let ecumenical = [("yes"),("that would be an ecumenical matter.")] --ecumenical = [("yes"),("that would be an ecumenical matter.")] -- oh oh array! lets try that! --ecumenical = array (1, 3) [(1, "yes"),(2, "that would be an ecumenical matter."),(3, "drink!")] -- Dispatch a command eval :: String -> Net () ---- fatherjackbot: -- /THE/ FEATURE: ----iwishthisworkedsosomplesomethinglikesthis----eval x | "?" `isSuffixOf` x = privmsg (if "what""who""how""why""where""when" `isInfixOf` x then "that would be an ecumenical matter" else "yes") -- with a little help: https://stackoverflow.com/questions/56944717/how-can-i-make-the-target-of-a-conditional-be-any-of-many-search-for-any-of-a-l/56944826#56944826 --interrogatives = ["what", "who", "how", "why", "where", "when"] --eval x | "?" `isSuffixOf` x = privmsg (if any (`isInfixOf` x) interrogatives then "that would be an ecumenical matter" else "yes") -- riddances = ["stfu", "shut up", "go away", "be quiet", "stop that", "enough", "!", "rage", "please stop", "Hush", "hush", "HUSH", "quiet you", "Quiet you", "QUIET", "please segfault", "segfault please"] ----- ------------- ------------------------ ----------------------------------- -------------------------------------------------------------- --interrogatives = ["what", "who", "how", "why", "where", "when", "which", " or ", "What", "Who", "How", "Why", "Where", "When", "Which", "Or ", "WHAT", "WHO", "HOW", "WHY", "WHERE", "WHEN", "WHICH", " OR "] interrogatives = ["wat", "what", "who", "how", "why", "where", "when", "which", " or ", "What", "Who", "How", "Why", "Where", "When", "Which", "Or ", "WHAT", "WHO", "HOW", "WHY", "WHERE", "WHEN", "WHICH", " OR "] eval x | "?" `isSuffixOf` x = privmsg (if any (`isInfixOf` x) interrogatives then "that would be an ecumenical matter" else "yes") --eval x | "?" `isSuffixOf` x = privmsg (if any (`isInfixOf` x) interrogatives then "that would be an ecumenical matter" else "yes") -- --------------------------------------------- ------------------------------------------- ----------------------------------- --------------------------- ------------------- ------------- ----- -- old prior scraps, kept here for elucidation of simpler forms --eval x | "?" `isSuffixOf` x = privmsg (if "FatherJackBot:" `isPrefixOf` x then "that would be an ecumenical matter" else "yes") -- well at least this one works. --eval x | "?" `isInfixOf` x = privmsg (if "FatherJackBot:" `isPrefixOf` x then "That would be an ecumenical matter." else "Yes.") -- well at least this one works. -- THE /ANTI/-FEATURE: --eval x | "drink" `isInfixOf` x = privmsg (if "FatherJackBot:" `isPrefixOf` x then "glug glug glug" else "DRINK!") --eval x | "drink" `isInfixOf` x = privmsg (if "gives FatherJackBot" `isInfixOf` x then "glug glug glug" else "DRINK!") -- SAFETY DE-ANNOYANCE FEATURE --courtesy extra features: stfu & leave (/gtfo). -- the stfu feature is still in development -- current form, leaves if told to stfu directly. -- next intended dev goal: have gtfo > leave, and stfu > unresponsive mode -- (considering simply having gives drink be what makes fatherted go into stfu mode) -- (also considering having stfu include an optional timer, rather than toggle.) --eval x | "stfu" `isInfixOf` x = (if "FatherJackBot:" `isPrefixOf` x then write "QUIT" ":Exiting" >> io (exitWith ExitSuccess) else privmsg "hrm") -- -- this version works great ----- or did i break it again, doh. -- --eval x | "STFU!" `isInfixOf` x = (if "FatherJackBot:" `isPrefixOf` x then write "QUIT" ":Exiting" >> io (exitWith ExitSuccess) else return()) -- -- but i'm going to have a go putting in an aray like before. -- --riddances = ["stfu", "shut up", "go away", "be quiet", "stop that", "enough", "!", "rage", "please stop"] --eval x | "!!!" `isInfixOf` x = privmsg (if any (`isInfixOf` x) riddances then write "QUIT" ":Exiting" >> io (exitWith ExitSuccess) else return()) --desperate stab in the dark... --works but multiple declarations of eval... hrmmm eval x | "FatherJackBot" `isInfixOf` x = (if any (`isInfixOf` x) riddances then write "QUIT" ":Exiting" >> io (exitWith ExitSuccess) else return()) --"that would be an ecumenical matter" else "yes") -- --tbd: also, "i'm SO, SO sorry. :E :E :E" said before quitting...? it does take jack out of the well trained mode of that episode with the cardinals. twas sarcastic sorry to bishop brennan when he did that. --old basic leave, straight n clean, for reference: eval "!leave" = write "QUIT" ":Exiting" >> io (exitWith ExitSuccess) -- WEBSEARCH FEATURE eval x | "!search " `isPrefixOf` x = privmsg ("https://lmddgtfy.net/?q=" ++ (drop 8 x) ++ " ok?") -- added this back in to be useful. -- PARROT FEATURE --eval x | "!repeat " `isPrefixOf` x = privmsg (drop 8 x) -- commented this out to minimise abuse eval _ = return () -- ignore everything else -- Send a privmsg to the current chan + server privmsg :: String -> Net () privmsg s = write "PRIVMSG" (chan ++ " :" ++ s) -- Send a message out to the server we're currently connected to write :: String -> String -> Net () write s t = do h <- asks socket io $ hPrintf h "%s %s\r\n" s t io $ printf "> %s %s\n" s t -- Convenience. io :: IO a -> Net a io = liftIO