@ -0,0 +1,11 @@ | |||
kind: pipeline | |||
name: default | |||
steps: | |||
- name: test | |||
image: golang:alpine | |||
commands: | |||
- CGO_ENABLED=0 go test -v ./... | |||
volumes: | |||
- name: gopath | |||
path: /go |
@ -0,0 +1,9 @@ | |||
# Would love to use scratch but we need those CA certs | |||
FROM golang:alpine | |||
ENV GOPROXY https://modules.fromouter.space | |||
ENV GO111MODULE=on | |||
WORKDIR /app | |||
ENTRYPOINT go run . |
@ -0,0 +1 @@ | |||
# Bot for scrabble sylladex |
@ -0,0 +1,5 @@ | |||
module git.fromouter.space/Hamcha/scrabblego | |||
go 1.12 | |||
require github.com/bwmarrin/discordgo v0.19.0 |
@ -0,0 +1,6 @@ | |||
github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5awQiY= | |||
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= | |||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | |||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | |||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= | |||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
@ -0,0 +1,100 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>Scrabble calculator</title> | |||
<meta charset="UTF-8" /> | |||
<link | |||
rel="stylesheet" | |||
href="https://unpkg.com/spectre.css/dist/spectre.min.css" | |||
/> | |||
<style> | |||
body { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
main { | |||
padding: 3em; | |||
} | |||
.number { | |||
width: 3em; | |||
} | |||
p { | |||
padding: 1em 0; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<main id="app"> | |||
<input type="text" placeholder="Oggetto" v-model="text" /> | |||
<input | |||
type="text" | |||
placeholder="Quanti slot hai" | |||
class="number" | |||
v-model="maxslot" | |||
/> | |||
<p> | |||
Risultato: <b>{{ score }}</b> % {{ maxslot }} => <b>{{ slot }}</b> | |||
</p> | |||
</main> | |||
<script type="module"> | |||
import Vue from "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.esm.browser.js"; | |||
let points = { | |||
A: 1, | |||
O: 1, | |||
I: 1, | |||
E: 1, | |||
C: 2, | |||
R: 2, | |||
S: 2, | |||
T: 2, | |||
L: 3, | |||
M: 3, | |||
N: 3, | |||
U: 3, | |||
W: 4, | |||
Y: 4, | |||
B: 5, | |||
D: 5, | |||
F: 5, | |||
P: 5, | |||
V: 5, | |||
K: 5, | |||
G: 8, | |||
H: 8, | |||
Z: 8, | |||
J: 8, | |||
X: 8, | |||
Q: 10 | |||
}; | |||
const app = new Vue({ | |||
el: "#app", | |||
data: { | |||
text: "", | |||
maxslot: 10 | |||
}, | |||
computed: { | |||
score: function() { | |||
const letters = this.text | |||
.toUpperCase() | |||
.trim() | |||
.split(""); | |||
return letters.reduce((total, letter) => { | |||
if (letter in points) { | |||
total += points[letter]; | |||
} | |||
return total; | |||
}, 0); | |||
}, | |||
slot: function() { | |||
return (this.score % this.maxslot) + 1; | |||
} | |||
} | |||
}); | |||
</script> | |||
</body> | |||
</html> |
@ -0,0 +1,118 @@ | |||
package main | |||
import ( | |||
"fmt" | |||
"log" | |||
"os" | |||
"os/signal" | |||
"strconv" | |||
"strings" | |||
"syscall" | |||
"github.com/bwmarrin/discordgo" | |||
) | |||
const TriggerWord = "!syl-" | |||
var points = map[rune]int{ | |||
'A': 1, 'O': 1, 'I': 1, 'E': 1, | |||
'C': 2, 'R': 2, 'S': 2, 'T': 2, | |||
'L': 3, 'M': 3, 'N': 3, 'U': 3, | |||
'W': 4, 'Y': 4, | |||
'B': 5, 'D': 5, 'F': 5, 'P': 5, 'V': 5, 'K': 5, | |||
'G': 8, 'H': 8, 'Z': 8, 'J': 8, 'X': 8, | |||
'Q': 10, | |||
} | |||
func scrabbleScore(letters string) int { | |||
letters = strings.ToUpper(letters) | |||
totalScore := 0 | |||
for _, glyph := range letters { | |||
letterScore, ok := points[glyph] | |||
if ok { | |||
totalScore += letterScore | |||
} | |||
} | |||
return totalScore | |||
} | |||
func scrabbleToStr(letters string) string { | |||
letters = strings.ToUpper(letters) | |||
arr := []string{} | |||
for _, glyph := range letters { | |||
letterScore, ok := points[glyph] | |||
if ok { | |||
arr = append(arr, fmt.Sprintf("%s=%d", string(glyph), letterScore)) | |||
} | |||
} | |||
return strings.Join(arr, " + ") | |||
} | |||
func main() { | |||
token := os.Getenv("TOKEN") | |||
if token == "" { | |||
panic("TOKEN env var is missing") | |||
} | |||
// Create a new Discordgo session | |||
dg, err := discordgo.New(token) | |||
checkErr(err) | |||
dg.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { | |||
// Ignore bot commands | |||
if m.Author.Bot { | |||
return | |||
} | |||
if strings.HasPrefix(m.Content, TriggerWord) { | |||
msg := m.Content[len(TriggerWord):] | |||
parts := strings.SplitN(msg, " ", 2) | |||
if len(parts) < 2 { | |||
return | |||
} | |||
maxsize, err := strconv.Atoi(parts[0]) | |||
if err != nil { | |||
return | |||
} | |||
score := scrabbleScore(parts[1]) | |||
slot := score % maxsize | |||
_, err = s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{ | |||
Author: &discordgo.MessageEmbedAuthor{ | |||
Name: "Scrabble Sylladex", | |||
}, | |||
Title: fmt.Sprintf("Risultato: %d", slot+1), | |||
Description: fmt.Sprintf("\"%s\" va nello slot %d (di %d)", parts[1], slot+1, maxsize), | |||
Fields: []*discordgo.MessageEmbedField{ | |||
{ | |||
Name: "Valore parola", | |||
Value: fmt.Sprintf("%s = %d", scrabbleToStr(parts[1]), score), | |||
}, { | |||
Name: "Posizionamento", | |||
Value: fmt.Sprintf("%d mod %d = %d → %d", score, maxsize, slot, slot+1), | |||
}, | |||
}, | |||
}) | |||
if err != nil { | |||
log.Printf("Error: %s\n", err.Error()) | |||
} | |||
} | |||
}) | |||
dg.AddHandler(func(s *discordgo.Session, m *discordgo.Ready) { | |||
log.Print("ready") | |||
}) | |||
checkErr(dg.Open()) | |||
defer dg.Close() | |||
sc := make(chan os.Signal, 1) | |||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGSEGV, syscall.SIGHUP) | |||
<-sc | |||
} | |||
func checkErr(err error) { | |||
if err != nil { | |||
log.Fatalf("FATAL ERROR: %s", err.Error()) | |||
os.Exit(1) | |||
} | |||
} |
@ -0,0 +1,18 @@ | |||
package main | |||
import "testing" | |||
func TestScrabbleScore(t *testing.T) { | |||
testscores := map[string]int{ | |||
"spada del potere": 35, | |||
"puppami la fava": 39, | |||
"yogurt alla papaja": 49, | |||
"jack": 16, | |||
"mela": 8, | |||
} | |||
for testword, testscore := range testscores { | |||
if score := scrabbleScore(testword); score != testscore { | |||
t.Errorf("Expected word \"%s\" to have score %d but got %d", testword, testscore, score) | |||
} | |||
} | |||
} |