AnalogueCuboid.scala

package net.snowtiger.analogue

import java.lang.StringBuilder

/**
 * An AnalogueCuboid provides a way of creating a triplet of natural numbers
 * (width, height, depth) using a pictographic representation.
 * See http://snowtiger.net/scala/analogue for a complete article on the subject.
 *
 * Note that the base class companion object must be imported
 * (using import AnalogueLiteral._) in order to use the required constants and
 * implicit type conversions.
 *
 * @author Mark B Davies
 */
class AnalogueCuboid(x: Int, y: Int, z: Int) extends  AnalogueLiteral
{
	val width = floor(x)
	val height = floor(y)
	val depth = floor(z)

	def volume = width*height*depth

	override def equals(obj: Any) =
	{
		obj match
		{
			case other:AnalogueCuboid =>
				width==other.width && height==other.height && depth==other.depth
			case _ => false
		}
	}

	def top = new AnalogueRectangle(width, depth)
	def side = new AnalogueRectangle(depth, height)
	def front = new AnalogueRectangle(width, height)

	// Cube construction
	def incDepth() = new AnalogueCuboid(width, height, depth+1)
	def \(other: AnalogueLine) = incDepth()
	def \!(other: AnalogueLine) = incDepth()
	def \+(other: AnalogueLine) = incDepth()

	def |(other: AnalogueCuboid) =
		new AnalogueCuboid(width, height+other.height+1, other.depth)
	def |+(other: AnalogueCuboid) =
		new AnalogueCuboid(width, height+other.height+1, other.depth)
	def |!(other: AnalogueCuboid) =
		new AnalogueCuboid(width, height+other.height+1, other.depth)

	def !(other: AnalogueLine) = incDepth()
	def !~(other: AnalogueLine) = incDepth()
	def !~~(other: AnalogueLine) = incDepth()
	def !~~~(other: AnalogueLine) = incDepth()
	def !~~~~(other: AnalogueLine) = incDepth()
	def !~~~~~(other: AnalogueLine) = incDepth()
	def !~~~~~~(other: AnalogueLine) = incDepth()
	def !~~~~~~~(other: AnalogueLine) = incDepth()
	def !~~~~~~~~(other: AnalogueLine) = incDepth()
	def !~~~~~~~~~(other: AnalogueLine) = incDepth()

	def ~(other: AnalogueLine) = this
	def ~~(other: AnalogueLine) = this
	def ~~~(other: AnalogueLine) = this
	def ~~~~(other: AnalogueLine) = this
	def ~~~~~(other: AnalogueLine) = this
	def ~~~~~~(other: AnalogueLine) = this
	def ~~~~~~~(other: AnalogueLine) = this
	def ~~~~~~~~(other: AnalogueLine) = this
	def ~~~~~~~~~(other: AnalogueLine) = this

	// Arithmetic operations on cuboids
	def +(other: AnalogueCuboid) =
		new AnalogueCuboid(width+other.width, height+other.height, depth+other.depth)
	def +(other: Int) = new AnalogueCuboid(width+other, height+other, depth+other)
	def *(other: Int) = new AnalogueCuboid(width*other, height*other, depth*other)

	def sizeString =
	{
		"("+width+"x"+height+"x"+depth+")=" + volume
	}

	def pictureString =
	{
		val lineString = new AnalogueLine(width).pictureString();
		val s = new StringBuilder(lineString)
		s.append("\n")

		var i = 1
		// Outputs lines of format: |  +     L
		while (i < depth.min(height+1))
		{
			s.append("|").append(" "*(i-1)).append("+")
			s.append(" "*(width-1)).append("L\n")
			i+= 1
		}

		var j = 1
		// Outputs lines of format:   \  +     L
		while (i < depth)
		{
			s.append(" "*j).append("\\").append(" "*(height-1))
			s.append("+").append(" "*(width-1)).append("L\n")
			i+= 1; j+= 1
		}

		// Outputs middle line, \  O~~~I  or   |  O~~~I
		if (i < height+1)
		{
			s.append("|").append(" "*(depth-1))
		}
		else
		{
			s.append(" "*j).append("\\").append(" "*(height-1))
			j+= 1
		}
		s.append(lineString).append("\n")
		i+= 1

		// Outputs lines of format:   |    !     I
		while (i < height+1)
		{
			s.append("|").append(" "*(depth-1)).append("!")
			s.append(" "*(width-1)).append("I\n")
			i+= 1
		}

		// Outputs lines of format:   \  !     I
		while (i < depth+height)
		{
			s.append(" "*j).append("\\").append(" "*(depth-j-1))
			s.append("!").append(" "*(width-1)).append("I\n")
			i+= 1; j+= 1
		}

		s.append(" "*j).append("!").append(lineString.substring(1))
		s.toString
	}

}