From 01b2dc8a3b2f8c5c0f310520c8bd62d63b20664c Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Tue, 15 Mar 2016 18:35:49 +0100 Subject: [PATCH 01/13] Changed copyright holders --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8ee978b..e11aa89 100644 --- a/LICENSE +++ b/LICENSE @@ -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 From 7bffa566c5736ed10d9de8560e9ad1b2d08fe23b Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Sat, 19 Mar 2016 23:49:41 +0100 Subject: [PATCH 02/13] New mod management, new parameter -mods --- main.go | 3 ++- modules/announcements.go | 5 +---- modules/coffee.go | 6 +----- modules/fortune.go | 5 +---- modules/fuzzytime.go | 5 +---- modules/gogs.go | 6 ++---- modules/modules.go | 33 ++++++++++++++++++++++++++++----- modules/rss.go | 5 ++--- modules/sc.go | 5 ++--- modules/stoll.go | 5 +---- modules/twitch.go | 5 ++--- modules/weather.go | 5 ++--- util/util.go | 12 ++++++++++++ 13 files changed, 57 insertions(+), 43 deletions(-) diff --git a/main.go b/main.go index 44bed25..8dfcb1f 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ 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") ) @@ -57,7 +58,7 @@ func main() { //mods := strings.Split(*modules, ",") //TODO: implement more robust list parsing - modules.Init(sayCh, *params) + modules.Init(sayCh, *mods, *params) go func() { for { diff --git a/modules/announcements.go b/modules/announcements.go index a73ac8b..be2b1db 100644 --- a/modules/announcements.go +++ b/modules/announcements.go @@ -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) { diff --git a/modules/coffee.go b/modules/coffee.go index f1773ce..05a0207 100644 --- a/modules/coffee.go +++ b/modules/coffee.go @@ -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) } - diff --git a/modules/fortune.go b/modules/fortune.go index b71172d..b0cd8d4 100644 --- a/modules/fortune.go +++ b/modules/fortune.go @@ -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) { diff --git a/modules/fuzzytime.go b/modules/fuzzytime.go index b6197f7..802a66c 100644 --- a/modules/fuzzytime.go +++ b/modules/fuzzytime.go @@ -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) { diff --git a/modules/gogs.go b/modules/gogs.go index ccd36ed..026c657 100644 --- a/modules/gogs.go +++ b/modules/gogs.go @@ -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() { diff --git a/modules/modules.go b/modules/modules.go index 482d3df..c7fc4cc 100644 --- a/modules/modules.go +++ b/modules/modules.go @@ -13,21 +13,44 @@ import ( ) var ( - SayCh chan string - MsgHandlers = make(map[string]func(*irc.Message)) - ModParams = make(map[string]string) + SayCh chan string + 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) { 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 +} diff --git a/modules/rss.go b/modules/rss.go index 93685a4..62d76e7 100644 --- a/modules/rss.go +++ b/modules/rss.go @@ -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() { diff --git a/modules/sc.go b/modules/sc.go index 3d50d51..4952943 100644 --- a/modules/sc.go +++ b/modules/sc.go @@ -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) { diff --git a/modules/stoll.go b/modules/stoll.go index 59a6931..8b2a840 100644 --- a/modules/stoll.go +++ b/modules/stoll.go @@ -7,8 +7,6 @@ import ( "fmt" "strings" - "code.dnix.de/an/xlog" - "github.com/sorcix/irc" ) @@ -522,8 +520,7 @@ var quotes = [][]string{ } func init() { - MsgHandlers["stoll"] = stollHandleMessage - xlog.Info("Stoll module initialized") + MsgFuncs["stoll"] = stollHandleMessage } func stollHandleMessage(m *irc.Message) { diff --git a/modules/twitch.go b/modules/twitch.go index a94bda3..e2d2f48 100644 --- a/modules/twitch.go +++ b/modules/twitch.go @@ -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) { diff --git a/modules/weather.go b/modules/weather.go index dce2019..a63486b 100644 --- a/modules/weather.go +++ b/modules/weather.go @@ -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() { diff --git a/util/util.go b/util/util.go index a3d1d0b..90c5357 100644 --- a/util/util.go +++ b/util/util.go @@ -6,6 +6,7 @@ import ( "bytes" "math/rand" "strconv" + "strings" "time" ) @@ -52,3 +53,14 @@ 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 +} From cc4050e87e3bf73845fd6827135797dfeca73520 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Sat, 19 Mar 2016 23:51:15 +0100 Subject: [PATCH 03/13] Added quiz module. --- modules/quiz.go | 182 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 modules/quiz.go diff --git a/modules/quiz.go b/modules/quiz.go new file mode 100644 index 0000000..10aa87a --- /dev/null +++ b/modules/quiz.go @@ -0,0 +1,182 @@ +// vi:ts=4:sts=4:sw=4:noet:tw=72 + +package modules + +import ( + "bufio" + "flokatirc/util" + "fmt" + "os" + "regexp" + "strings" + "time" + + "github.com/sorcix/irc" + + "code.dnix.de/an/xlog" +) + +type quizQuestion struct { + category, question, answer, regexp string +} + +var ( + quizCtrlCh = make(chan string, 1024) + quizAnswerCh = make(chan *irc.Message, 1024) + quizQuestions []quizQuestion +) + +func init() { + MsgFuncs["quiz"] = quizHandleMessage + RunFuncs["quiz"] = quiz + quizQuestions = quizLoadQuestions("./modules/quiz/questions.de") +} + +func quizHandleMessage(m *irc.Message) { + tok := strings.Split(m.Trailing, " ") + if len(tok) < 1 { + return + } + switch tok[0] { + case "!quizstart": + quizCtrlCh <- "start" + break + case "!quizstop": + quizCtrlCh <- "stop" + break + default: + quizAnswerCh <- m + break + } +} + +func quiz() { + 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() { + for { + if !quizAskQuestion() { + return + } + } +} + +func quizAskQuestion() bool { + q := quizQuestions[util.Random(0, len(quizQuestions))] + SayCh <- fmt.Sprintf("%s\n%s (Kategorie: %s)", "*", q.question, q.category) + m, solved, cont := quizWaitForAnswer(q) + if solved { + SayCh <- fmt.Sprintf("%s\n%s hat die Frage beantwortet.", "*", m.Prefix) + } else { + SayCh <- fmt.Sprintf("%s\nNiemand konnte die Frage beantworten.", "*") + SayCh <- fmt.Sprintf("%s\nDie richtige Antwort wäre gewesen:", "*") + SayCh <- fmt.Sprintf("%s\n%s", "*", q.answer) + } + time.Sleep(5 * time.Second) + return cont +} + +func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { + i := 0 + t := 0 + for { + select { + case m := <-quizAnswerCh: + re, err := regexp.Compile(q.regexp) + if err != nil { + xlog.Error(err.Error()) + return nil, false, false + } + if re.MatchString(strings.ToLower(util.ReplaceUmlauts(m.Trailing))) { + return m, true, true + } + break + case s := <-quizCtrlCh: + if s == "stop" { + return nil, false, false + } + break + default: + time.Sleep(1 * time.Millisecond) + t++ + if t > 20000 { + t = 0 + i++ + if i > 3 { + return nil, false, true + } else { + quizGiveHint(q) + } + } + } + } +} + +func quizGiveHint(q quizQuestion) { + //SayCh <- fmt.Sprintf("%s\nHint: %s | %s", "*", q.answer, q.regexp) +} + +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{"", "", "", ""} + } + } 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(tok[1], "#", "", -1) + q.answer = util.ReplaceUmlauts(q.answer) + regexp := strings.Split(tok[1], "#") + if q.regexp == "" { + if len(regexp) > 1 { + q.regexp = strings.ToLower(regexp[1]) + } else { + q.regexp = strings.ToLower(regexp[0]) + } + } + break + case "Regexp": + q.regexp = util.ReplaceUmlauts(tok[1]) + break + } + } + } + + if err := scanner.Err(); err != nil { + xlog.Fatal(err.Error()) + } + + return questions +} From 41164153c8e72b7325b0fb761cc157e91d10f597 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Sun, 20 Mar 2016 23:01:04 +0100 Subject: [PATCH 04/13] Quiz module: Earn points for solved questions. --- main.go | 8 +++++ modules/modules.go | 2 ++ modules/quiz.go | 81 +++++++++++++++++++++++++++++++++------------- modules/stoll.go | 6 ++-- util/util.go | 7 ---- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/main.go b/main.go index 8dfcb1f..d371ed1 100644 --- a/main.go +++ b/main.go @@ -83,6 +83,7 @@ func main() { } }() + go Ping(bot) RegisterHandlers(bot) bot.HandleLoop() xlog.Info("Exiting") @@ -95,6 +96,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) diff --git a/modules/modules.go b/modules/modules.go index c7fc4cc..cdc02c1 100644 --- a/modules/modules.go +++ b/modules/modules.go @@ -8,6 +8,7 @@ package modules import ( "strings" + "time" "github.com/sorcix/irc" ) @@ -20,6 +21,7 @@ var ( ) 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) { diff --git a/modules/quiz.go b/modules/quiz.go index 10aa87a..9d2c6b7 100644 --- a/modules/quiz.go +++ b/modules/quiz.go @@ -6,6 +6,7 @@ import ( "bufio" "flokatirc/util" "fmt" + "math/rand" "os" "regexp" "strings" @@ -29,7 +30,8 @@ var ( func init() { MsgFuncs["quiz"] = quizHandleMessage RunFuncs["quiz"] = quiz - quizQuestions = quizLoadQuestions("./modules/quiz/questions.de") + quizQuestions = quizLoadQuestions("./modules/quiz/questions.txt") + rand.Seed(time.Now().Unix()) } func quizHandleMessage(m *irc.Message) { @@ -66,23 +68,26 @@ func quiz() { } func quizRun() { + SayCh <- fmt.Sprintf("%s\nQuiz gestartet.", "*") for { if !quizAskQuestion() { + SayCh <- fmt.Sprintf("%s\nQuiz beendet.", "*") return } } } func quizAskQuestion() bool { - q := quizQuestions[util.Random(0, len(quizQuestions))] - SayCh <- fmt.Sprintf("%s\n%s (Kategorie: %s)", "*", q.question, q.category) + q := quizQuestions[rand.Intn(len(quizQuestions))] + SayCh <- fmt.Sprintf("%s\nEine Frage aus der Kategorie \"%s\":", "*", q.category) + SayCh <- fmt.Sprintf("%s\n>>> %s <<<", "*", q.question) m, solved, cont := quizWaitForAnswer(q) if solved { - SayCh <- fmt.Sprintf("%s\n%s hat die Frage beantwortet.", "*", m.Prefix) + mm := m + m = mm } else { - SayCh <- fmt.Sprintf("%s\nNiemand konnte die Frage beantworten.", "*") SayCh <- fmt.Sprintf("%s\nDie richtige Antwort wäre gewesen:", "*") - SayCh <- fmt.Sprintf("%s\n%s", "*", q.answer) + SayCh <- fmt.Sprintf("%s\n%s [%s]", "*", q.answer, q.regexp) } time.Sleep(5 * time.Second) return cont @@ -90,16 +95,26 @@ func quizAskQuestion() bool { func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { i := 0 - t := 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 nil, false, false } 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) + SayCh <- fmt.Sprintf("%s\n%s hat die Frage korrekt beantwortet und erhält dafür %d Punkte.", "*", solver, points) return m, true, true } break @@ -108,24 +123,45 @@ func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { return nil, false, false } break - default: - time.Sleep(1 * time.Millisecond) - t++ - if t > 20000 { - t = 0 - i++ - if i > 3 { + case <-time.After(15 * time.Second): + i++ + if i > 3 { + if haveAnswer { + SayCh <- fmt.Sprintf("%s\nNiemand konnte die Frage korrekt beantworten.", "*") return nil, false, true } else { - quizGiveHint(q) + SayCh <- fmt.Sprintf("%s\nNiemand hat auf die Frage geantwortet.", "*") + return nil, false, false } + } else { + quizGiveHint(q, i) } } } } -func quizGiveHint(q quizQuestion) { - //SayCh <- fmt.Sprintf("%s\nHint: %s | %s", "*", q.answer, q.regexp) +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 { @@ -147,7 +183,7 @@ func quizLoadQuestions(path string) []quizQuestion { q = quizQuestion{"", "", "", ""} } } else { - tok := strings.Split(line, ": ") + tok := strings.Split(line, ":: ") switch tok[0] { case "Category": q.category = tok[1] @@ -157,18 +193,17 @@ func quizLoadQuestions(path string) []quizQuestion { break case "Answer": q.answer = strings.Replace(tok[1], "#", "", -1) - q.answer = util.ReplaceUmlauts(q.answer) - regexp := strings.Split(tok[1], "#") if q.regexp == "" { + regexp := strings.Split(strings.ToLower(util.ReplaceUmlauts(tok[1])), "#") if len(regexp) > 1 { - q.regexp = strings.ToLower(regexp[1]) + q.regexp = regexp[1] } else { - q.regexp = strings.ToLower(regexp[0]) + q.regexp = regexp[0] } } break case "Regexp": - q.regexp = util.ReplaceUmlauts(tok[1]) + q.regexp = util.ReplaceUmlauts(strings.ToLower(tok[1])) break } } diff --git a/modules/stoll.go b/modules/stoll.go index 8b2a840..32dd122 100644 --- a/modules/stoll.go +++ b/modules/stoll.go @@ -3,9 +3,10 @@ package modules import ( - "flokatirc/util" "fmt" + "math/rand" "strings" + "time" "github.com/sorcix/irc" ) @@ -521,6 +522,7 @@ var quotes = [][]string{ func init() { MsgFuncs["stoll"] = stollHandleMessage + rand.Seed(time.Now().Unix()) } func stollHandleMessage(m *irc.Message) { @@ -531,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]" diff --git a/util/util.go b/util/util.go index 90c5357..e39e041 100644 --- a/util/util.go +++ b/util/util.go @@ -4,10 +4,8 @@ package util import ( "bytes" - "math/rand" "strconv" "strings" - "time" ) func ToInt(v interface{}) int { @@ -49,11 +47,6 @@ 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) From cb87e33ead404b48e5f7ca5b9272efaf74ccb466 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Fri, 1 Apr 2016 19:21:49 +0200 Subject: [PATCH 05/13] Lots of changes in quiz module. --- modules/quiz.go | 80 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/modules/quiz.go b/modules/quiz.go index 9d2c6b7..955ecac 100644 --- a/modules/quiz.go +++ b/modules/quiz.go @@ -18,19 +18,20 @@ import ( ) type quizQuestion struct { - category, question, answer, regexp string + category, question, answer, regexp, level string } var ( - quizCtrlCh = make(chan string, 1024) - quizAnswerCh = make(chan *irc.Message, 1024) - quizQuestions []quizQuestion + quizCtrlCh = make(chan string, 1024) + quizAnswerCh = make(chan *irc.Message, 1024) + quizQuestions []quizQuestion + quizQuestionValues = map[string]int{"extreme": 5, "hard": 4, "medium": 3, "easy": 2, "baby": 1} ) func init() { MsgFuncs["quiz"] = quizHandleMessage RunFuncs["quiz"] = quiz - quizQuestions = quizLoadQuestions("./modules/quiz/questions.txt") + quizQuestions = quizLoadQuestions("questions.txt") rand.Seed(time.Now().Unix()) } @@ -40,7 +41,7 @@ func quizHandleMessage(m *irc.Message) { return } switch tok[0] { - case "!quizstart": + case "!quiz", "!quizstart": quizCtrlCh <- "start" break case "!quizstop": @@ -53,6 +54,7 @@ func quizHandleMessage(m *irc.Message) { } 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) @@ -68,32 +70,55 @@ func quiz() { } func quizRun() { + ranklist := make(map[string]int) SayCh <- fmt.Sprintf("%s\nQuiz gestartet.", "*") for { - if !quizAskQuestion() { + 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 quizAskQuestion() bool { +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\":", "*", q.category) + SayCh <- fmt.Sprintf("%s\nEine Frage aus der Kategorie \"%s\" (%s):", "*", q.category, q.level) SayCh <- fmt.Sprintf("%s\n>>> %s <<<", "*", q.question) - m, solved, cont := quizWaitForAnswer(q) - if solved { - mm := m - m = mm - } else { + 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 cont + return solved, cont, solver, gain } -func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { +func quizWaitForAnswer(q quizQuestion) (bool, bool, string, int) { i := 0 haveAnswer := false timer := time.Now().Unix() @@ -108,19 +133,21 @@ func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { re, err := regexp.Compile(q.regexp) if err != nil { xlog.Error(err.Error()) - return nil, false, false + 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) - SayCh <- fmt.Sprintf("%s\n%s hat die Frage korrekt beantwortet und erhält dafür %d Punkte.", "*", solver, points) - return m, true, true + 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 nil, false, false + return false, false, "", 0 } break case <-time.After(15 * time.Second): @@ -128,10 +155,10 @@ func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { if i > 3 { if haveAnswer { SayCh <- fmt.Sprintf("%s\nNiemand konnte die Frage korrekt beantworten.", "*") - return nil, false, true + return false, true, "", 0 } else { SayCh <- fmt.Sprintf("%s\nNiemand hat auf die Frage geantwortet.", "*") - return nil, false, false + return false, false, "", 0 } } else { quizGiveHint(q, i) @@ -172,7 +199,7 @@ func quizLoadQuestions(path string) []quizQuestion { defer file.Close() questions := make([]quizQuestion, 0) - q := quizQuestion{"", "", "", ""} + q := quizQuestion{"", "", "", "", ""} scanner := bufio.NewScanner(file) for scanner.Scan() { @@ -180,7 +207,7 @@ func quizLoadQuestions(path string) []quizQuestion { if len(line) == 0 || line[0] == '#' || line[0] == '\n' { if q.category != "" { questions = append(questions, q) - q = quizQuestion{"", "", "", ""} + q = quizQuestion{"", "", "", "", "medium"} } } else { tok := strings.Split(line, ":: ") @@ -192,7 +219,7 @@ func quizLoadQuestions(path string) []quizQuestion { q.question = tok[1] break case "Answer": - q.answer = strings.Replace(tok[1], "#", "", -1) + 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 { @@ -205,6 +232,9 @@ func quizLoadQuestions(path string) []quizQuestion { case "Regexp": q.regexp = util.ReplaceUmlauts(strings.ToLower(tok[1])) break + case "Level": + q.level = tok[1] + break } } } From 5af0c2f07aeabdde4d03c17b9a84b222798fd576 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Fri, 1 Apr 2016 19:26:57 +0200 Subject: [PATCH 06/13] modules/quiz: medium -> normal --- modules/quiz.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/quiz.go b/modules/quiz.go index 955ecac..3c37e70 100644 --- a/modules/quiz.go +++ b/modules/quiz.go @@ -25,7 +25,7 @@ var ( quizCtrlCh = make(chan string, 1024) quizAnswerCh = make(chan *irc.Message, 1024) quizQuestions []quizQuestion - quizQuestionValues = map[string]int{"extreme": 5, "hard": 4, "medium": 3, "easy": 2, "baby": 1} + quizQuestionValues = map[string]int{"extreme": 5, "hard": 4, "normal": 3, "easy": 2, "baby": 1} ) func init() { @@ -207,7 +207,7 @@ func quizLoadQuestions(path string) []quizQuestion { if len(line) == 0 || line[0] == '#' || line[0] == '\n' { if q.category != "" { questions = append(questions, q) - q = quizQuestion{"", "", "", "", "medium"} + q = quizQuestion{"", "", "", "", "normal"} } } else { tok := strings.Split(line, ":: ") From 600954764af9c19bab2a9de96a36c0d7f36133c5 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Thu, 16 Jun 2016 19:50:10 +0200 Subject: [PATCH 07/13] quiz: load questions.txt on quiz start --- modules/quiz.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/quiz.go b/modules/quiz.go index 3c37e70..a49d6cc 100644 --- a/modules/quiz.go +++ b/modules/quiz.go @@ -31,7 +31,6 @@ var ( func init() { MsgFuncs["quiz"] = quizHandleMessage RunFuncs["quiz"] = quiz - quizQuestions = quizLoadQuestions("questions.txt") rand.Seed(time.Now().Unix()) } @@ -70,6 +69,7 @@ func quiz() { } func quizRun() { + quizQuestions = quizLoadQuestions("questions.txt") ranklist := make(map[string]int) SayCh <- fmt.Sprintf("%s\nQuiz gestartet.", "*") for { From 13ba99025dd18688b4c39b60390858d4f5889391 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Tue, 12 Jul 2016 14:00:03 +0200 Subject: [PATCH 08/13] Added -autocmd --- main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.go b/main.go index d371ed1..6d839a2 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,7 @@ var ( 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() { @@ -84,6 +85,10 @@ func main() { }() go Ping(bot) + if *autocmd != "" { + println(*autocmd) + bot.Sender.Send(&irc.Message{Command: *autocmd}) + } RegisterHandlers(bot) bot.HandleLoop() xlog.Info("Exiting") From cbe213af656641e77c3f856f20acff2983202dfc Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Tue, 1 Nov 2016 18:34:05 +0100 Subject: [PATCH 09/13] Markov module --- main.go | 1 + modules/markov.go | 272 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 modules/markov.go diff --git a/main.go b/main.go index d371ed1..a6cd38f 100644 --- a/main.go +++ b/main.go @@ -59,6 +59,7 @@ func main() { //TODO: implement more robust list parsing modules.Init(sayCh, *mods, *params) + modules.ModParams["_nick"] = *name go func() { for { diff --git a/modules/markov.go b/modules/markov.go new file mode 100644 index 0000000..b56d8d6 --- /dev/null +++ b/modules/markov.go @@ -0,0 +1,272 @@ +// 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) + + markovChain.Write(text) + + answerLen, _ := strconv.Atoi(ModParams["markov-answer-len"]) + respChance, _ := strconv.Atoi(ModParams["markov-response-chance"]) + if rand.Intn(100) <= respChance || strings.HasPrefix(text, ModParams["_nick"]) { + responseText := markovChain.Generate(answerLen, text) + if responseText != "" { + go func() { + time.Sleep(time.Duration(rand.Intn(8)+2) * time.Second) + SayCh <- "*\n" + responseText + }() + } + } +} + +func markovRun() { + prefixLen, _ := strconv.Atoi(ModParams["markov-prefix-len"]) + markovChain = markovNewChain(prefixLen) + //if *importFile != "" { + // StartImport(*importFile) + 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) + } + } + } else { + err := markovChain.Load(ModParams["markov-state-file"]) + if err != nil { + xlog.Error(err.Error()) + } + } + 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 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.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) + 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() + 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) + c.mu.Lock() + defer c.mu.Unlock() + p := make(MarkovPrefix, c.prefixLen) + p = strings.Split(in, " ") + for { + if len(p) == c.prefixLen { + break + } + if len(p) < c.prefixLen { + p = append(p, "") + } + if len(p) > c.prefixLen { + if rand.Intn(2) == 0 { + p = p[1:] + } else { + p = p[0 : len(p)-1] + } + } + } + prefix := p.String() + 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) + p.Shift(next) + } + if len(words) == 0 { + return "" + } else { + 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 +} From 450abd2cedba37421f62d7931cac70dd42e54909 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Thu, 3 Nov 2016 18:04:40 +0100 Subject: [PATCH 10/13] Several changes in answer generation in markov module --- modules/markov.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/modules/markov.go b/modules/markov.go index b56d8d6..7dbc983 100644 --- a/modules/markov.go +++ b/modules/markov.go @@ -44,7 +44,7 @@ func markovHandleMessage(m *irc.Message) { answerLen, _ := strconv.Atoi(ModParams["markov-answer-len"]) respChance, _ := strconv.Atoi(ModParams["markov-response-chance"]) - if rand.Intn(100) <= respChance || strings.HasPrefix(text, ModParams["_nick"]) { + if rand.Intn(100) <= respChance || strings.Index(text, ModParams["_nick"]) != -1 { responseText := markovChain.Generate(answerLen, text) if responseText != "" { go func() { @@ -161,6 +161,10 @@ func markovNewChain(prefixLen int) *MarkovChain { // 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]+" ", "", 0) + } sr := strings.NewReader(in) p := make(MarkovPrefix, c.prefixLen) for { @@ -180,24 +184,20 @@ func (c *MarkovChain) Write(in string) (int, error) { // 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]+" ", "", 0) + } c.mu.Lock() defer c.mu.Unlock() p := make(MarkovPrefix, c.prefixLen) p = strings.Split(in, " ") - for { - if len(p) == c.prefixLen { - break - } - if len(p) < c.prefixLen { - p = append(p, "") - } - if len(p) > c.prefixLen { - if rand.Intn(2) == 0 { - p = p[1:] - } else { - p = p[0 : len(p)-1] - } - } + if len(p) < c.prefixLen { + p = append(p, "") + } + if len(p) > c.prefixLen { + i := rand.Intn(len(p) - 1) + p = p[i : i+c.prefixLen] } prefix := p.String() var words []string @@ -208,6 +208,9 @@ func (c *MarkovChain) Generate(n int, in string) string { } next := choices[rand.Intn(len(choices))] words = append(words, next) + if strings.HasSuffix(next, ".") || strings.HasSuffix(next, "!") || strings.HasSuffix(next, "?") { + break + } p.Shift(next) } if len(words) == 0 { From 0f080a29463a690b31d510da0889c02c1249b74d Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Thu, 3 Nov 2016 18:08:01 +0100 Subject: [PATCH 11/13] markov.go: Convert text input to lowercase before parsing --- modules/markov.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/markov.go b/modules/markov.go index 7dbc983..509b471 100644 --- a/modules/markov.go +++ b/modules/markov.go @@ -44,7 +44,7 @@ func markovHandleMessage(m *irc.Message) { answerLen, _ := strconv.Atoi(ModParams["markov-answer-len"]) respChance, _ := strconv.Atoi(ModParams["markov-response-chance"]) - if rand.Intn(100) <= respChance || strings.Index(text, ModParams["_nick"]) != -1 { + if rand.Intn(100) <= respChance || strings.Index(text, strings.ToLower(ModParams["_nick"])) != -1 { responseText := markovChain.Generate(answerLen, text) if responseText != "" { go func() { @@ -124,7 +124,7 @@ func markovParseText(text string) string { text = strings.Replace(text, ">", ">", -1) text = strings.Replace(text, "&", "&", -1) - return text + return strings.ToLower(text) } // Prefix is a Markov chain prefix of one or more words. From 5f9238a433faf8a096ee32aa9a59f9b344c3d674 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Sat, 5 Nov 2016 10:40:20 +0100 Subject: [PATCH 12/13] markov.go: learning after answering (prevents repition of input) --- main.go | 2 +- modules/markov.go | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 96c6dbd..666c480 100644 --- a/main.go +++ b/main.go @@ -45,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} diff --git a/modules/markov.go b/modules/markov.go index 509b471..5359f59 100644 --- a/modules/markov.go +++ b/modules/markov.go @@ -37,11 +37,8 @@ func markovHandleMessage(m *irc.Message) { if text == "" { return } - text = markovParseText(text) - markovChain.Write(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 { @@ -53,6 +50,8 @@ func markovHandleMessage(m *irc.Message) { }() } } + + markovChain.Write(text) } func markovRun() { @@ -132,7 +131,7 @@ type MarkovPrefix []string // String returns the Prefix as a string (for use as a map key). func (p MarkovPrefix) String() string { - return strings.Join(p, " ") + return strings.Trim(strings.Join(p, " "), " ") } // Shift removes the first word from the Prefix and appends the given word. @@ -163,7 +162,7 @@ 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]+" ", "", 0) + in = strings.Replace(in, tok[0]+" ", "", 1) } sr := strings.NewReader(in) p := make(MarkovPrefix, c.prefixLen) @@ -176,6 +175,7 @@ func (c *MarkovChain) Write(in string) (int, error) { 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 @@ -186,20 +186,18 @@ 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]+" ", "", 0) + 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 { - p = append(p, "") - } 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()] @@ -213,9 +211,12 @@ func (c *MarkovChain) Generate(n int, in string) string { } p.Shift(next) } + prefix = strings.Trim(prefix, " ") if len(words) == 0 { - return "" + xlog.Debug("No answer found") + return prefix + " ... pfrrrz" } else { + xlog.Debug("Found words: [%s]", strings.Join(words, " ")) return prefix + " " + strings.Join(words, " ") } } From abdab70ce1c07b36bc67f23f8c761b1bf60fc45b Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Sat, 5 Nov 2016 10:56:40 +0100 Subject: [PATCH 13/13] markov.go: Import text after loading state file --- modules/markov.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/modules/markov.go b/modules/markov.go index 5359f59..c930300 100644 --- a/modules/markov.go +++ b/modules/markov.go @@ -57,8 +57,10 @@ func markovHandleMessage(m *irc.Message) { func markovRun() { prefixLen, _ := strconv.Atoi(ModParams["markov-prefix-len"]) markovChain = markovNewChain(prefixLen) - //if *importFile != "" { - // StartImport(*importFile) + 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) @@ -70,11 +72,6 @@ func markovRun() { markovChain.Write(text) } } - } else { - err := markovChain.Load(ModParams["markov-state-file"]) - if err != nil { - xlog.Error(err.Error()) - } } go func() { for {