mirror of
https://code.dnix.de/da/flokatirc
synced 2026-07-27 07:49:44 +02:00
Merged branch master into master
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2015,2016 Andreas Neue
|
||||
Copyright (c) 2015,2016 Andreas Neue, Daniel Aberger
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -29,7 +29,9 @@ var (
|
||||
channels = flag.String("chan", "#test", "Channels to join")
|
||||
nsname = flag.String("nsname", "NickServ", "NickServ name")
|
||||
nspass = flag.String("nspass", "", "NickServ password")
|
||||
mods = flag.String("mods", "", "Modules to load")
|
||||
params = flag.String("params", "", "Module params")
|
||||
autocmd = flag.String("autocmd", "", "Autosend IRC command")
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -43,7 +45,7 @@ var (
|
||||
func main() {
|
||||
sayCh = make(chan string, 1024)
|
||||
|
||||
xlog.Init(xlog.INFO)
|
||||
xlog.Init(xlog.DEBUG)
|
||||
|
||||
//bot := ircx.Classic(*server, *name)
|
||||
cfg := ircx.Config{User: *name, MaxRetries: 1000}
|
||||
@@ -57,7 +59,8 @@ func main() {
|
||||
//mods := strings.Split(*modules, ",")
|
||||
//TODO: implement more robust list parsing
|
||||
|
||||
modules.Init(sayCh, *params)
|
||||
modules.Init(sayCh, *mods, *params)
|
||||
modules.ModParams["_nick"] = *name
|
||||
|
||||
go func() {
|
||||
for {
|
||||
@@ -82,6 +85,11 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
go Ping(bot)
|
||||
if *autocmd != "" {
|
||||
println(*autocmd)
|
||||
bot.Sender.Send(&irc.Message{Command: *autocmd})
|
||||
}
|
||||
RegisterHandlers(bot)
|
||||
bot.HandleLoop()
|
||||
xlog.Info("Exiting")
|
||||
@@ -94,6 +102,13 @@ func RegisterHandlers(bot *ircx.Bot) {
|
||||
bot.HandleFunc(irc.PRIVMSG, PrivmsgHandler)
|
||||
}
|
||||
|
||||
func Ping(bot *ircx.Bot) {
|
||||
for {
|
||||
time.Sleep(1 * time.Minute)
|
||||
bot.Sender.Send(&irc.Message{Command: irc.PING})
|
||||
}
|
||||
}
|
||||
|
||||
func ConnectHandler(s ircx.Sender, m *irc.Message) {
|
||||
if *nspass != "" {
|
||||
xlog.Info("Authenticating with NickServ: %v, %v", *name, *nspass)
|
||||
|
||||
@@ -5,16 +5,13 @@ package modules
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
func init() {
|
||||
MsgHandlers["announcements"] = anncouncementsHandleMessage
|
||||
xlog.Info("Announcements module initialized")
|
||||
MsgFuncs["announcements"] = anncouncementsHandleMessage
|
||||
}
|
||||
|
||||
func anncouncementsHandleMessage(m *irc.Message) {
|
||||
|
||||
+1
-5
@@ -12,8 +12,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
"github.com/sorcix/irc/ctcp"
|
||||
)
|
||||
@@ -29,9 +27,8 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["coffee"] = coffeeHandleMessage
|
||||
MsgFuncs["coffee"] = coffeeHandleMessage
|
||||
r.names = make(map[string]bool)
|
||||
xlog.Info("Coffee module initialized")
|
||||
}
|
||||
|
||||
func coffeeHandleMessage(m *irc.Message) {
|
||||
@@ -108,4 +105,3 @@ func printAction(s string) {
|
||||
msg := ctcp.Encode(ctcp.ACTION, fmt.Sprintf(s))
|
||||
SayCh <- fmt.Sprintf("%s\n%s", "*", msg)
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -8,14 +8,11 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["fortune"] = fortuneHandleMessage
|
||||
xlog.Info("Fortune module initialized")
|
||||
MsgFuncs["fortune"] = fortuneHandleMessage
|
||||
}
|
||||
|
||||
func fortuneHandleMessage(m *irc.Message) {
|
||||
|
||||
@@ -7,14 +7,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["fuzzytime"] = fuzzytimeHandleMessage
|
||||
xlog.Info("Fuzzytime module initialized")
|
||||
MsgFuncs["fuzzytime"] = fuzzytimeHandleMessage
|
||||
}
|
||||
|
||||
func fuzzytimeHandleMessage(m *irc.Message) {
|
||||
|
||||
+2
-4
@@ -8,8 +8,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
@@ -18,8 +16,8 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["gogs"] = gogsHandleMessage
|
||||
xlog.Info("Gogs module initialized")
|
||||
MsgFuncs["gogs"] = gogsHandleMessage
|
||||
RunFuncs["gogs"] = gogsConfig
|
||||
}
|
||||
|
||||
func gogsConfig() {
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
// vi:ts=4:sts=4:sw=4:noet:tw=72
|
||||
|
||||
package modules
|
||||
|
||||
// This Markov chain code is taken from the "Generating arbitrary text"
|
||||
// codewalk: http://golang.org/doc/codewalk/markov/
|
||||
//
|
||||
// Minor modifications have been made to make it easier to integrate
|
||||
// with a webserver and to save/load state
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
var markovChain *MarkovChain
|
||||
|
||||
func init() {
|
||||
MsgFuncs["markov"] = markovHandleMessage
|
||||
RunFuncs["markov"] = markovRun
|
||||
}
|
||||
|
||||
func markovHandleMessage(m *irc.Message) {
|
||||
text := m.Trailing
|
||||
if text == "" {
|
||||
return
|
||||
}
|
||||
text = markovParseText(text)
|
||||
|
||||
answerLen, _ := strconv.Atoi(ModParams["markov-answer-len"])
|
||||
respChance, _ := strconv.Atoi(ModParams["markov-response-chance"])
|
||||
if rand.Intn(100) <= respChance || strings.Index(text, strings.ToLower(ModParams["_nick"])) != -1 {
|
||||
responseText := markovChain.Generate(answerLen, text)
|
||||
if responseText != "" {
|
||||
go func() {
|
||||
time.Sleep(time.Duration(rand.Intn(8)+2) * time.Second)
|
||||
SayCh <- "*\n" + responseText
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
markovChain.Write(text)
|
||||
}
|
||||
|
||||
func markovRun() {
|
||||
prefixLen, _ := strconv.Atoi(ModParams["markov-prefix-len"])
|
||||
markovChain = markovNewChain(prefixLen)
|
||||
err := markovChain.Load(ModParams["markov-state-file"])
|
||||
if err != nil {
|
||||
xlog.Error(err.Error())
|
||||
}
|
||||
filepath := ModParams["markov-import-file"]
|
||||
if filepath != "-" {
|
||||
file, _ := os.Open(filepath)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
text = markovParseText(text)
|
||||
if text != "" {
|
||||
markovChain.Write(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(60 * time.Second)
|
||||
markovChain.Save(ModParams["markov-state-file"])
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
func markovParseText(text string) string {
|
||||
messageRegex := regexp.MustCompile(`<([^>]+)>`)
|
||||
matches := messageRegex.FindAllStringSubmatch(text, -1)
|
||||
for _, matches2 := range matches {
|
||||
|
||||
if strings.HasPrefix(matches2[1], "http") || strings.HasPrefix(matches2[1], "mailto") {
|
||||
text = strings.Replace(text, matches2[0], "", -1)
|
||||
|
||||
} else if strings.HasPrefix(matches2[1], "@U") {
|
||||
parts := strings.SplitN(matches2[1], "|", 2)
|
||||
|
||||
if len(parts) == 2 {
|
||||
text = strings.Replace(text, matches2[0], "@"+parts[1], -1)
|
||||
} else {
|
||||
text = strings.Replace(text, matches2[0], "", -1)
|
||||
}
|
||||
|
||||
} else if strings.HasPrefix(matches2[1], "@") {
|
||||
text = strings.Replace(text, matches2[0], matches2[1], -1)
|
||||
|
||||
} else if strings.HasPrefix(matches2[1], "#") {
|
||||
parts := strings.SplitN(matches2[1], "|", 2)
|
||||
|
||||
if len(parts) == 2 {
|
||||
text = strings.Replace(text, matches2[0], "#"+parts[1], -1)
|
||||
} else {
|
||||
text = strings.Replace(text, matches2[0], "", -1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
text = strings.TrimSpace(text)
|
||||
|
||||
text = strings.Replace(text, "<", "<", -1)
|
||||
text = strings.Replace(text, ">", ">", -1)
|
||||
text = strings.Replace(text, "&", "&", -1)
|
||||
|
||||
return strings.ToLower(text)
|
||||
}
|
||||
|
||||
// Prefix is a Markov chain prefix of one or more words.
|
||||
type MarkovPrefix []string
|
||||
|
||||
// String returns the Prefix as a string (for use as a map key).
|
||||
func (p MarkovPrefix) String() string {
|
||||
return strings.Trim(strings.Join(p, " "), " ")
|
||||
}
|
||||
|
||||
// Shift removes the first word from the Prefix and appends the given word.
|
||||
func (p MarkovPrefix) Shift(word string) {
|
||||
copy(p, p[1:])
|
||||
p[len(p)-1] = word
|
||||
}
|
||||
|
||||
// MarkovChain contains a map ("chain") of prefixes to a list of suffixes.
|
||||
// A prefix is a string of prefixLen words joined with spaces.
|
||||
// A suffix is a single word. A prefix can have multiple suffixes.
|
||||
type MarkovChain struct {
|
||||
MarkovChain map[string][]string
|
||||
prefixLen int
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewMarkovChain returns a new MarkovChain with prefixes of prefixLen words.
|
||||
func markovNewChain(prefixLen int) *MarkovChain {
|
||||
return &MarkovChain{
|
||||
MarkovChain: make(map[string][]string),
|
||||
prefixLen: prefixLen,
|
||||
}
|
||||
}
|
||||
|
||||
// Write parses the bytes into prefixes and suffixes that are stored in MarkovChain.
|
||||
func (c *MarkovChain) Write(in string) (int, error) {
|
||||
in = strings.ToLower(in)
|
||||
if strings.HasPrefix(in, strings.ToLower(ModParams["_nick"])) {
|
||||
tok := strings.Split(in, " ")
|
||||
in = strings.Replace(in, tok[0]+" ", "", 1)
|
||||
}
|
||||
sr := strings.NewReader(in)
|
||||
p := make(MarkovPrefix, c.prefixLen)
|
||||
for {
|
||||
var s string
|
||||
if _, err := fmt.Fscan(sr, &s); err != nil {
|
||||
break
|
||||
}
|
||||
key := p.String()
|
||||
c.mu.Lock()
|
||||
c.MarkovChain[key] = append(c.MarkovChain[key], s)
|
||||
c.mu.Unlock()
|
||||
xlog.Debug("Chain len: %d, learned [%s] [%s]", len(c.MarkovChain), key, s)
|
||||
p.Shift(s)
|
||||
}
|
||||
return len(in), nil
|
||||
}
|
||||
|
||||
// Generate returns a string of at most n words generated from MarkovChain.
|
||||
func (c *MarkovChain) Generate(n int, in string) string {
|
||||
in = strings.ToLower(in)
|
||||
if strings.HasPrefix(in, strings.ToLower(ModParams["_nick"])) {
|
||||
tok := strings.Split(in, " ")
|
||||
in = strings.Replace(in, tok[0]+" ", "", 1)
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
p := make(MarkovPrefix, c.prefixLen)
|
||||
p = strings.Split(in, " ")
|
||||
if len(p) > c.prefixLen {
|
||||
i := rand.Intn(len(p) - 1)
|
||||
p = p[i : i+c.prefixLen]
|
||||
}
|
||||
prefix := p.String()
|
||||
xlog.Debug("Looking for answer on [%s]", prefix)
|
||||
var words []string
|
||||
for i := 0; i < n; i++ {
|
||||
choices := c.MarkovChain[p.String()]
|
||||
if len(choices) == 0 {
|
||||
break
|
||||
}
|
||||
next := choices[rand.Intn(len(choices))]
|
||||
words = append(words, next)
|
||||
if strings.HasSuffix(next, ".") || strings.HasSuffix(next, "!") || strings.HasSuffix(next, "?") {
|
||||
break
|
||||
}
|
||||
p.Shift(next)
|
||||
}
|
||||
prefix = strings.Trim(prefix, " ")
|
||||
if len(words) == 0 {
|
||||
xlog.Debug("No answer found")
|
||||
return prefix + " ... pfrrrz"
|
||||
} else {
|
||||
xlog.Debug("Found words: [%s]", strings.Join(words, " "))
|
||||
return prefix + " " + strings.Join(words, " ")
|
||||
}
|
||||
}
|
||||
|
||||
// Save the chain to a file
|
||||
func (c *MarkovChain) Save(fileName string) error {
|
||||
// Open the file for writing
|
||||
fo, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// close fo on exit and check for its returned error
|
||||
defer func() {
|
||||
if err := fo.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create an encoder and dump to it
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
enc := gob.NewEncoder(fo)
|
||||
err = enc.Encode(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the chain from a file
|
||||
func (c *MarkovChain) Load(fileName string) error {
|
||||
// Open the file for reading
|
||||
fi, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// close fi on exit and check for its returned error
|
||||
defer func() {
|
||||
if err := fi.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create a decoder and read from it
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
dec := gob.NewDecoder(fi)
|
||||
err = dec.Decode(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+28
-3
@@ -8,26 +8,51 @@ package modules
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
|
||||
var (
|
||||
SayCh chan string
|
||||
MsgHandlers = make(map[string]func(*irc.Message))
|
||||
MsgFuncs = make(map[string]func(*irc.Message))
|
||||
RunFuncs = make(map[string]func())
|
||||
ModParams = make(map[string]string)
|
||||
)
|
||||
|
||||
func Init(ch chan string, params string) {
|
||||
func Init(ch chan string, mods, params string) {
|
||||
time.Sleep(5 * time.Second)
|
||||
SayCh = ch
|
||||
for mod, _ := range MsgFuncs {
|
||||
if !contains(strings.Split(mods, ","), mod) {
|
||||
delete(MsgFuncs, mod)
|
||||
}
|
||||
}
|
||||
for mod, _ := range RunFuncs {
|
||||
if !contains(strings.Split(mods, ","), mod) {
|
||||
delete(RunFuncs, mod)
|
||||
}
|
||||
}
|
||||
for _, param := range strings.Split(params, "!") {
|
||||
kv := strings.Split(param, ":")
|
||||
ModParams[kv[0]] = kv[1]
|
||||
}
|
||||
for _, fn := range RunFuncs {
|
||||
go fn()
|
||||
}
|
||||
}
|
||||
|
||||
func HandleMessage(m *irc.Message) {
|
||||
for _, fn := range MsgHandlers {
|
||||
for _, fn := range MsgFuncs {
|
||||
fn(m)
|
||||
}
|
||||
}
|
||||
|
||||
func contains(sa []string, s string) bool {
|
||||
for _, a := range sa {
|
||||
if a == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
// vi:ts=4:sts=4:sw=4:noet:tw=72
|
||||
|
||||
package modules
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flokatirc/util"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
)
|
||||
|
||||
type quizQuestion struct {
|
||||
category, question, answer, regexp, level string
|
||||
}
|
||||
|
||||
var (
|
||||
quizCtrlCh = make(chan string, 1024)
|
||||
quizAnswerCh = make(chan *irc.Message, 1024)
|
||||
quizQuestions []quizQuestion
|
||||
quizQuestionValues = map[string]int{"extreme": 5, "hard": 4, "normal": 3, "easy": 2, "baby": 1}
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgFuncs["quiz"] = quizHandleMessage
|
||||
RunFuncs["quiz"] = quiz
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func quizHandleMessage(m *irc.Message) {
|
||||
tok := strings.Split(m.Trailing, " ")
|
||||
if len(tok) < 1 {
|
||||
return
|
||||
}
|
||||
switch tok[0] {
|
||||
case "!quiz", "!quizstart":
|
||||
quizCtrlCh <- "start"
|
||||
break
|
||||
case "!quizstop":
|
||||
quizCtrlCh <- "stop"
|
||||
break
|
||||
default:
|
||||
quizAnswerCh <- m
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func quiz() {
|
||||
time.Sleep(5 * time.Second)
|
||||
SayCh <- fmt.Sprintf("%s\nquiz mod test. !quizstart to start, !quizstop to end.", "*")
|
||||
for {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
select {
|
||||
case s := <-quizCtrlCh:
|
||||
if s == "start" {
|
||||
quizRun()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func quizRun() {
|
||||
quizQuestions = quizLoadQuestions("questions.txt")
|
||||
ranklist := make(map[string]int)
|
||||
SayCh <- fmt.Sprintf("%s\nQuiz gestartet.", "*")
|
||||
for {
|
||||
solved, cont, solver, gain := quizAskQuestion()
|
||||
if !cont {
|
||||
SayCh <- fmt.Sprintf("%s\nQuiz beendet.", "*")
|
||||
return
|
||||
} else {
|
||||
if solved {
|
||||
if _, exists := ranklist[solver]; exists {
|
||||
ranklist[solver] += gain
|
||||
} else {
|
||||
ranklist[solver] = gain
|
||||
}
|
||||
if ranklist[solver] > 1000 {
|
||||
bold := byte(0x02)
|
||||
solver = string(bold) + solver + string(bold)
|
||||
SayCh <- fmt.Sprintf("%s\n%s gewinnt!", "*", solver)
|
||||
quizPrintRanklist(ranklist)
|
||||
SayCh <- fmt.Sprintf("%s\nQuiz beendet.", "*")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
quizPrintRanklist(ranklist)
|
||||
}
|
||||
}
|
||||
|
||||
func quizPrintRanklist(ranklist map[string]int) {
|
||||
SayCh <- fmt.Sprintf("%s\nAktueller Punktestand:", "*")
|
||||
for k, v := range ranklist {
|
||||
SayCh <- fmt.Sprintf("%s\n%s: %d", "*", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func quizAskQuestion() (bool, bool, string, int) {
|
||||
q := quizQuestions[rand.Intn(len(quizQuestions))]
|
||||
SayCh <- fmt.Sprintf("%s\nEine Frage aus der Kategorie \"%s\" (%s):", "*", q.category, q.level)
|
||||
SayCh <- fmt.Sprintf("%s\n>>> %s <<<", "*", q.question)
|
||||
solved, cont, solver, gain := quizWaitForAnswer(q)
|
||||
if !solved {
|
||||
SayCh <- fmt.Sprintf("%s\nDie richtige Antwort wäre gewesen:", "*")
|
||||
SayCh <- fmt.Sprintf("%s\n%s [%s]", "*", q.answer, q.regexp)
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
return solved, cont, solver, gain
|
||||
}
|
||||
|
||||
func quizWaitForAnswer(q quizQuestion) (bool, bool, string, int) {
|
||||
i := 0
|
||||
haveAnswer := false
|
||||
timer := time.Now().Unix()
|
||||
for {
|
||||
select {
|
||||
case m := <-quizAnswerCh:
|
||||
haveAnswer = true
|
||||
points := 10 - ((time.Now().Unix() - timer) / 10)
|
||||
if points < 1 {
|
||||
points = 1
|
||||
}
|
||||
re, err := regexp.Compile(q.regexp)
|
||||
if err != nil {
|
||||
xlog.Error(err.Error())
|
||||
return false, false, "", 0
|
||||
}
|
||||
if re.MatchString(strings.ToLower(util.ReplaceUmlauts(m.Trailing))) {
|
||||
bold := byte(0x02)
|
||||
solver := strings.Split(m.Prefix.String(), "!")[0]
|
||||
solver = string(bold) + solver + string(bold)
|
||||
value := quizQuestionValues[q.level]
|
||||
gain := int(points) * value
|
||||
SayCh <- fmt.Sprintf("%s\n%s hat die Frage korrekt beantwortet und erhält dafür %d (%d * %d) Punkte.", "*", solver, gain, points, value)
|
||||
return true, true, solver, gain
|
||||
}
|
||||
break
|
||||
case s := <-quizCtrlCh:
|
||||
if s == "stop" {
|
||||
return false, false, "", 0
|
||||
}
|
||||
break
|
||||
case <-time.After(15 * time.Second):
|
||||
i++
|
||||
if i > 3 {
|
||||
if haveAnswer {
|
||||
SayCh <- fmt.Sprintf("%s\nNiemand konnte die Frage korrekt beantworten.", "*")
|
||||
return false, true, "", 0
|
||||
} else {
|
||||
SayCh <- fmt.Sprintf("%s\nNiemand hat auf die Frage geantwortet.", "*")
|
||||
return false, false, "", 0
|
||||
}
|
||||
} else {
|
||||
quizGiveHint(q, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func quizGiveHint(q quizQuestion, n int) {
|
||||
var hint string
|
||||
haveHint := false
|
||||
for {
|
||||
hint = ""
|
||||
for i := 0; i < len(q.answer); i++ {
|
||||
if string(q.answer[i]) == " " {
|
||||
hint += " "
|
||||
} else {
|
||||
if rand.Intn(10) < 2 {
|
||||
haveHint = true
|
||||
hint += string(q.answer[i])
|
||||
} else {
|
||||
hint += "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
if haveHint {
|
||||
break
|
||||
}
|
||||
}
|
||||
SayCh <- fmt.Sprintf("%s\nTipp: %s", "*", hint)
|
||||
}
|
||||
|
||||
func quizLoadQuestions(path string) []quizQuestion {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
xlog.Fatal(err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
questions := make([]quizQuestion, 0)
|
||||
q := quizQuestion{"", "", "", "", ""}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if len(line) == 0 || line[0] == '#' || line[0] == '\n' {
|
||||
if q.category != "" {
|
||||
questions = append(questions, q)
|
||||
q = quizQuestion{"", "", "", "", "normal"}
|
||||
}
|
||||
} else {
|
||||
tok := strings.Split(line, ":: ")
|
||||
switch tok[0] {
|
||||
case "Category":
|
||||
q.category = tok[1]
|
||||
break
|
||||
case "Question":
|
||||
q.question = tok[1]
|
||||
break
|
||||
case "Answer":
|
||||
q.answer = strings.Replace(util.ReplaceUmlauts(tok[1]), "#", "", -1)
|
||||
if q.regexp == "" {
|
||||
regexp := strings.Split(strings.ToLower(util.ReplaceUmlauts(tok[1])), "#")
|
||||
if len(regexp) > 1 {
|
||||
q.regexp = regexp[1]
|
||||
} else {
|
||||
q.regexp = regexp[0]
|
||||
}
|
||||
}
|
||||
break
|
||||
case "Regexp":
|
||||
q.regexp = util.ReplaceUmlauts(strings.ToLower(tok[1]))
|
||||
break
|
||||
case "Level":
|
||||
q.level = tok[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
xlog.Fatal(err.Error())
|
||||
}
|
||||
|
||||
return questions
|
||||
}
|
||||
+2
-3
@@ -24,9 +24,8 @@ import (
|
||||
var hideOutput = true
|
||||
|
||||
func init() {
|
||||
MsgHandlers["rss"] = rssHandleMessage
|
||||
go rssRun()
|
||||
xlog.Info("RSS module initialized")
|
||||
MsgFuncs["rss"] = rssHandleMessage
|
||||
RunFuncs["rss"] = rssRun
|
||||
}
|
||||
|
||||
func rssRun() {
|
||||
|
||||
+2
-3
@@ -48,9 +48,8 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["sc"] = scHandleMessage
|
||||
go scScrapeLoop()
|
||||
xlog.Info("SC module initialized")
|
||||
MsgFuncs["sc"] = scHandleMessage
|
||||
RunFuncs["sc"] = scScrapeLoop
|
||||
}
|
||||
|
||||
func scHandleMessage(m *irc.Message) {
|
||||
|
||||
+5
-6
@@ -3,11 +3,10 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"flokatirc/util"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"code.dnix.de/an/xlog"
|
||||
"time"
|
||||
|
||||
"github.com/sorcix/irc"
|
||||
)
|
||||
@@ -522,8 +521,8 @@ var quotes = [][]string{
|
||||
}
|
||||
|
||||
func init() {
|
||||
MsgHandlers["stoll"] = stollHandleMessage
|
||||
xlog.Info("Stoll module initialized")
|
||||
MsgFuncs["stoll"] = stollHandleMessage
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func stollHandleMessage(m *irc.Message) {
|
||||
@@ -534,7 +533,7 @@ func stollHandleMessage(m *irc.Message) {
|
||||
if tok[0] == "!stoll" {
|
||||
line := ""
|
||||
for i := 0; i < 3; i++ {
|
||||
line += quotes[i][util.Random(0, len(quotes[i]))]
|
||||
line += quotes[i][rand.Intn(len(quotes[i]))]
|
||||
line += " "
|
||||
}
|
||||
line += "[Dr. Axel Stoll, promovierter Naturwissenschaftler]"
|
||||
|
||||
+2
-3
@@ -137,9 +137,8 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
MsgHandlers["twitch"] = twitchHandleMessage
|
||||
go pollStreamData()
|
||||
xlog.Info("Twitch module initialized")
|
||||
MsgFuncs["twitch"] = twitchHandleMessage
|
||||
RunFuncs["twitch"] = pollStreamData
|
||||
}
|
||||
|
||||
func twitchHandleMessage(m *irc.Message) {
|
||||
|
||||
+2
-3
@@ -71,9 +71,8 @@ type WeatherObject struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
MsgHandlers["weather"] = weatherHandleMessage
|
||||
go weatherConfig()
|
||||
xlog.Info("Weather module initialized")
|
||||
MsgFuncs["weather"] = weatherHandleMessage
|
||||
RunFuncs["weather"] = weatherConfig
|
||||
}
|
||||
|
||||
func weatherConfig() {
|
||||
|
||||
+10
-5
@@ -4,9 +4,8 @@ package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ToInt(v interface{}) int {
|
||||
@@ -48,7 +47,13 @@ func NumberToString(n int, sep rune) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func Random(min, max int) int {
|
||||
rand.Seed(time.Now().Unix())
|
||||
return rand.Intn(max-min) + min
|
||||
func ReplaceUmlauts(s string) string {
|
||||
ret := strings.Replace(s, "Ä", "Ae", -1)
|
||||
ret = strings.Replace(ret, "Ö", "Oe", -1)
|
||||
ret = strings.Replace(ret, "Ü", "Ue", -1)
|
||||
ret = strings.Replace(ret, "ä", "ae", -1)
|
||||
ret = strings.Replace(ret, "ö", "oe", -1)
|
||||
ret = strings.Replace(ret, "ü", "ue", -1)
|
||||
ret = strings.Replace(ret, "ß", "ss", -1)
|
||||
return ret
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user