Repository navigation
Expand file tree
/
Copy pathfizzbuzz.cfg
More file actions
316 lines (308 loc) · 13.3 KB
/
Copy pathfizzbuzz.cfg
File metadata and controls
316 lines (308 loc) · 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# FizzBuzz Implementation in G-code (Klipper)
# September 19, 2026
#
# "Write a program that prints the numbers from 1 to 100. But for multiples of
# three print “Fizz” instead of the number and for the multiples of five print
# “Buzz”. For numbers which are multiples of both three and five print
# “FizzBuzz”."
#
# The printer does the FizzBuzz math. `_FB_CALC` applies n%15 / n%3 / n%5 and
# stores the label; `_FB_CELL` then extrudes that stored result with G0/G1.
# There is no pre-baked list of 100 words and no host-language generator.
#
# ---------------------------------------------------------------------------
# Filament and output
# ---------------------------------------------------------------------------
# Assumes PLA+ on a single extruder, one colour for the whole job. No tool
# changes, no mixing, no T1. `_FB_PREPARE` selects `extruder`, heats it, and
# lays a one-colour prime line before any glyphs.
#
# hotend 215 C typical PLA+ (override: FIZZBUZZ N=100 HOTEND=220)
# bed 60 C typical PLA+ on PEI (override: FIZZBUZZ N=100 BED=65)
# layer 0.28 mm first-layer stroke height
# filament 1.75 mm E per mm is sized for a 0.40 mm nozzle
#
# ---------------------------------------------------------------------------
# Bed, origin, coordinate system
# ---------------------------------------------------------------------------
# Target firmware : Klipper
# Bed : 256 mm x 256 mm
# Origin : (0, 0, 0) = front-left of the bed after G28
# Axes : X right, Y back, Z up (standard Klipper Cartesian)
#
# Programmed motion stays inside an 18 mm margin (12 mm extra to the steel):
#
# X, Y in [18.0, 238.0]
# Z in [0.28, 8.0 ] (first-layer height; hop at 8 mm)
#
# Layout: 5 x 20 grid of 44 x 11 mm cells from (18, 18), left-to-right,
# top-to-bottom (1-5 on the back row). Every cell prints the *full*
# calculated token: the number, "Fizz", "Buzz", or "FizzBuzz". No F / B / FB.
# cell X = 18 + col * 44 col = (n-1) % 5 (0..4)
# cell Y = 18 + (19-row) * 11 row = (n-1) // 5 (0..19)
# Glyphs are inset 1.6 mm, so strokes stay in [19.6, 236.4].
# The prime line is on Y=20 from X=20 to X=100 (still inside the margin).
#
# ---------------------------------------------------------------------------
# How to load / run (Mainsail / Fluidd)
# ---------------------------------------------------------------------------
# 1. Load PLA+ on the only extruder. Confirm the bed is clear and 256x256.
# 2. Copy this file to the printer config directory, e.g.
# ~/printer_data/config/fizzbuzz.cfg
# 3. Add to printer.cfg:
# [include fizzbuzz.cfg]
# 4. Restart Klipper (Firmware Restart).
# 5. In the Klipper / Mainsail / Fluidd console, call the entry macro with N
# (N is the last integer to print; the challenge is N=100):
# FIZZBUZZ N=100
#
# That call prepares the printer (home, PLA+ heat, prime) then calculates and
# prints each term from 1 through N as the full token (number, Fizz, Buzz,
# or FizzBuzz).
#
# FIZZBUZZ N=100 full challenge
# FIZZBUZZ N=15 1 through 15 only
# FIZZBUZZ N=100 HOME=0 already homed; Z is trusted
# FIZZBUZZ N=100 HOTEND=220
# FIZZBUZZ N=100 BED=65
# FIZZBUZZ N=100 COLD=1 skip heaters, prime, and E (motion-only test)
#
# Do NOT upload this file as a print job. It is Klipper config. Jinja2 in a
# raw .gcode job is not evaluated; the macros below are what calculate.
#
# ---------------------------------------------------------------------------
# Proof / Klippy batch simulator
# ---------------------------------------------------------------------------
# src/GCode/sim/simulate.py runs this same entry point through official Klippy
# fileoutput (no hardware) and writes fizzbuzz_preview.png. See sim/README.md.
#
# ---------------------------------------------------------------------------
# run_all.ps1
# ---------------------------------------------------------------------------
# Physical PLA+ toolpath + M118 of the calculated labels. Cannot hash-match
# FizzBuzz.txt. test_nobuild.json uses command `klipper` (not a host binary),
# so the runner skips this solution. Use simulate.py for an actual check.
[gcode_macro _FB_LAYOUT]
variable_bed: 256.0
variable_x_min: 18.0
variable_x_max: 238.0
variable_y_min: 18.0
variable_y_max: 238.0
variable_x0: 18.0
variable_y0: 18.0
variable_cols: 5
variable_rows: 20
variable_cell_w: 44.0
variable_cell_h: 11.0
variable_z_draw: 0.28
variable_z_hop: 8.0
variable_hotend: 215
variable_bed_temp: 60
variable_e_mm: 0.048
gcode:
{action_respond_info("FizzBuzz layout: 256x256 bed, PLA+ 215/60, single colour, 5x20 full-word cells.")}
# Home, heat PLA+, lock the single extruder, prime one colour.
[gcode_macro _FB_PREPARE]
gcode:
{% set L = printer["gcode_macro _FB_LAYOUT"] %}
{% set home = params.HOME|default(1)|int %}
{% set cold = params.COLD|default(0)|int %}
{% set hotend = params.HOTEND|default(L.hotend)|float %}
{% set bed = params.BED|default(L.bed_temp)|float %}
{% set z_draw = params.Z_DRAW|default(L.z_draw)|float %}
{% set z_hop = params.Z_HOP|default(L.z_hop)|float %}
G90
G21
M107
ACTIVATE_EXTRUDER EXTRUDER=extruder
{% if cold %}
M104 S0
M140 S0
{% if home %}
G28
{% endif %}
G0 Z{z_hop} F600
M118 Cold motion test; heaters and extrusion skipped
{% else %}
M140 S{bed}
M104 S{hotend}
{% if home %}
G28
{% endif %}
M190 S{bed}
M109 S{hotend}
M83
G92 E0
G0 Z{z_hop} F600
G0 X20 Y20 F6000
G1 Z{z_draw} F600
G1 X100 Y20 E3.8 F1500
G1 E-0.8 F1800
G0 Z{z_hop} F600
G0 X20 Y22 F6000
G92 E0
M106 S204
M118 Prepared PLA+ {hotend}/{bed} C; single colour prime done
{% endif %}
# Retract, park inside the margin, cool down.
[gcode_macro _FB_FINISH]
gcode:
{% set L = printer["gcode_macro _FB_LAYOUT"] %}
{% set cold = params.COLD|default(0)|int %}
{% set z_hop = params.Z_HOP|default(L.z_hop)|float %}
{% if not cold %}
G1 E-1.2 F1800
{% endif %}
G90
G0 Z{z_hop} F600
G0 X{L.x_min} Y{L.y_max} F6000
M400
M107
M104 S0
M140 S0
M118 FizzBuzz print complete
# Calculate the FizzBuzz term for N and store it on this macro. The next
# command (_FB_CELL) reads printer["gcode_macro _FB_CALC"].label and prints it.
[gcode_macro _FB_CALC]
variable_label: ""
gcode:
{% set n = params.N|int %}
{% if n % 15 == 0 %}
{% set result = "FizzBuzz" %}
{% elif n % 3 == 0 %}
{% set result = "Fizz" %}
{% elif n % 5 == 0 %}
{% set result = "Buzz" %}
{% else %}
{% set result = n|string %}
{% endif %}
SET_GCODE_VARIABLE MACRO=_FB_CALC VARIABLE=label VALUE='"{result}"'
{action_respond_info("FIZZBUZZ " ~ n|string ~ " " ~ result)}
M118 {result}
# Stroke-font extruder. CHAR is one character of the label _FB_CALC stored.
# Glyphs live in the unit square (origin = bottom-left of the character box).
[gcode_macro _FB_DRAW_CHAR]
gcode:
{% set L = printer["gcode_macro _FB_LAYOUT"] %}
{% set ch = params.CHAR|string %}
{% set ox = params.X|float %}
{% set oy = params.Y|float %}
{% set w = params.W|float %}
{% set h = params.H|float %}
{% set z_draw = params.Z_DRAW|default(L.z_draw)|float %}
{% set z_hop = params.Z_HOP|default(L.z_hop)|float %}
{% set feed = params.FEED|default(900)|float %}
{% set cold = params.COLD|default(0)|int %}
{% set e_mm = params.E_MM|default(L.e_mm)|float %}
{% set glyphs = {
"0": [ [[0.18,0.12],[0.18,0.88],[0.82,0.88],[0.82,0.12],[0.18,0.12]] ],
"1": [ [[0.30,0.70],[0.50,0.90],[0.50,0.12]], [[0.24,0.12],[0.76,0.12]] ],
"2": [ [[0.16,0.72],[0.22,0.86],[0.40,0.94],[0.64,0.94],[0.80,0.84],[0.82,0.70],[0.70,0.54],[0.18,0.12],[0.84,0.12]] ],
"3": [ [[0.16,0.88],[0.78,0.88],[0.50,0.56],[0.76,0.44],[0.80,0.26],[0.68,0.12],[0.30,0.10],[0.16,0.22]] ],
"4": [ [[0.70,0.12],[0.70,0.90],[0.18,0.40],[0.86,0.40]] ],
"5": [ [[0.80,0.90],[0.22,0.90],[0.18,0.54],[0.68,0.56],[0.84,0.42],[0.82,0.22],[0.62,0.10],[0.24,0.12],[0.16,0.24]] ],
"6": [ [[0.76,0.86],[0.40,0.94],[0.20,0.76],[0.18,0.24],[0.32,0.10],[0.68,0.10],[0.84,0.24],[0.82,0.46],[0.60,0.56],[0.22,0.48]] ],
"7": [ [[0.16,0.90],[0.84,0.90],[0.36,0.12]] ],
"8": [ [[0.50,0.52],[0.22,0.62],[0.20,0.82],[0.36,0.94],[0.64,0.94],[0.80,0.82],[0.78,0.62],[0.50,0.52],[0.22,0.40],[0.18,0.22],[0.34,0.08],[0.66,0.08],[0.82,0.22],[0.78,0.40],[0.50,0.52]] ],
"9": [ [[0.22,0.16],[0.60,0.08],[0.80,0.24],[0.82,0.76],[0.68,0.92],[0.32,0.92],[0.18,0.76],[0.20,0.56],[0.42,0.46],[0.80,0.54]] ],
"F": [ [[0.20,0.10],[0.20,0.90],[0.84,0.90]], [[0.20,0.54],[0.70,0.54]] ],
"B": [ [[0.20,0.10],[0.20,0.90],[0.62,0.90],[0.80,0.78],[0.80,0.62],[0.62,0.52],[0.20,0.52]], [[0.62,0.52],[0.84,0.40],[0.84,0.22],[0.64,0.10],[0.20,0.10]] ],
"i": [ [[0.50,0.10],[0.50,0.52]], [[0.50,0.72],[0.50,0.86]] ],
"z": [ [[0.16,0.88],[0.84,0.88],[0.16,0.12],[0.84,0.12]] ],
"u": [ [[0.18,0.90],[0.18,0.28],[0.30,0.12],[0.70,0.12],[0.82,0.28],[0.82,0.90]] ]
} %}
{% set strokes = glyphs[ch] if ch in glyphs else [] %}
{% set ns = namespace(x=ox, y=oy) %}
{% for stroke in strokes %}
{% for i in range(stroke|length) %}
{% set px = [L.x_min, [L.x_max, ox + stroke[i][0] * w]|min]|max %}
{% set py = [L.y_min, [L.y_max, oy + stroke[i][1] * h]|min]|max %}
{% if i == 0 %}
G0 Z{z_hop} F600
G0 X{px} Y{py} F6000
G1 Z{z_draw} F600
{% if not cold %}
G1 E0.12 F900
{% endif %}
{% else %}
{% set dist = ((px - ns.x) * (px - ns.x) + (py - ns.y) * (py - ns.y)) ** 0.5 %}
{% if not cold %}
G1 X{px} Y{py} E{dist * e_mm} F{feed}
{% else %}
G1 X{px} Y{py} F{feed}
{% endif %}
{% endif %}
{% set ns.x = px %}
{% set ns.y = py %}
{% endfor %}
{% if not cold %}
G1 E-0.8 F1800
{% endif %}
{% endfor %}
G0 Z{z_hop} F600
# Extrude the calculated string left-to-right inside a box.
[gcode_macro _FB_DRAW_TEXT]
gcode:
{% set text = params.TEXT|string %}
{% set ox = params.X|float %}
{% set oy = params.Y|float %}
{% set box_w = params.W|float %}
{% set box_h = params.H|float %}
{% set z_draw = params.Z_DRAW|default(0.28)|float %}
{% set z_hop = params.Z_HOP|default(8.0)|float %}
{% set cold = params.COLD|default(0)|int %}
{% set nch = text|length %}
{% if nch > 0 %}
{% set gap = 0.35 %}
{% set cw_fit = (box_w - gap * (nch - 1)) / nch %}
{% set cw = [cw_fit, box_h * 0.70]|min %}
{% set xoff = (box_w - (nch * cw + gap * (nch - 1))) / 2 %}
{% for i in range(nch) %}
_FB_DRAW_CHAR CHAR={text[i]} X={ox + xoff + i * (cw + gap)} Y={oy} W={cw} H={box_h} Z_DRAW={z_draw} Z_HOP={z_hop} COLD={cold}
{% endfor %}
{% endif %}
# Print one grid cell from the label that `_FB_CALC` just stored. N is only
# used to place the cell; the letters come from the calculated result.
[gcode_macro _FB_CELL]
gcode:
{% set L = printer["gcode_macro _FB_LAYOUT"] %}
{% set n = params.N|int %}
{% set label = printer["gcode_macro _FB_CALC"].label %}
{% set z_draw = params.Z_DRAW|default(L.z_draw)|float %}
{% set z_hop = params.Z_HOP|default(L.z_hop)|float %}
{% set cold = params.COLD|default(0)|int %}
{% set cols = L.cols|int %}
{% set rows = L.rows|int %}
{% set row = (n - 1) // cols %}
{% set col = (n - 1) % cols %}
{% set cx = L.x0 + col * L.cell_w %}
{% set cy = L.y0 + (rows - 1 - row) * L.cell_h %}
; Full challenge token: number, Fizz, Buzz, or FizzBuzz.
_FB_DRAW_TEXT TEXT={label} X={cx + 1.6} Y={cy + 1.6} W={L.cell_w - 3.2} H={L.cell_h - 3.2} Z_DRAW={z_draw} Z_HOP={z_hop} COLD={cold}
[gcode_macro FIZZBUZZ]
description: Console entry: FIZZBUZZ N=100 (PLA+ FizzBuzz 1..N on 256x256)
gcode:
{% if "N" not in params %}
{action_raise_error("Call from the Klipper console as: FIZZBUZZ N=100")}
{% endif %}
{% set N = params.N|int %}
{% set L = printer["gcode_macro _FB_LAYOUT"] %}
{% set home = params.HOME|default(1)|int %}
{% set cold = params.COLD|default(0)|int %}
{% set hotend = params.HOTEND|default(L.hotend)|float %}
{% set bed = params.BED|default(L.bed_temp)|float %}
{% set z_draw = params.Z_DRAW|default(L.z_draw)|float %}
{% set z_hop = params.Z_HOP|default(L.z_hop)|float %}
{% if N < 1 or N > 100 %}
{action_raise_error("N must be 1..100 (bed holds 100 full-word cells). Example: FIZZBUZZ N=100")}
{% endif %}
{% if z_draw < 0.15 %}
{action_raise_error("Z_DRAW is below 0.15 mm; refusing to scrape the bed.")}
{% endif %}
_FB_PREPARE HOME={home} COLD={cold} HOTEND={hotend} BED={bed} Z_DRAW={z_draw} Z_HOP={z_hop}
M118 FizzBuzz 1..{N} PLA+ single colour on 256x256
{% for n in range(1, N + 1) %}
_FB_CALC N={n}
_FB_CELL N={n} Z_DRAW={z_draw} Z_HOP={z_hop} COLD={cold}
{% endfor %}
_FB_FINISH COLD={cold} Z_HOP={z_hop}