Compare commits

...

3 Commits

Author SHA1 Message Date
Nico 4afce3410b potential fix for resetting while game is running 2021-04-10 19:20:21 +01:00
Nico 999ec57197 make slower 2021-03-08 16:30:17 +00:00
Nico d0137450b2 score sorting, switch to release timings 2021-03-07 17:30:15 +00:00
1 changed files with 62 additions and 13 deletions

75
main.go
View File

@ -16,6 +16,7 @@ package main
* sync to make things concurrency safe
* time to sleep for some time before reducing the counter
* rand to randomise the timer ticks
* sort to sort things
*/
import (
"bufio"
@ -26,11 +27,12 @@ import (
"sync"
"time"
"math/rand"
"sort"
)
/*
as we'll be referencing them a lot later, we should create some constants to store things like the network address and our IRC nick/user name. This is set up for connecting to tilde.town from localhost.
we also set the minimum and maximum timeout lengths (in seconds) for the counter to tick down, and the value to reset to.
we also set the minimum and maximum timeout lengths (in minutes) for the counter to tick down, and the value to reset to.
*/
const (
nick string = "thebuttonbot"
@ -38,8 +40,8 @@ const (
realname string = "thebuttonbot"
channel string = "#thebutton"
server string = "localhost:6667"
maxTime int = 10
minTime int = 5
maxTime int = 20
minTime int = 15
resetCount int = 10
)
@ -48,7 +50,7 @@ const (
*/
var (
counter int = resetCount
scores map[string]int
scores map[string]int = make(map[string]int)
countMutex sync.Mutex
connMutex sync.Mutex
)
@ -64,6 +66,22 @@ type IRCMessage struct {
Command string
Parameters []string
}
/*
types Pair and PairList (and the associated functions) only exist for the sake of sorting the high score list.
the high scores are converted from a map into a PairList, and then sorted.
PairList implements the interface for sort.Sort()
*/
type Pair struct {
Key string
Value int
}
type PairList []Pair
func (p PairList) Len() int { return len(p) }
func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }
/*
function parseMessage parses an IRC message, and returns an IRCMessage.
@ -107,6 +125,31 @@ func parseMessage(s string) IRCMessage {
}
/*
function scoreString formats the score list and returns a string.
*/
func scoreString() string {
// Make an empty starting string
s := ""
// Initialise a pairlist for names and fill it
names := make(PairList, len(scores))
i := 0
for k, v := range scores {
names[i] = Pair{Key: k, Value: v}
i++
}
// sort and format for sending
sort.Reverse(names)
for i, v := range names {
// append all the scores to it
s += fmt.Sprintf("%s: %d", v.Key, v.Value)
if i != len(names)-1 {
s += ","
}
}
return s
}
/*
function sendMessage sends a message using connection conn on IRC channel c with content s.
It first locks the connection mutex, and unlocks it afterwards, to make the function concurrency-safe.
@ -144,7 +187,7 @@ func countdown(conn *net.Conn, reset chan int) {
locked := false
for {
duration := rand.Intn(maxTime-minTime) + minTime
timer := time.NewTimer(time.Duration(duration) * time.Second) // TODO randomise a bit, longer times
timer := time.NewTimer(time.Duration(duration) * time.Minute)
select {
case <-timer.C: // on a timer timeout
if !locked {
@ -152,7 +195,8 @@ func countdown(conn *net.Conn, reset chan int) {
setCounter(c - 1)
if c-1 == 0 {
locked = true
sendMessage(conn, channel, "Ker-Chunk! The timer ticked down to the final position. You're all dead.")
sendMessage(conn, channel, "Ker-Chunk! The timer ticked down to the final position. You're all dead.")
sendMessage(conn, channel, scoreString())
} else {
sendMessage(conn, channel, fmt.Sprintf("*tick, tick, tick* The timer ticks down. It now reads %d", c-1))
}
@ -234,28 +278,33 @@ func main() {
*/
if msg.Command == "PRIVMSG" {
msgChannel := msg.Parameters[0]
// msgSender := msg.SourceNick
msgSender := msg.SourceNick
msgContent := strings.TrimPrefix(msg.Parameters[1], ":")
fmt.Println(msgContent)
if msgChannel == channel {
if msgContent == ",ping" {
sendMessage(&conn, channel, "Pong!\r\n")
} else if msgContent == ",scores" {
// TODO implement scoring
sendMessage(&conn, channel, "Not implemented yet")
sendMessage(&conn, channel, scoreString())
} else if msgContent == ",press" {
// TODO score these
c := getCounter()
if c != 0 {
reset <- 0
sendMessage(&conn, channel, fmt.Sprintf("You press the button. The countdown resets to %d", resetCount))
points := (resetCount - c)*(resetCount - c)
scores[msgSender] += points
sendMessage(&conn, channel, fmt.Sprintf("%s presses the button for %d points. The countdown resets to %d", msgSender, points, resetCount))
} else {
sendMessage(&conn, channel, "You're all dead. Dead people can't press buttons.")
}
} else if msgContent == ",reset" {
// TODO maybe check some kind of auth on doing this
reset <- 0
sendMessage(&conn, channel, "Timer reset!")
if getCounter() == 0 {
reset <- 0
scores = map[string]int{} // empty the scoreboard
sendMessage(&conn, channel, "Timer reset!")
} else {
sendMessage(&conn, channel, "You can't reset the timer while the game is running!")
}
} else if msgContent == ",count" {
sendMessage(&conn, channel, fmt.Sprintf("You look up at the ominous countdown. It reads %d", getCounter()))
} else if msgContent == ",help" {