Welcome to RichStrat, currently showcasing the planets with orbits shown to scale. The other pages use a number of different types of maps.

All the code is written in Scala. When displayed on the web this scala code is compiled to Javascript. However all the demonstations will also compile to Java byte code and work on the JavaFx graphical platfrom. I hope with my modest computing skills to demonstate the power and enjoyment of using Scala for simple games and every day adminstration of personal and small business tasks. At least for the time being I'm not going to give a full introduction to Scala, there are a number of good resources out there, but before I present any code I just want to draw attention to the four common basic types that I use in Scala coding and from which most other types are created.

Note that 7 is an Int. but "7" is a String. -8.22 is a Double, but "-8.22" is a String and false is a Boolean, but "false" is a String. I know this may sound a bit dry, a bit abstract, a bit boring even, but if you can grasp the above you really have cracked the foundations of computer programming. Which is a wonderful thing because now you can get computers to start working for you.

Petyr Baelish, Game of Thrones: When the Queen proclaims one king and the Hand proclaims another, whose peace do the Computers protect? Who do they follow? The man who programmes them.

Languages like Basic which you may have come across try to hide these concepts from you, but this leads to no end of trouble down the road for a small time saving at the begining which is why Scala is a way better language than Basic and its ilk. So here's my Vec2 class file. This is the foundation of the map algorithorithms. Note how it contains two data elements, two Doubles, two decimal values.

    
package rich
package geom
import math._

/** A 2 dimensional vector, can be used to represent 2 dimensional points and translations of 2 dimensional points */
final class Vec2 (val x: Double, val y: Double) extends PersistCompound with LineOrPt
{
   override def equals(other: Any): Boolean = other match
   {
      case Vec2(px, py) => (x =~ px) && (y =~ py)
      case _ => false
   }
   override def toString = "x: " - x.toString - ", y: " - y.toString
   def str1: String = "x: " - x.str1 - ", y: " - y.str1
   def toPair: (Double, Double) = (x, y)
   def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)
   def addXY (otherX: Double, otherY: Double): Vec2 = Vec2(x + otherX, y + otherY)
   def subXY (otherX: Double, otherY: Double): Vec2 = Vec2(x - otherX, y - otherY)
   def -(other: Vec2): Vec2 = Vec2(x - other.x, y - other.y)
   def unary_- : Vec2 = Vec2(-x, -y)
   def *(factor: Double): Vec2 = Vec2(x * factor, y * factor)
   def /(divisor: Double): Vec2 = Vec2(x / divisor, y / divisor)
   def addX(adj: Double): Vec2 = Vec2(x + adj, y)
   def addY(adj: Double): Vec2 = Vec2(x, y + adj)
   def subX(adj: Double): Vec2 = Vec2(x - adj, y)   
   def subY(adj: Double): Vec2 = Vec2(x, y - adj)
   def scaleY(factor: Double): Vec2 = Vec2(x, y * factor)
   def mirrorX: Vec2 = Vec2(-x, y)
   def mirrorY: Vec2 = Vec2(x, -y)
   override def persistMems: Seq[Persist] = Seq(x, y)
   override def persistName: String = "Vec2"   
   /* Reverses the y coordinate. Useful for translating between canvases where the y axis measures down and coordinate systems where y is up */
   def inverseY: Vec2 = Vec2(x, -y)
   def toTuple: Tuple2[Double, Double] = (x, y)
   def vecLength = math.sqrt(x * x + y * y)
   def vecAngle: Angle =
   {
      def get(x: Double, y: Double): Double = ife(x < 0.00000001, Pi / 2, atan(y / x))
      val r = x match
      {
         case x if x < 0 & y < 0 => get(x, y) + Pi 
         case x if x < 0 => Pi - get(x, y)
         case _ => get(x, y)
      }
      Angle(r)
   }
   def distanceFrom(other: Vec2): Double = math.sqrt({val dim = (x - other.x); dim * dim} + {val dim = (y - other.y); dim * dim})
   def rectVerts(width: Double, height: Double): Seq[Vec2] =
   {
      val ax = width / 2
      val ay = height / 2
      Seq(Vec2(x - ax, y + ay), Vec2(x + ax, y + ay), Vec2(x + ax, y -ay), Vec2(x -ax, y -ay))
   }
   def withinRect(target: Vec2, width: Double, height: Double): Boolean =
   {
      val xd: Double = width / 2
      val yd: Double = height / 2
      (x > target.x - xd) && (x < target.x + xd) && (y > target.y - yd) && (y < target.y + yd)
   }   
   def rotate(angle: Angle): Vec2 = angle.radians match
   {
     case 0 => Vec2.this
     case a => Vec2(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a))
   }
  
   //def trans(aff: AffD2): Vec2 = aff(this)
   def centreSquare(length: Double): Vec2S =
   {
      val r = length / 2.0
      Seq(addXY(-r, r), addXY(r, r), addXY(r, -r), addXY(-r, -r)) 
   }
   override def numOfPts = 1
   override def seqOfPts: Vec2S = Vec2S.xy(x, y)
   def fillText(str: String, fontSize: Int, fontColour: Colour = Colour.Black) = FillText(this, str, fontSize, fontColour)
}

