84 lines
1.6 KiB
Go
84 lines
1.6 KiB
Go
|
package tins2021
|
||
|
|
||
|
import (
|
||
|
"crypto/sha256"
|
||
|
"encoding/base64"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
const scoreFileName = "score.json"
|
||
|
|
||
|
type Highscores []Score
|
||
|
|
||
|
func (h Highscores) AddScore(score, difficulty int) (Highscores, bool) {
|
||
|
highscores := len(h)
|
||
|
var rank = highscores
|
||
|
for ; rank > 0; rank-- {
|
||
|
if score <= h[rank-1].Score {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
highscore := NewScore(score, difficulty)
|
||
|
if rank == highscores && highscores < 10 {
|
||
|
return append(h, highscore), true
|
||
|
}
|
||
|
if rank < 10 {
|
||
|
return append(h[:rank], append([]Score{highscore}, h[rank:highscores-1]...)...), true
|
||
|
}
|
||
|
return h, false
|
||
|
}
|
||
|
|
||
|
type Score struct {
|
||
|
Score int
|
||
|
Difficulty int
|
||
|
Hash string
|
||
|
}
|
||
|
|
||
|
func NewScore(score, difficulty int) Score {
|
||
|
s := Score{Score: score, Difficulty: difficulty}
|
||
|
s.Hash = s.hash()
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func (s *Score) hash() string {
|
||
|
hashText := fmt.Sprintf("tins2021_qbitter, %d, %d", s.Score, s.Difficulty)
|
||
|
hash := sha256.Sum256([]byte(hashText))
|
||
|
return base64.StdEncoding.EncodeToString(hash[:])
|
||
|
}
|
||
|
|
||
|
func (s *Score) Validate() bool {
|
||
|
hash := s.hash()
|
||
|
if hash == s.Hash {
|
||
|
return true
|
||
|
}
|
||
|
s.Score = 0
|
||
|
s.Difficulty = 0
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
type ScoreState struct {
|
||
|
Current Score
|
||
|
Highscores Highscores
|
||
|
}
|
||
|
|
||
|
func LoadScores() (ScoreState, error) {
|
||
|
var state ScoreState
|
||
|
if err := LoadUserFileJSON(scoreFileName, &state); err != nil {
|
||
|
return ScoreState{}, err
|
||
|
}
|
||
|
state.Current.Validate()
|
||
|
for i := 0; i < len(state.Highscores); {
|
||
|
if !state.Highscores[i].Validate() {
|
||
|
state.Highscores = append(state.Highscores[:i], state.Highscores[i+1:]...)
|
||
|
} else {
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return state, nil
|
||
|
}
|
||
|
|
||
|
func SaveScores(s *ScoreState) error {
|
||
|
return SaveUserFileJSON(scoreFileName, s)
|
||
|
}
|