// 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 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.txt") rand.Seed(time.Now().Unix()) } 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() { SayCh <- fmt.Sprintf("%s\nQuiz gestartet.", "*") for { if !quizAskQuestion() { SayCh <- fmt.Sprintf("%s\nQuiz beendet.", "*") return } } } func quizAskQuestion() bool { 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 { mm := m m = mm } else { 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 } func quizWaitForAnswer(q quizQuestion) (*irc.Message, bool, bool) { 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 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 case s := <-quizCtrlCh: if s == "stop" { return nil, false, false } break 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 { SayCh <- fmt.Sprintf("%s\nNiemand hat auf die Frage geantwortet.", "*") return nil, false, false } } 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{"", "", "", ""} } } 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) 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 } } } if err := scanner.Err(); err != nil { xlog.Fatal(err.Error()) } return questions }