object Vec2
{
   def apply(x: Double, y: Double): Vec2 = new Vec2(x, y)
   def unapply(orig: Vec2): Option[(Double, Double)] = Some((orig.x, orig.y))
//   def fromDoubles(elems: Double*): Seq[Vec2] =
//   {      
//      def loop(rem: Seq[Double], acc: Seq[Vec2]): Seq[Vec2] = rem match
//      {
//         case Seq() => acc
//         case Seq(x, y, tail @ _*) => loop(tail, acc :+ Vec2(x, y))
//      }
//      if (elems.length.isOdd) excep("Odd number of Doubles passed to Vec2 Seq constructor")
//      loop(elems, Seq())
//   }
   //def zero: Vec2 = new Vec2(0, 0)
   def circlePt(angle: Double): Vec2 = Vec2(cos(angle), sin(angle))
   def circlePtClockwise(angle: Double): Vec2 = Vec2(cos(angle), - sin(angle))
   def gets(coods: Double *): Array[Vec2] =
   {
      (for ( i <- 0 until coods.length / 2) yield Vec2(coods(i * 2), coods(i * 2 + 1))).toArray
   }
   def rectBL(left: Double, bottom: Double, width: Double, height: Double): Array[Vec2] =
      Array[Vec2](Vec2(left, bottom), Vec2(left, bottom + height), Vec2(left + width, bottom + height), Vec2(left + width, bottom))
   def squareBL(left: Double, bottom: Double, length: Double): Array[Vec2] =
      Array[Vec2](Vec2(left, bottom), Vec2(left, bottom + length), Vec2(left + length, bottom + length), Vec2(left + length, bottom))   
   
   implicit class ImpVec2Srray(arr: Array[Vec2])
   {
      def +++ (offset: Vec2): Array[Vec2] = arr.map(_ + offset)
      def xy_+ (xOff: Double, yOff: Double): Array[Vec2] = arr.map(orig => Vec2(orig.x + xOff, orig.y + yOff))
      def --- (offset: Vec2): Array[Vec2] = arr.map(_ - offset)
      def *** (factor: Double): Array[Vec2] = arr.map(_ * factor)
      def a_*+ (factor: Double, offset: Vec2): Array[Vec2] = arr.map(_ * factor + offset)
      def a_+* (offset: Vec2, factor: Double): Array[Vec2] = arr.map(i => (i + offset) * factor)
      def xy_*+ (factor: Double, xOff: Double, yOff: Double): Array[Vec2] = arr.map(_ * factor + Vec2(xOff, yOff))
      def a_+* (xOff: Double, yOff: Double, factor: Double): Array[Vec2] = arr.map(i => (i + Vec2(xOff, yOff)) * factor)
   }
   
