generated from VLADIMIR/template
95 lines
3.8 KiB
Go
95 lines
3.8 KiB
Go
package answer_service
|
|
|
|
import (
|
|
"evening_detective_server/internal/modules/game_model"
|
|
"sort"
|
|
|
|
"evening_detective_server/internal/modules/storytelling"
|
|
)
|
|
|
|
// TeamResult — строка итоговой таблицы: команда, баллы по вопросам (в порядке
|
|
// сценария), сумма баллов и место.
|
|
type TeamResult struct {
|
|
Team *game_model.Team
|
|
Answers []AnswerScore
|
|
// TotalScore — сумма баллов по всем вопросам сценария; неоценённые
|
|
// вопросы считаются как 0.
|
|
TotalScore int
|
|
// Place — место в итоговой таблице. Команды с одинаковой суммой баллов
|
|
// и одинаковым числом ходов занимают одно место (следующее место
|
|
// пропускается); проставляется функцией rankTeams.
|
|
Place int
|
|
}
|
|
|
|
// GameResults — итоговая таблица игры: вопросы сценария (шапка таблицы) и
|
|
// результаты команд, отсортированные по сумме баллов.
|
|
type GameResults struct {
|
|
Questions []*storytelling.Question
|
|
Teams []TeamResult
|
|
}
|
|
|
|
// buildTeamResults собирает строки итоговой таблицы по командам: баллы в
|
|
// порядке вопросов сценария (неотвеченный/неоценённый вопрос — с пустым
|
|
// текстом и Score=nil), сумма баллов (nil считается как 0). Команды в
|
|
// результате — в порядке переданного списка; сортировку и места делает
|
|
// rankTeams.
|
|
func buildTeamResults(
|
|
questions []*storytelling.Question,
|
|
teams []*game_model.Team,
|
|
answerByTeamAndCode map[int]map[string]AnswerScore,
|
|
) []TeamResult {
|
|
res := make([]TeamResult, 0, len(teams))
|
|
for _, team := range teams {
|
|
byCode := answerByTeamAndCode[team.ID]
|
|
answers := make([]AnswerScore, 0, len(questions))
|
|
total := 0
|
|
for _, question := range questions {
|
|
answer, ok := byCode[question.Code]
|
|
if !ok {
|
|
answers = append(answers, AnswerScore{QuestionCode: question.Code})
|
|
continue
|
|
}
|
|
answers = append(answers, answer)
|
|
if answer.Score != nil {
|
|
total += *answer.Score
|
|
}
|
|
}
|
|
res = append(res, TeamResult{
|
|
Team: team,
|
|
Answers: answers,
|
|
TotalScore: total,
|
|
})
|
|
}
|
|
return res
|
|
}
|
|
|
|
// rankTeams сортирует строки итоговой таблицы по сумме баллов (убывание);
|
|
// при равенстве суммы выше команда с меньшим числом ходов. Команды с
|
|
// одинаковой суммой баллов И одинаковым числом ходов занимают одно место
|
|
// (следующее место пропускается — схема 1,2,2,4 по ключу (сумма, ходы)).
|
|
// id команды влияет только на порядок показа внутри группы (меньший id
|
|
// первым), не на место. Входной срез не изменяется.
|
|
func rankTeams(rows []TeamResult) []TeamResult {
|
|
sorted := make([]TeamResult, len(rows))
|
|
copy(sorted, rows)
|
|
sort.SliceStable(sorted, func(i, j int) bool {
|
|
a, b := sorted[i], sorted[j]
|
|
if a.TotalScore != b.TotalScore {
|
|
return a.TotalScore > b.TotalScore
|
|
}
|
|
if a.Team.ActionsCount != b.Team.ActionsCount {
|
|
return a.Team.ActionsCount < b.Team.ActionsCount
|
|
}
|
|
return a.Team.ID < b.Team.ID
|
|
})
|
|
place := 0
|
|
for i := range sorted {
|
|
row := sorted[i]
|
|
if i == 0 || row.TotalScore != sorted[i-1].TotalScore || row.Team.ActionsCount != sorted[i-1].Team.ActionsCount {
|
|
place = i + 1
|
|
}
|
|
sorted[i].Place = place
|
|
}
|
|
return sorted
|
|
}
|