multiplication_puzzle..scad
1 piece_side_length = 25; 2 // for n x n multiplication puzzle 3 n = 9; // [1:9] 4 spacing = 0.5; 5 6 same_height = "NO"; // [YES, NO] 7 height = 1; // workable when same_height is "YES" 8 9 module puzzle_piece(side_length, spacing) { 10 $fn = 48; 11 12 circle_radius = side_length / 10; 13 half_circle_radius = circle_radius / 2; 14 half_side_length = side_length / 2; 15 side_length_div_4 = side_length / 4; 16 bulge_circle_radius = circle_radius - spacing; 17 18 circle_x = half_circle_radius - half_side_length - spacing; 19 circle_y = side_length_div_4 - half_side_length; 20 circle_y2 = side_length_div_4 * 3 - half_side_length; 21 22 module df_circles() { 23 translate([circle_x, circle_y]) 24 circle(circle_radius); 25 translate([circle_x, circle_y2]) 26 circle(circle_radius); 27 } 28 29 module bulge_circles() { 30 translate([side_length + circle_x, circle_y]) 31 circle(bulge_circle_radius); 32 translate([side_length + circle_x, circle_y2]) 33 circle(bulge_circle_radius); 34 } 35 36 translate([half_side_length - spacing, half_side_length - spacing]) { 37 difference() { 38 square(side_length - spacing, center = true); 39 // left 40 df_circles(); 41 // top 42 rotate(-90) 43 df_circles(); 44 } 45 46 // right 47 bulge_circles(); 48 // bottom 49 rotate(-90) 50 bulge_circles(); 51 } 52 } 53 54 module puzzle_piece_with_text(side_length, text, spacing) { 55 half_side_length = side_length / 2; 56 57 difference() { 58 puzzle_piece(side_length, spacing); 59 translate([half_side_length, half_side_length]) 60 rotate(-45) 61 text(text, size = side_length / 3, halign = "center", valign = "center"); 62 } 63 } 64 65 module multiplication_puzzle(n, piece_side_length, spacing, same_height = false, height = 1) { 66 $fn = 48; 67 circle_radius = piece_side_length / 10; 68 half_circle_radius = circle_radius / 2; 69 side_length_div_4 = piece_side_length / 4; 70 n_minus_one = n - 1; 71 72 intersection() { 73 union() for(x = [0 : n_minus_one], y = [0 : n_minus_one]) { 74 pos = [piece_side_length * x, piece_side_length * y]; 75 r = (x + 1) * (y + 1); 76 linear_extrude(same_height ? height : r) union() { 77 translate(pos) 78 puzzle_piece_with_text(piece_side_length, str(r), spacing); 79 80 if(x == 0) { 81 x_offset = half_circle_radius - spacing * 2; 82 y_offset = piece_side_length * y - spacing; 83 translate([x_offset, side_length_div_4 + y_offset, 0]) 84 circle(circle_radius); 85 translate([x_offset, side_length_div_4 * 3 + y_offset, 0]) 86 circle(circle_radius); 87 } 88 if(y == n_minus_one) { 89 x_offset = piece_side_length * x - spacing; 90 y_offset = piece_side_length * (y + 1) - half_circle_radius; 91 translate([side_length_div_4 + x_offset, y_offset]) 92 circle(circle_radius); 93 translate([side_length_div_4 * 3 + x_offset, y_offset]) 94 circle(circle_radius); 95 96 } 97 } 98 linear_extrude((same_height ? height : r) - 0.6) 99 translate(pos) 100 puzzle_piece(piece_side_length, spacing); 101 } 102 103 linear_extrude(same_height ? height : n * n) 104 square(piece_side_length * n - spacing * 1.5); 105 } 106 } 107 108 multiplication_puzzle(n, piece_side_length, spacing, same_height == "YES", height);