diff --git a/assets.go b/assets.go index 2c2e044..5893ba4 100644 --- a/assets.go +++ b/assets.go @@ -210,6 +210,22 @@ var degreeGraphImage *ebiten.Image // should maybe be created only when needed var titleDegreeGraphAsset []byte var titleDegreeGraphImage *ebiten.Image // should maybe be created only when needed +//go:embed assets/ex-degreematr.png +var degreeMatrAsset []byte +var degreeMatrImage *ebiten.Image // should maybe be created only when needed + +//go:embed assets/extitle-degreematr.png +var titleDegreeMatrAsset []byte +var titleDegreeMatrImage *ebiten.Image // should maybe be created only when needed + +//go:embed assets/ex-degreelist.png +var degreeListAsset []byte +var degreeListImage *ebiten.Image // should maybe be created only when needed + +//go:embed assets/extitle-degreelist.png +var titleDegreeListAsset []byte +var titleDegreeListImage *ebiten.Image // should maybe be created only when needed + const spriteSide int = 64 const menuSpriteSide int = 128 @@ -514,6 +530,30 @@ func loadAssets() { log.Fatal(err) } titleDegreeGraphImage = ebiten.NewImageFromImage(decodedAsset) + + decodedAsset, _, err = image.Decode(bytes.NewReader(degreeListAsset)) + if err != nil { + log.Fatal(err) + } + degreeListImage = ebiten.NewImageFromImage(decodedAsset) + + decodedAsset, _, err = image.Decode(bytes.NewReader(titleDegreeListAsset)) + if err != nil { + log.Fatal(err) + } + titleDegreeListImage = ebiten.NewImageFromImage(decodedAsset) + + decodedAsset, _, err = image.Decode(bytes.NewReader(degreeMatrAsset)) + if err != nil { + log.Fatal(err) + } + degreeMatrImage = ebiten.NewImageFromImage(decodedAsset) + + decodedAsset, _, err = image.Decode(bytes.NewReader(titleDegreeMatrAsset)) + if err != nil { + log.Fatal(err) + } + titleDegreeMatrImage = ebiten.NewImageFromImage(decodedAsset) } // split the graphElementsImage diff --git a/assets/ex-degreelist.png b/assets/ex-degreelist.png new file mode 100644 index 0000000..842a163 Binary files /dev/null and b/assets/ex-degreelist.png differ diff --git a/assets/ex-degreematr.png b/assets/ex-degreematr.png new file mode 100644 index 0000000..c39dc12 Binary files /dev/null and b/assets/ex-degreematr.png differ diff --git a/assets/extitle-degreegraph.png b/assets/extitle-degreegraph.png index 653d283..904374e 100644 Binary files a/assets/extitle-degreegraph.png and b/assets/extitle-degreegraph.png differ diff --git a/assets/extitle-degreelist.png b/assets/extitle-degreelist.png new file mode 100644 index 0000000..da112e0 Binary files /dev/null and b/assets/extitle-degreelist.png differ diff --git a/assets/extitle-degreematr.png b/assets/extitle-degreematr.png new file mode 100644 index 0000000..3c3fcf0 Binary files /dev/null and b/assets/extitle-degreematr.png differ diff --git a/ex-degreelist.go b/ex-degreelist.go new file mode 100644 index 0000000..4fbe76e --- /dev/null +++ b/ex-degreelist.go @@ -0,0 +1,115 @@ +package main + +import ( + "image" + "math/rand" + + "github.com/hajimehoshi/ebiten/v2" +) + +func initDegreeList(correction bool, graphCode, questionCode, answerCode int) (e exo, gCode, qCode int) { + + e.BasicSetup() + e.id = degreeList + e.successRequired = 5 + + numNodes := 4 + + elementSpacing := 100 + + // title setup + e.titleImage = titleDegreeListImage + xTitleShift, yTitleShift := e.titleImage.Size() + e.titleXPosition = (windowWidth - xTitleShift) / 2 + e.titleYPosition = elementSpacing + e.successCounterY = elementSpacing + yTitleShift + yTitleShift += spriteSide + + // graph setup + e.displayList = true + + if correction { + e.g.decode(graphCode, numNodes) + gCode = graphCode + } else { + e.g.genConnectedGraph(numNodes, 4, 12, -1, -1) + gCode = e.g.encode() + } + e.g.linkMatrGraph = false + + listSize := spriteSide * (numNodes + 1) + e.g.xlistposition = (windowWidth - listSize) / 2 + e.g.ylistposition = 2*elementSpacing + yTitleShift + + // question setup + var from int + if correction { + from, _ = decodeFromToQuestion(questionCode, numNodes) + qCode = questionCode + } else { + from = rand.Intn(numNodes) + qCode = encodeFromToQuestion(from, from, numNodes) + } + xshift, yshift := degreeListImage.Size() + e.drawQuestion = func(screen *ebiten.Image) { + options := ebiten.DrawImageOptions{} + options.GeoM.Translate(float64((windowWidth-xshift)/2), float64(listSize+3*elementSpacing+yTitleShift)) + screen.DrawImage( + degreeListImage, + &options, + ) + // from label + options.GeoM.Translate(float64(8*spriteSide+5), 8) + xLabel := from % 10 + yLabel := from / 10 + labelSubimage := image.Rect( + xLabel*spriteSide, (yLabel+1)*spriteSide, + (xLabel+1)*spriteSide, (yLabel+2)*spriteSide, + ) + screen.DrawImage( + graphElementsImage.SubImage(labelSubimage).(*ebiten.Image), + &options, + ) + } + + // answers setup + e.hasAnswerSheet = true + answerSize := menuSpriteSide / 2 + e.answers.init((windowWidth-15*answerSize)/2, listSize+yshift+3*elementSpacing+20+yTitleShift) + for i := 0; i < 10; i++ { + x := (i % 6) * (menuSpriteSide / 2) + y := (i / 6) * (menuSpriteSide / 2) + e.answers.addButton(i*3*answerSize/2+answerSize/4, 0, menuElementsImage.SubImage(image.Rect(x, y+menuSpriteSide, x+menuSpriteSide/2, y+menuSpriteSide+menuSpriteSide/2)).(*ebiten.Image)) + } + + answer := len(e.g.successorsList[from]) + for i := 0; i < len(e.g.edges); i++ { + if i != from { + if e.g.edges[i][from] > 0 { + answer++ + } + } + } + + if correction { + if answerCode < len(e.answers.clics) && answerCode >= 0 { + e.answers.clics[answerCode] = 1 + } + } + + e.checkResult = func() (bool, bool) { + return e.answers.clics[answer] >= 1, *(e.answers.numClics) >= 1 + } + + e.codeAnswer = func() int { + for answerID, clics := range e.answers.clics { + if clics > 0 { + return answerID + } + } + return 0 + } + + // return exercise + return e, gCode, qCode +} diff --git a/ex-degreematr.go b/ex-degreematr.go new file mode 100644 index 0000000..20b501c --- /dev/null +++ b/ex-degreematr.go @@ -0,0 +1,115 @@ +package main + +import ( + "image" + "math/rand" + + "github.com/hajimehoshi/ebiten/v2" +) + +func initDegreeMatr(correction bool, graphCode, questionCode, answerCode int) (e exo, gCode, qCode int) { + + e.BasicSetup() + e.id = degreeMatr + e.successRequired = 5 + + numNodes := 4 + + elementSpacing := 100 + + // title setup + e.titleImage = titleDegreeMatrImage + xTitleShift, yTitleShift := e.titleImage.Size() + e.titleXPosition = (windowWidth - xTitleShift) / 2 + e.titleYPosition = elementSpacing + e.successCounterY = elementSpacing + yTitleShift + yTitleShift += spriteSide + + // graph setup + e.displayAdjMatr = true + + if correction { + e.g.decode(graphCode, numNodes) + gCode = graphCode + } else { + e.g.genConnectedGraph(numNodes, 4, 12, -1, -1) + gCode = e.g.encode() + } + e.g.linkMatrGraph = false + + matrixSize := matrixCellSize * (numNodes + 1) + e.g.xmatrposition = (windowWidth - matrixSize) / 2 + e.g.ymatrposition = 2*elementSpacing + yTitleShift + + // question setup + var from int + if correction { + from, _ = decodeFromToQuestion(questionCode, numNodes) + qCode = questionCode + } else { + from = rand.Intn(numNodes) + qCode = encodeFromToQuestion(from, from, numNodes) + } + xshift, yshift := degreeMatrImage.Size() + e.drawQuestion = func(screen *ebiten.Image) { + options := ebiten.DrawImageOptions{} + options.GeoM.Translate(float64((windowWidth-xshift)/2), float64(matrixSize+3*elementSpacing+yTitleShift)) + screen.DrawImage( + degreeMatrImage, + &options, + ) + // from label + options.GeoM.Translate(float64(8*spriteSide+5), 8) + xLabel := from % 10 + yLabel := from / 10 + labelSubimage := image.Rect( + xLabel*spriteSide, (yLabel+1)*spriteSide, + (xLabel+1)*spriteSide, (yLabel+2)*spriteSide, + ) + screen.DrawImage( + graphElementsImage.SubImage(labelSubimage).(*ebiten.Image), + &options, + ) + } + + // answers setup + e.hasAnswerSheet = true + answerSize := menuSpriteSide / 2 + e.answers.init((windowWidth-15*answerSize)/2, matrixSize+yshift+3*elementSpacing+20+yTitleShift) + for i := 0; i < 10; i++ { + x := (i % 6) * (menuSpriteSide / 2) + y := (i / 6) * (menuSpriteSide / 2) + e.answers.addButton(i*3*answerSize/2+answerSize/4, 0, menuElementsImage.SubImage(image.Rect(x, y+menuSpriteSide, x+menuSpriteSide/2, y+menuSpriteSide+menuSpriteSide/2)).(*ebiten.Image)) + } + + answer := len(e.g.successorsList[from]) + for i := 0; i < len(e.g.edges); i++ { + if i != from { + if e.g.edges[i][from] > 0 { + answer++ + } + } + } + + if correction { + if answerCode < len(e.answers.clics) && answerCode >= 0 { + e.answers.clics[answerCode] = 1 + } + } + + e.checkResult = func() (bool, bool) { + return e.answers.clics[answer] >= 1, *(e.answers.numClics) >= 1 + } + + e.codeAnswer = func() int { + for answerID, clics := range e.answers.clics { + if clics > 0 { + return answerID + } + } + return 0 + } + + // return exercise + return e, gCode, qCode +} diff --git a/exolist.go b/exolist.go index 3b9bf6c..293e60a 100644 --- a/exolist.go +++ b/exolist.go @@ -26,6 +26,8 @@ const ( isTreeList isTreeMatr degreeGraph + degreeMatr + degreeList globalNumExo ) @@ -78,6 +80,10 @@ func (g *game) initExo(exNum int) { g.e, g.exState.descriptionExo = initMatrToList(g.correctionMode, g.exState.descriptionExo, g.exState.answer) case degreeGraph: g.e, g.exState.descriptionExo, g.exState.descriptionQuestion = initDegreeGraph(g.correctionMode, g.exState.descriptionExo, g.exState.descriptionQuestion, g.exState.answer) + case degreeList: + g.e, g.exState.descriptionExo, g.exState.descriptionQuestion = initDegreeList(g.correctionMode, g.exState.descriptionExo, g.exState.descriptionQuestion, g.exState.answer) + case degreeMatr: + g.e, g.exState.descriptionExo, g.exState.descriptionQuestion = initDegreeMatr(g.correctionMode, g.exState.descriptionExo, g.exState.descriptionQuestion, g.exState.answer) } log.Print(g.exState.encode()) @@ -125,6 +131,10 @@ func getExTitlePerNum(exNum int) *ebiten.Image { return titleMatrToListImage case degreeGraph: return titleDegreeGraphImage + case degreeList: + return titleDegreeListImage + case degreeMatr: + return titleDegreeMatrImage } return nil