clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

feat/elo-difficulty
puzzletea / games / netwalk / print_adapter.go
print_adapter.go 4.1K
1package netwalk23import (4 "math"56 "codeberg.org/go-pdf/fpdf"7 "github.com/FelineStateMachine/puzzletea/export/pdf"8)910type printAdapter struct{}1112var PDFPrintAdapter = printAdapter{}1314func (printAdapter) CanonicalGameType() string { return "Netwalk" }15func (printAdapter) Aliases() []string { return []string{"netwalk", "network"} }1617func (printAdapter) BuildPDFPayload(save []byte) (any, error) {18 return pdfexport.ParseNetwalkPrintData(save)19}2021func (printAdapter) RenderPDFBody(pdf *fpdf.Fpdf, payload any) error {22 switch data := payload.(type) {23 case *pdfexport.NetwalkData:24 renderNetwalkPage(pdf, data)25 }26 return nil27}2829func renderNetwalkPage(pdf *fpdf.Fpdf, data *pdfexport.NetwalkData) {30 if data == nil || data.Size <= 0 {31 return32 }3334 pageW, pageH := pdf.GetPageSize()35 pageNo := pdf.PageNo()36 body := pdfexport.PuzzleBodyRect(pageW, pageH, pageNo)37 rules := []string{"Rotate tiles so every connector matches and the full network reaches the server without loops."}38 ruleLines := pdfexport.InstructionLineCount(pdf, body.W, rules)39 area := pdfexport.PuzzleBoardRect(pageW, pageH, pageNo, ruleLines)40 cellSize := pdfexport.FitCompactCellSize(data.Size, data.Size, area)41 if cellSize <= 0 {42 return43 }4445 blockW := float64(data.Size) * cellSize46 blockH := float64(data.Size) * cellSize47 startX, startY := pdfexport.CenteredOrigin(area, data.Size, data.Size, cellSize)4849 drawNetwalkGrid(pdf, startX, startY, blockW, blockH, data.Size, cellSize)5051 for y := range data.Size {52 for x := range data.Size {53 cellX := startX + float64(x)*cellSize54 cellY := startY + float64(y)*cellSize55 drawNetwalkTile(pdf, data, x, y, cellX, cellY, cellSize)56 }57 }5859 pdf.SetDrawColor(55, 55, 55)60 pdf.SetLineWidth(pdfexport.OuterBorderLineMM)61 pdf.Rect(startX, startY, blockW, blockH, "D")6263 ruleY := pdfexport.InstructionY(startY+blockH, pageH, ruleLines)64 pdfexport.RenderInstructions(pdf, body.X, ruleY, body.W, rules)65}6667func drawNetwalkGrid(pdf *fpdf.Fpdf, startX, startY, blockW, blockH float64, size int, cellSize float64) {68 if size <= 1 {69 return70 }7172 pdf.SetDrawColor(115, 115, 115)73 pdf.SetLineWidth(math.Max(pdfexport.ThinGridLineMM*0.72, 0.14))7475 for i := 1; i < size; i++ {76 offset := float64(i) * cellSize77 pdf.Line(startX+offset, startY, startX+offset, startY+blockH)78 pdf.Line(startX, startY+offset, startX+blockW, startY+offset)79 }80}8182func drawNetwalkTile(pdf *fpdf.Fpdf, data *pdfexport.NetwalkData, x, y int, cellX, cellY, cellSize float64) {83 mask := directionMask(data.Masks[y][x])84 if mask == 0 {85 return86 }87 mask = rotateMask(mask, data.Rotations[y][x])8889 centerX := cellX + cellSize/290 centerY := cellY + cellSize/291 isRoot := x == data.RootX && y == data.RootY92 isLeaf := degree(mask) == 193 pad := cellSize * 0.1694 if isRoot || isLeaf {95 pad = math.Max(pad, netwalkMarkerRadius(cellSize, isRoot))96 }97 pdf.SetLineWidth(math.Max(cellSize*0.055, 0.26))98 pdf.SetDrawColor(65, 65, 65)99100 if mask&north != 0 {101 pdf.Line(centerX, centerY, centerX, cellY+pad)102 }103 if mask&east != 0 {104 pdf.Line(centerX, centerY, cellX+cellSize-pad, centerY)105 }106 if mask&south != 0 {107 pdf.Line(centerX, centerY, centerX, cellY+cellSize-pad)108 }109 if mask&west != 0 {110 pdf.Line(centerX, centerY, cellX+pad, centerY)111 }112113 switch {114 case isRoot:115 drawNetwalkSourceMarker(pdf, centerX, centerY, cellSize)116 return117 case isLeaf:118 drawNetwalkSinkMarker(pdf, centerX, centerY, cellSize)119 }120}121122func netwalkMarkerRadius(cellSize float64, root bool) float64 {123 scale := 0.16124 if root {125 scale = 0.20126 }127 return math.Max(1.2, math.Min(2.6, cellSize*scale))128}129130func drawNetwalkSinkMarker(pdf *fpdf.Fpdf, centerX, centerY, cellSize float64) {131 radius := netwalkMarkerRadius(cellSize, false)132 pdf.SetDrawColor(65, 65, 65)133 pdf.SetFillColor(255, 255, 255)134 pdf.SetLineWidth(math.Max(cellSize*0.045, 0.22))135 pdf.Circle(centerX, centerY, radius, "DF")136}137138func drawNetwalkSourceMarker(pdf *fpdf.Fpdf, centerX, centerY, cellSize float64) {139 radius := netwalkMarkerRadius(cellSize, true)140 pdf.SetDrawColor(65, 65, 65)141 pdf.SetFillColor(255, 255, 255)142 pdf.SetLineWidth(math.Max(cellSize*0.05, 0.24))143 pdf.Circle(centerX, centerY, radius, "DF")144145 pdf.SetFillColor(65, 65, 65)146 pdf.Circle(centerX, centerY, radius*0.36, "F")147}