/Games/Wooden Block Puzzle/WoodenBlock.foocad
Generates a puzzle piece for the classic "Wooden" Block puzzle. Take 6 pieces, and arrange them into a 3x3x3 cube.
See Generate.feather for a script which generates all the pieces. Note, you do not need a full set of pieces. 6 is all you need for a single puzzle.
See Solver.kts for a script which solves the puzzles, so that you can see if a combination of pieces has a solution and if so, how easy it is (the more solutions there are, the easier it is).
For a hard puzzle try pieces : P E T A I D Note, the "D" piece requires support material the others do not.
class WoodenBlock : AbstractModel() { // The name of the piece. These are the names which look a little like // the shape. They are NOT the letters that appear on the blocks. // Values ALL 1 2 3 V A I O E Y U S D P R T N L H B X W K J G M F C // See rename @Custom var piece = "1" // The size of the cube @Custom var size = 20 // Make the pieces slightly smaller, so that they fit together. @Custom var gap = 0.3 @Custom var radius = 2 // 1 for a chamfer, more than 1 for more rounding. @Custom var radiusSides = 3 @Custom var embossDepth = 1.2 @Custom var embossThicker = 0.2 // We want a "sphere", whose shadow is the same from either X, Y or Z direction. // A "normal" sphere won't do, as we cannot control the "sides" in the x, y and z. // So here we revolve a semi circle, where the number of sides of the semicircle // and number of sides of the revolution are the same. fun rounding() : Shape3d { //return Sphere( radius, radiusSides ) // A normal sphere won't do! return PolygonBuilder().apply { moveTo(0,-radius) lineTo(radius,-radius) lineTo(radius,radius) lineTo(0,radius) close() }.build() .roundCorner(2, radius, radiusSides ) .roundCorner(1, radius, radiusSides ) .revolve().sides(radiusSides*4) } // ghi // def // abc fun voxel( position: char ) : Shape3d { val lower = position.toLowerCase() val i = lower.toInt() - 'a'.toInt() val x = i % 3 val y = i ~/ 3 val z = if (position.isLowerCase()) 0 else 1 return Cube(size - gap - radius*2).translate( x*size, y*size, z*size ) } fun piece( info : String, color: String, letter : String ) : Shape3d { val pieces = listOf<Shape3d>() for (item in info.split(" ")) { val fromC = item.charAt(0) val toC = item.charAt(1) pieces.add( voxel(fromC).hull( voxel(toC ) ) ) 1 } val union = Union3d( pieces ) val result = union.minkowski( rounding() ).translate(radius, radius, radius ) val emboss = Text( letter, size * 0.65 ).hAlign(CENTER) .mirrorX() .offset( embossThicker ) .extrude( embossDepth ) .translate(size*1.5,size*0.2,-0.1) return result.color( color ) - emboss.color("White") } // ghi // def // abc fun piece( name : String ) : Shape3d { val small = "Silver" val four = "Red" val five = "Orange" val extra1 = "Yellow" val extra2 = "Green" if (name == "1") return piece( "bb", small, name ) if (name == "2") return piece( "ab", small, name ) if (name == "3") return piece( "ac", small, name ) if (name == "v") return piece( "ab be", small, name ) if (name == "A") return piece( "be ef fF", four, name ) if (name == "I") return piece( "ab be eE", four, name ) if (name == "O") return piece( "ab be ed da", four, name ) if (name == "E") return piece( "ac cf", four, name ) if (name == "Y") return piece( "ab be ef", four, name ) if (name == "U") return piece( "ac be", four, name ) if (name == "S") return piece( "ab ad aA", four, name ) if (name == "D") return piece( "cb be eE ED", five, name ) if (name == "R") return piece( "ac ad dD", five, name ) if (name == "P") return piece( "ac cf fF", five, name ) if (name == "T") return piece( "ca aA be", five, name ) if (name == "N") return piece( "ab be eE EF", five, name ) if (name == "L") return piece( "ca cC be", five, name ) if (name == "K") return piece( "df dg be", extra1, name ) if (name == "B") return piece( "ac de ad be", extra1, name ) if (name == "H") return piece( "bh df", extra1, name ) if (name == "W") return piece( "ac be bB", extra1, name ) if (name == "C") return piece( "da ac cf", extra1, name ) if (name == "J") return piece( "aA ac cf", extra2, name ) if (name == "G") return piece( "da ac cC", extra2, name ) if (name == "Z") return piece( "ab bh hi", extra2, name ) if (name == "M") return piece( "ab ad de eb aA", extra2, name ) if (name == "F") return piece( "ac cC cf", extra2, name ) return piece( "aa", "Silver", "." ) } override fun build() = piece( piece ) }