Skip to content

Commit 55d43c4

Browse files
committed
Refactor puzzle generation and solution checking endpoints; update Swagger documentation
1 parent 6e425ce commit 55d43c4

5 files changed

Lines changed: 546 additions & 63 deletions

File tree

controllers/puzzles.go

Lines changed: 154 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ func (p *PuzzleController) DeletePuzzle(c *gin.Context) {
274274
c.JSON(http.StatusOK, gin.H{"message": "Puzzle deleted"})
275275
}
276276

277-
// GeneratePuzzle godoc
278-
// @Summary Generate puzzle input and solutions
279-
// @Description Generates puzzle input and calculates solutions for a given puzzle
277+
// GeneratePuzzleInput godoc
278+
// @Summary Generate puzzle input
279+
// @Description Generates puzzle input for a given puzzle
280280
// @Tags Puzzles
281281
// @Produce json
282282
// @Param theme query string true "Theme name"
@@ -285,54 +285,155 @@ func (p *PuzzleController) DeletePuzzle(c *gin.Context) {
285285
// @Success 200 {object} map[string]interface{}
286286
// @Failure 404 {object} map[string]string
287287
// @Failure 500 {object} map[string]string
288-
// @Router /puzzle/generate [get]
289-
func (p *PuzzleController) GeneratePuzzle(c *gin.Context) {
290-
themeName := c.Query("theme")
291-
puzzleId := c.Query("puzzle")
292-
uniqueID := c.Query("unique_id")
293-
294-
theme := p.loader.GetTheme(themeName)
295-
if theme == nil {
296-
c.JSON(http.StatusNotFound, gin.H{"message": "Theme not found"})
297-
return
298-
}
299-
300-
var foundPuzzle *models.Puzzle
301-
for i, puzzle := range theme.Puzzles {
302-
if puzzle.GetId() == puzzleId {
303-
foundPuzzle = &theme.Puzzles[i]
304-
break
305-
}
306-
}
307-
308-
if foundPuzzle == nil {
309-
c.JSON(http.StatusNotFound, gin.H{"message": "Puzzle not found"})
310-
return
311-
}
312-
313-
// Use pythonRunner to generate input and solutions
314-
linesCount := 400 // Default value, could be made configurable
315-
inputLines, err := p.pythonRunner.RunForge(foundPuzzle.GetForgePath(), linesCount, uniqueID)
316-
if err != nil {
317-
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate puzzle input: " + err.Error()})
318-
return
319-
}
320-
321-
firstSolution, err := p.pythonRunner.RunDecrypt(foundPuzzle.GetDecryptPath(), inputLines)
322-
if err != nil {
323-
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to solve first part: " + err.Error()})
324-
return
325-
}
326-
327-
secondSolution, err := p.pythonRunner.RunUnveil(foundPuzzle.GetUnveilPath(), inputLines)
328-
if err != nil {
329-
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to solve second part: " + err.Error()})
330-
return
331-
}
332-
333-
c.JSON(http.StatusOK, gin.H{
334-
"first_solution": firstSolution,
335-
"second_solution": secondSolution,
336-
"input_lines": inputLines,
337-
})
288+
// @Router /puzzle/generate/input [get]
289+
func (p *PuzzleController) GeneratePuzzleInput(c *gin.Context) {
290+
themeName := c.Query("theme")
291+
puzzleId := c.Query("puzzle")
292+
uniqueID := c.Query("unique_id")
293+
294+
theme := p.loader.GetTheme(themeName)
295+
if theme == nil {
296+
c.JSON(http.StatusNotFound, gin.H{"message": "Theme not found"})
297+
return
298+
}
299+
300+
var foundPuzzle *models.Puzzle
301+
for i, puzzle := range theme.Puzzles {
302+
if puzzle.GetId() == puzzleId {
303+
foundPuzzle = &theme.Puzzles[i]
304+
break
305+
}
306+
}
307+
308+
if foundPuzzle == nil {
309+
c.JSON(http.StatusNotFound, gin.H{"message": "Puzzle not found"})
310+
return
311+
}
312+
313+
linesCount := 400 // Default value, could be made configurable
314+
inputLines, err := p.pythonRunner.RunForge(foundPuzzle.GetForgePath(), linesCount, uniqueID)
315+
if err != nil {
316+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate puzzle input: " + err.Error()})
317+
return
318+
}
319+
320+
c.JSON(http.StatusOK, gin.H{
321+
"input_lines": inputLines,
322+
})
338323
}
324+
325+
// CheckFirstSolution godoc
326+
// @Summary Check first solution
327+
// @Description Checks if the first solution matches the provided value
328+
// @Tags Puzzles
329+
// @Produce json
330+
// @Param theme query string true "Theme name"
331+
// @Param puzzle query string true "Puzzle Id"
332+
// @Param unique_id query string true "Unique ID for generation"
333+
// @Param solution query string true "Solution to check"
334+
// @Success 200 {object} map[string]string
335+
// @Failure 404 {object} map[string]string
336+
// @Failure 500 {object} map[string]string
337+
// @Router /puzzle/check/first [get]
338+
func (p *PuzzleController) CheckFirstSolution(c *gin.Context) {
339+
themeName := c.Query("theme")
340+
puzzleId := c.Query("puzzle")
341+
uniqueID := c.Query("unique_id")
342+
solution := c.Query("solution")
343+
344+
theme := p.loader.GetTheme(themeName)
345+
if theme == nil {
346+
c.JSON(http.StatusNotFound, gin.H{"message": "Theme not found"})
347+
return
348+
}
349+
350+
var foundPuzzle *models.Puzzle
351+
for i, puzzle := range theme.Puzzles {
352+
if puzzle.GetId() == puzzleId {
353+
foundPuzzle = &theme.Puzzles[i]
354+
break
355+
}
356+
}
357+
358+
if foundPuzzle == nil {
359+
c.JSON(http.StatusNotFound, gin.H{"message": "Puzzle not found"})
360+
return
361+
}
362+
363+
linesCount := 400 // Default value, could be made configurable
364+
inputLines, err := p.pythonRunner.RunForge(foundPuzzle.GetForgePath(), linesCount, uniqueID)
365+
if err != nil {
366+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate puzzle input: " + err.Error()})
367+
return
368+
}
369+
370+
firstSolution, err := p.pythonRunner.RunDecrypt(foundPuzzle.GetDecryptPath(), inputLines)
371+
if err != nil {
372+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to solve first part: " + err.Error()})
373+
return
374+
}
375+
376+
if firstSolution == solution {
377+
c.JSON(http.StatusOK, gin.H{"message": "First solution matches"})
378+
} else {
379+
c.JSON(http.StatusOK, gin.H{"message": "First solution does not match"})
380+
}
381+
}
382+
383+
// CheckSecondSolution godoc
384+
// @Summary Check second solution
385+
// @Description Checks if the second solution matches the provided value
386+
// @Tags Puzzles
387+
// @Produce json
388+
// @Param theme query string true "Theme name"
389+
// @Param puzzle query string true "Puzzle Id"
390+
// @Param unique_id query string true "Unique ID for generation"
391+
// @Param solution query string true "Solution to check"
392+
// @Success 200 {object} map[string]string
393+
// @Failure 404 {object} map[string]string
394+
// @Failure 500 {object} map[string]string
395+
// @Router /puzzle/check/second [get]
396+
func (p *PuzzleController) CheckSecondSolution(c *gin.Context) {
397+
themeName := c.Query("theme")
398+
puzzleId := c.Query("puzzle")
399+
uniqueID := c.Query("unique_id")
400+
solution := c.Query("solution")
401+
402+
theme := p.loader.GetTheme(themeName)
403+
if theme == nil {
404+
c.JSON(http.StatusNotFound, gin.H{"message": "Theme not found"})
405+
return
406+
}
407+
408+
var foundPuzzle *models.Puzzle
409+
for i, puzzle := range theme.Puzzles {
410+
if puzzle.GetId() == puzzleId {
411+
foundPuzzle = &theme.Puzzles[i]
412+
break
413+
}
414+
}
415+
416+
if foundPuzzle == nil {
417+
c.JSON(http.StatusNotFound, gin.H{"message": "Puzzle not found"})
418+
return
419+
}
420+
421+
linesCount := 400 // Default value, could be made configurable
422+
inputLines, err := p.pythonRunner.RunForge(foundPuzzle.GetForgePath(), linesCount, uniqueID)
423+
if err != nil {
424+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate puzzle input: " + err.Error()})
425+
return
426+
}
427+
428+
secondSolution, err := p.pythonRunner.RunUnveil(foundPuzzle.GetUnveilPath(), inputLines)
429+
if err != nil {
430+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to solve second part: " + err.Error()})
431+
return
432+
}
433+
434+
if secondSolution == solution {
435+
c.JSON(http.StatusOK, gin.H{"message": "Second solution matches"})
436+
} else {
437+
c.JSON(http.StatusOK, gin.H{"message": "Second solution does not match"})
438+
}
439+
}

docs/docs.go

Lines changed: 145 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,158 @@ const docTemplate = `{
192192
}
193193
}
194194
},
195-
"/puzzle/generate": {
195+
"/puzzle/check/first": {
196196
"get": {
197-
"description": "Generates puzzle input and calculates solutions for a given puzzle",
197+
"description": "Checks if the first solution matches the provided value",
198198
"produces": [
199199
"application/json"
200200
],
201201
"tags": [
202202
"Puzzles"
203203
],
204-
"summary": "Generate puzzle input and solutions",
204+
"summary": "Check first solution",
205+
"parameters": [
206+
{
207+
"type": "string",
208+
"description": "Theme name",
209+
"name": "theme",
210+
"in": "query",
211+
"required": true
212+
},
213+
{
214+
"type": "string",
215+
"description": "Puzzle Id",
216+
"name": "puzzle",
217+
"in": "query",
218+
"required": true
219+
},
220+
{
221+
"type": "string",
222+
"description": "Unique ID for generation",
223+
"name": "unique_id",
224+
"in": "query",
225+
"required": true
226+
},
227+
{
228+
"type": "string",
229+
"description": "Solution to check",
230+
"name": "solution",
231+
"in": "query",
232+
"required": true
233+
}
234+
],
235+
"responses": {
236+
"200": {
237+
"description": "OK",
238+
"schema": {
239+
"type": "object",
240+
"additionalProperties": {
241+
"type": "string"
242+
}
243+
}
244+
},
245+
"404": {
246+
"description": "Not Found",
247+
"schema": {
248+
"type": "object",
249+
"additionalProperties": {
250+
"type": "string"
251+
}
252+
}
253+
},
254+
"500": {
255+
"description": "Internal Server Error",
256+
"schema": {
257+
"type": "object",
258+
"additionalProperties": {
259+
"type": "string"
260+
}
261+
}
262+
}
263+
}
264+
}
265+
},
266+
"/puzzle/check/second": {
267+
"get": {
268+
"description": "Checks if the second solution matches the provided value",
269+
"produces": [
270+
"application/json"
271+
],
272+
"tags": [
273+
"Puzzles"
274+
],
275+
"summary": "Check second solution",
276+
"parameters": [
277+
{
278+
"type": "string",
279+
"description": "Theme name",
280+
"name": "theme",
281+
"in": "query",
282+
"required": true
283+
},
284+
{
285+
"type": "string",
286+
"description": "Puzzle Id",
287+
"name": "puzzle",
288+
"in": "query",
289+
"required": true
290+
},
291+
{
292+
"type": "string",
293+
"description": "Unique ID for generation",
294+
"name": "unique_id",
295+
"in": "query",
296+
"required": true
297+
},
298+
{
299+
"type": "string",
300+
"description": "Solution to check",
301+
"name": "solution",
302+
"in": "query",
303+
"required": true
304+
}
305+
],
306+
"responses": {
307+
"200": {
308+
"description": "OK",
309+
"schema": {
310+
"type": "object",
311+
"additionalProperties": {
312+
"type": "string"
313+
}
314+
}
315+
},
316+
"404": {
317+
"description": "Not Found",
318+
"schema": {
319+
"type": "object",
320+
"additionalProperties": {
321+
"type": "string"
322+
}
323+
}
324+
},
325+
"500": {
326+
"description": "Internal Server Error",
327+
"schema": {
328+
"type": "object",
329+
"additionalProperties": {
330+
"type": "string"
331+
}
332+
}
333+
}
334+
}
335+
}
336+
},
337+
"/puzzle/generate/input": {
338+
"get": {
339+
"description": "Generates puzzle input for a given puzzle",
340+
"produces": [
341+
"application/json"
342+
],
343+
"tags": [
344+
"Puzzles"
345+
],
346+
"summary": "Generate puzzle input",
205347
"parameters": [
206348
{
207349
"type": "string",

0 commit comments

Comments
 (0)