   import scala.collection._   
   
   implicit class ImpVec2Traversible[Repr](travLike: TraversableLike[Vec2, Repr])
   {
      /** Translates each Vec2 member of collection equivalent to trav.map(_ + offset) */
      def +++ (offset: Vec2)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += x + offset
         b.result
      }
      /** Translates each Vec2 member of collection equivalent to trav.map(_ + Vec2(xOff, yOff) */
      def slate (xOff: Double, yOff: Double)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (orig <- travLike) b += Vec2(orig.x + xOff, orig.y + yOff)
         b.result
      }
      
      def --- (offset: Vec2)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += x - offset
         b.result
      }
      
      def *** (factor: Double)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += x * factor
         b.result
      }
      
      def a_*+ (factor: Double, offset: Vec2)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += x * factor + offset
         b.result
      }
      def a_+* (offset: Vec2, factor: Double)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += (x + offset) * factor
         b.result
      }
      
      def rotate (angle: Angle)(implicit bf: generic.CanBuildFrom[Repr, Vec2, Repr]): Repr =
      {
         def builder =
         { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
            val b = bf(travLike.repr)
            b.sizeHint(travLike)
            b
         }
         val b = builder
         for (x <- travLike) b += (x.rotate(angle))
         b.result
      }
      
      
      
      
   }
  implicit object Vec2PBuilder extends PBuilder2[Vec2, Double, Double]
  {
     override def persistType = "Vec2"
     override def isType(obj: Any): Boolean = obj.isInstanceOf[Vec2]
     override def apply = Vec2.apply  
  }
  
  implicit class Vec2SeqImplicit(thisSeq: Vec2S) extends Transable[Vec2S]
  {
     def fTrans(f: Vec2 => Vec2): Vec2S = thisSeq.map(f)

   /** Creates a bounding rectangle for a collection of 2d points */
   def boundingRect: BoundingRect =
   {
      var minX, maxX = thisSeq(0).x
      var minY, maxY = thisSeq(0).y      
      thisSeq.tail.foreach(v =>
         {           
            minX = minX.min(v.x)
            maxX = maxX.max(v.x)
            minY = minY.min(v.y)
            maxY = maxY.max(v.y)           
            
         })         
      BoundingRect(minX, maxX, minY, maxY)               
   }
   def boundingWidth: Double = boundingRect.width
   def boundingHeight: Double = boundingRect.height   
   def polyCentre: Vec2 = boundingRect.cen
   import Colour.Black
   def fill(colour: Colour): FillPoly = FillPoly(thisSeq, colour)
   def draw(lineWidth: Double, lineColour: Colour = Black): DrawPoly = DrawPoly(thisSeq, lineWidth, lineColour)
   def fillDraw(fillColour: Colour, lineWidth: Double = 1.0, lineColour: Colour = Black): FillDrawPoly =
      FillDrawPoly(thisSeq, fillColour, lineWidth, lineColour)
   def fillDrawText(fillColour: Colour, lineWidth: Double, lineColour: Colour, str: String, fontSize: Int, fontColour: Colour = Black) = 
      FillDrawTextPoly(thisSeq, fillColour, lineWidth, lineColour, str, fontSize, fontColour)
   def fillText(fillColour: Colour, str: String, fontSize: Int, fontColour: Colour = Black) =
      FillTextPoly(thisSeq, fillColour, str, fontSize, fontColour)   
   def drawText(lineWidth: Double, lineColour: Colour, str: String, fontSize: Int, fontColour: Colour = Black) = 
      DrawTextPoly(thisSeq, lineWidth, lineColour, str, fontSize, fontColour)   
   def fillSubj(evObj: Any, fillColour: Colour): PolySubj = PolySubj.fill(thisSeq.polyCentre, thisSeq, evObj, fillColour)
   def fillDrawSubj(evObj: Any, fillColour: Colour, lineWidth:  Double, lineColour: Colour = Black): PolySubj =
      PolySubj.fillDraw(thisSeq.polyCentre, thisSeq, evObj, fillColour, lineWidth, lineColour)
    def drawSubj(evObj: Any, lineWidth:  Double, lineColour: Colour = Black): PolySubj =
      PolySubj.draw(thisSeq.polyCentre, thisSeq, evObj, lineWidth, lineColour)  
   def fillTextSubj(evObj: Any, fillColour: Colour, str: String, fontSize: Int = 10, textColour: Colour = Black): PolySubj =
      PolySubj.fillText(thisSeq.polyCentre, thisSeq, evObj, fillColour, str, fontSize, textColour)
   def fillContrastTextSubj(evObj: Any, fillColour: Colour, str: String, fontSize: Int = 10): PolySubj =
      fillTextSubj(evObj, fillColour, str, fontSize, fillColour.colourContrast)  
   def subj(evObj: Any, elems: CanvEl[_]*): PolySubj = new PolySubj(thisSeq.polyCentre, thisSeq, evObj, elems)
   def subjSeq(evObj: Any, elems: Seq[CanvEl[_]]): PolySubj = new PolySubj(thisSeq.polyCentre, thisSeq, evObj, elems)
   def toPairs: Seq[(Double, Double)] = thisSeq.map(v => (v.x, v.y))
   def forPairs[U](f: (Double, Double) => U): Unit = thisSeq.foreach(v => f(v.x, v.y))
   def fHeadPair[A](f: (Double, Double) => A): A = f(thisSeq.head.x, thisSeq.head.y)
   def forTailPairs[U](f: (Double, Double) => U): Unit = thisSeq.tail.foreach(v => f(v.x, v.y))
   //def objFrom(obj: Any): Vec2 => Option[Any] = 
//   implicit class SeqVec2Implicit(vSeq: Seq[Vec2]) extends Transable[Seq[Vec2]]
//   {
//      def fTranslate(f: Vec2 => Vec2): Seq[Vec2] = vSeq.map(f)
//      def objFrom(obj: Any): Vec2 => Option[Any] = pt => ptInPolygon(pt)(Some(obj), None)
//      
      def ptInPolygon(pt: Vec2): Boolean = 
      { //Checks whether a forward horizontal ray crosses this polygon side      
         val rayIntersections: Seq[Line2] = Line2.SeqFromPts(thisSeq).filter(ls => 
         //Checks whether a forward horizontal ray crosses this polygon side
            if ( 
                //Check if point is above or below the polygon side
               ((pt.y > ls.y1) && (pt.y > ls.y2)) || //above pnt1 and pnt2
               ((pt.y < ls.y1) && (pt.y < ls.y2)) //below pnt1 and pnt 2
            ) false
            else 
            {
               val deltaY = ls.y2 - ls.y1
               if (0.000001 > deltaY.abs) false //if the polygon side is close to horizontal the
// point is close enough to the perimeter of the polygon that the point can measured as outside
               else
               {
                  val ptDeltaY = pt.y - ls.y1
                  val deltaX = ls.x2 - ls.x1
                  val lineX = ls.x1 + (deltaX * ptDeltaY / deltaY)
                  pt.x > lineX
               }
            })        
         rayIntersections.length % 2 == 1 //For a convex polygon the ray can only cross one side if inside
      }

//   implicit class ImplicitVec2SeqSeq(thisSeqSeq: Seq[Seq[Vec2]])
//   {
//      def fill(colour: Colour): Seq[FillPoly] = thisSeqSeq.map(s => FillPoly(s, colour))
//      //def fillSubj(evObj: Any, colour: Colour): PolySubj = PolySubj.fill(vSeq, evObj, colour)
   }
}