/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 )
}

