help system

This commit is contained in:
2025-09-14 20:40:39 +02:00
parent 488084f1bb
commit 7ba33e248f
4 changed files with 137 additions and 10 deletions

View File

@@ -14,7 +14,8 @@ INSERT INTO TEAMS (id, name, city, difficulty_level, password, last_cipher, pena
INSERT INTO POSITIONS (id, gps, clue) VALUES INSERT INTO POSITIONS (id, gps, clue) VALUES
(1, '50.087451,14.420671', 'Najdi sochu uprostřed náměstí.'), (1, '50.087451,14.420671', 'Najdi sochu uprostřed náměstí.'),
(2, '49.195061,16.606836', 'Podívej se pod lavičku.'), (2, '49.195061,16.606836', 'Podívej se pod lavičku.'),
(3, '49.820923,18.262524', 'Hledej u velkého stromu.'); (3, '49.820923,18.262524', 'Hledej u velkého stromu.'),
(4, '50.075538,14.437800', 'Kousek od fontány.');
-- Vložení QR kódů -- Vložení QR kódů
INSERT INTO QR_CODES (id, position_id, uid) VALUES INSERT INTO QR_CODES (id, position_id, uid) VALUES
@@ -32,7 +33,8 @@ INSERT INTO CIPHERS (id, assignment, solution, clue) VALUES
INSERT INTO TASKS (id, cipher_id, position_id, difficulty_level, order_num, end_clue) VALUES INSERT INTO TASKS (id, cipher_id, position_id, difficulty_level, order_num, end_clue) VALUES
(1, 1, 1, 1, 1, 'Pokračuj k dalšímu stanovišti.'), (1, 1, 1, 1, 1, 'Pokračuj k dalšímu stanovišti.'),
(2, 2, 2, 2, 2, 'Hledej QR kód u stromu.'), (2, 2, 2, 2, 2, 'Hledej QR kód u stromu.'),
(3, 3, 3, 3, 3, 'Gratulujeme, jsi v cíli!'); (3, 3, 3, 3, 3, 'Gratulujeme, jsi v cíli!'),
(4, 1, 4, 1, 2, 'To je vše, děkujeme za účast!');
-- Vložení admina: heslo -- Vložení admina: heslo
INSERT INTO ADMINS (id, username, password) VALUES INSERT INTO ADMINS (id, username, password) VALUES

134
klice.go
View File

@@ -117,13 +117,13 @@ func isLoggedIn(w http.ResponseWriter, r *http.Request) (bool, int) {
func teamInfoHandler(w http.ResponseWriter, r *http.Request) { func teamInfoHandler(w http.ResponseWriter, r *http.Request) {
if loggedIn, teamID := isLoggedIn(w, r); loggedIn { if loggedIn, teamID := isLoggedIn(w, r); loggedIn {
var teamName, city string var teamName, city, last_cipher, penalty string
err := db.QueryRow("SELECT name, city FROM teams WHERE id = ?", teamID).Scan(&teamName, &city) err := db.QueryRow("SELECT name, city, last_cipher, penalty FROM teams WHERE id = ?", teamID).Scan(&teamName, &city, &last_cipher, &penalty)
if err != nil { if err != nil {
http.Error(w, "Could not retrieve team information", http.StatusInternalServerError) http.Error(w, "Could not retrieve team information", http.StatusInternalServerError)
return return
} }
fmt.Fprintf(w, "Team Name: %s, City: %s", teamName, city) fmt.Fprintf(w, "Team Name: %s, City: %s, Last Cipher: %s, Penalty: %s", teamName, city, last_cipher, penalty)
} }
} }
@@ -143,9 +143,54 @@ func qrHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if loggedIn, teamID := isLoggedIn(w, r); loggedIn { if loggedIn, teamID := isLoggedIn(w, r); loggedIn {
var cipherID int
var assignment string var assignment string
err = db.QueryRow("select id, assignment from CIPHERS where id = (select cipher_id from TASKS where position_id = ? and difficulty_level = (select difficulty_level from teams where id = ?))", positionID, teamID).Scan(&cipherID, &assignment) var cipherID int
var taskID int
var order int
var last_cipher int
var help int = 0
var penalty int = 0
// Find task for this position and team's difficulty level
err = db.QueryRow("SELECT id FROM TASKS WHERE position_id = ? AND difficulty_level = (SELECT difficulty_level FROM teams WHERE id = ?)", positionID, teamID).Scan(&taskID)
if err == sql.ErrNoRows {
http.Error(w, "No task found for this position and team", http.StatusNotFound)
return
} else if err != nil {
http.Error(w, "Could not retrieve task", http.StatusInternalServerError)
return
}
// get task order
err = db.QueryRow("SELECT order_num FROM TASKS WHERE id = ?", taskID).Scan(&order)
if err != nil {
http.Error(w, "Could not retrieve task order", http.StatusInternalServerError)
return
}
// get last cipher visited by team
err = db.QueryRow("SELECT last_cipher FROM teams WHERE id = ?", teamID).Scan(&last_cipher)
if err != nil {
http.Error(w, "Could not retrieve last cipher", http.StatusInternalServerError)
return
}
// check if the task is available for the team
// if order > last_cipher + 1, task is not yet available
// if order == last_cipher + 1, task is now available, update last_cipher
// if order <= last_cipher, task has been already visited, allow viewing
if order > last_cipher+1 {
http.Error(w, "This task is not yet available", http.StatusForbidden)
return
} else if order == last_cipher+1 {
last_cipher = order
_, err = db.Exec("UPDATE teams SET last_cipher = ? WHERE id = ?", order, teamID)
if err != nil {
http.Error(w, "Could not update last cipher", http.StatusInternalServerError)
return
}
} else if order < last_cipher {
help = 2
}
// get cipher assignment
err = db.QueryRow("SELECT id, assignment FROM CIPHERS WHERE id = (SELECT cipher_id FROM TASKS WHERE id = ?)", taskID).Scan(&cipherID, &assignment)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
http.Error(w, "No cipher found", http.StatusNotFound) http.Error(w, "No cipher found", http.StatusNotFound)
return return
@@ -162,6 +207,85 @@ func qrHandler(w http.ResponseWriter, r *http.Request) {
Coordinates: "", Coordinates: "",
Solution: "", Solution: "",
} }
// get penalties for this task and team
err = db.QueryRow("SELECT minutes FROM penalties WHERE team_id = ? AND task_id = ?", teamID, taskID).Scan(&penalty)
if err == sql.ErrNoRows {
penalty = 0
} else if err != nil {
http.Error(w, "Could not retrieve penalties", http.StatusInternalServerError)
return
}
// determine help level based on penalties
if penalty > 0 && penalty < 15 {
help = 1
} else if penalty >= 15 {
help = 2
}
// handle answer and help form submission
if r.Method == http.MethodPost {
if err := r.ParseForm(); err != nil {
http.Error(w, "Could not parse form", http.StatusBadRequest)
return
}
if r.FormValue("help") == "1" && help == 0 { // small help
help = 1
db.Exec("INSERT INTO penalties (team_id, task_id, minutes) VALUES (?, ?, 5)", teamID, taskID)
db.Exec("UPDATE teams SET penalty = penalty + 5 WHERE id = ?", teamID)
} else if r.FormValue("help") == "2" && help == 1 { // give up
help = 2
db.Exec("UPDATE penalties SET minutes = 30 WHERE team_id = ? AND task_id = ?", teamID, taskID)
db.Exec("UPDATE teams SET penalty = penalty + 30 WHERE id = ?", teamID)
db.Exec("UPDATE teams SET last_cipher = ? WHERE id = ?", order+1, teamID)
}
}
// find which clues to show
if help == 1 { // small help
var helpText string
err = db.QueryRow("SELECT clue FROM CIPHERS WHERE id = ?", cipherID).Scan(&helpText)
if err == sql.ErrNoRows {
helpText = ""
} else if err != nil {
http.Error(w, "Could not retrieve help text", http.StatusInternalServerError)
return
}
CipherTemplateData.HelpText = helpText
} else if help == 2 { // next cipher
// get end clue
var endClue string
err = db.QueryRow("SELECT end_clue FROM TASKS WHERE id = ?", taskID).Scan(&endClue)
if err == sql.ErrNoRows {
endClue = ""
} else if err != nil {
http.Error(w, "Could not retrieve end clue", http.StatusInternalServerError)
return
}
CipherTemplateData.FinalClue = endClue
// get coordinates
var coordinates string
err = db.QueryRow("SELECT gps FROM POSITIONS WHERE id = (SELECT position_id FROM TASKS WHERE id = (SELECT id FROM TASKS WHERE order_num = ? AND difficulty_level = (SELECT difficulty_level FROM teams WHERE id = ?)))", order+1, teamID).Scan(&coordinates)
if err == sql.ErrNoRows {
coordinates = ""
} else if err != nil {
http.Error(w, "Could not retrieve coordinates", http.StatusInternalServerError)
return
}
CipherTemplateData.Coordinates = coordinates
// get solution
var solution string
err = db.QueryRow("SELECT solution FROM CIPHERS WHERE id = ?", cipherID).Scan(&solution)
if err == sql.ErrNoRows {
solution = ""
} else if err != nil {
http.Error(w, "Could not retrieve solution", http.StatusInternalServerError)
return
}
CipherTemplateData.Solution = solution
}
CipherTemplateData.Help = help
err = CipherTemplate.Execute(w, CipherTemplateData) err = CipherTemplate.Execute(w, CipherTemplateData)
if err != nil { if err != nil {
http.Error(w, "Could not render template", http.StatusInternalServerError) http.Error(w, "Could not render template", http.StatusInternalServerError)

View File

@@ -11,6 +11,7 @@ type CipherTemplateS struct {
FinalClue string FinalClue string
Coordinates string Coordinates string
Solution string Solution string
Help int
} }
var CipherTemplate = template.Must(template.ParseFiles("templates/assignment.html")) var CipherTemplate = template.Must(template.ParseFiles("templates/assignment.html"))

View File

@@ -9,13 +9,13 @@
<h1>Zadání šifry {{.Order}}</h1> <h1>Zadání šifry {{.Order}}</h1>
<p>{{.Assignment}}</p> <p>{{.Assignment}}</p>
<hr> <hr>
{{if eq .HelpText ""}} {{if eq .Help 0}}
<p>Požádat o malou nápovědu.</p> <p>Požádat o malou nápovědu.</p>
<form method="post"> <form method="post">
<input type="hidden" name="help" value="1"> <input type="hidden" name="help" value="1">
<input type="submit" value="Zobrazit nápovědu"> <input type="submit" value="Zobrazit nápovědu">
</form> </form>
{{else if eq .Coordinates ""}} {{else if eq .Help 1}}
<p>Nápověda: {{.HelpText}}</p> <p>Nápověda: {{.HelpText}}</p>
<p>Vzdát se a ukázat pozici další šifry.</p> <p>Vzdát se a ukázat pozici další šifry.</p>
<form method="post"> <form method="post">
@@ -26,7 +26,7 @@
<p>Řešení: {{.Solution}}</p> <p>Řešení: {{.Solution}}</p>
{{end}} {{end}}
<hr> <hr>
{{if eq .Coordinates ""}} {{if ne .Help 2}}
<form method="post"> <form method="post">
Řešení: <input type="text" name="assignment"><br> Řešení: <input type="text" name="assignment"><br>
<input type="submit" value="Odeslat"> <input type="submit" value="Odeslat">