From 17f37677bf6cbb1241d6425decbebbf66f14df2b Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 20 Apr 2024 12:48:41 +0100 Subject: [PATCH] Fixed #709: Random basic data types --- .../scala/indigo/shared/datatypes/Point.scala | 23 ++++++++--- .../indigo/shared/datatypes/Radians.scala | 4 ++ .../indigo/shared/datatypes/Rectangle.scala | 13 +++++++ .../scala/indigo/shared/datatypes/Size.scala | 13 +++++++ .../indigo/shared/datatypes/Vector2.scala | 4 ++ .../indigo/shared/datatypes/Vector3.scala | 4 ++ .../indigo/shared/datatypes/Vector4.scala | 4 ++ .../scala/indigo/shared/geometry/Vertex.scala | 4 ++ .../shared/datatypes/PointSpecification.scala | 38 +++++++++++++++++++ .../datatypes/RadiansSpecification.scala | 15 ++++++++ .../shared/datatypes/SizeSpecification.scala | 38 +++++++++++++++++++ 11 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 indigo/indigo/src/test/scala/indigo/shared/datatypes/PointSpecification.scala create mode 100644 indigo/indigo/src/test/scala/indigo/shared/datatypes/RadiansSpecification.scala create mode 100644 indigo/indigo/src/test/scala/indigo/shared/datatypes/SizeSpecification.scala diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Point.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Point.scala index 233175cff..2ac560f8d 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Point.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Point.scala @@ -1,5 +1,6 @@ package indigo.shared.datatypes +import indigo.Dice import indigo.shared.geometry.Vertex final case class Point(x: Int, y: Int) derives CanEqual: @@ -51,7 +52,7 @@ final case class Point(x: Int, y: Int) derives CanEqual: def moveBy(x: Int, y: Int): Point = moveBy(Point(x, y)) - def rotateBy(angle: Radians): Point = { + def rotateBy(angle: Radians): Point = val a = angle.wrap.toDouble val s = Math.sin(a) val c = Math.cos(a) @@ -60,18 +61,17 @@ final case class Point(x: Int, y: Int) derives CanEqual: Math.round(this.x * c - this.y * s).toInt, Math.round(this.x * s + this.y * c).toInt ) - } + def rotateBy(angle: Radians, origin: Point): Point = (this - origin).rotateBy(angle) + origin - def rotateTo(angle: Radians): Point = { + def rotateTo(angle: Radians): Point = val a = angle.wrap.toDouble val r = this.distanceTo(Point.zero) Point( Math.round(r * Math.cos(a)).toInt, Math.round(r * Math.sin(a)).toInt ) - } def angle: Radians = Radians(Math.atan2(this.y, this.x)) @@ -102,7 +102,7 @@ object Point: Point(a.x + (((b.x - a.x) / divisor) * multiplier).toInt, a.y + (((b.y - a.y) / divisor) * multiplier).toInt) def distanceBetween(a: Point, b: Point): Double = - (a, b) match { + (a, b) match case (Point(x1, y1), Point(x2, y2)) if x1 == x2 => Math.abs((y2 - y1).toDouble) @@ -114,7 +114,6 @@ object Point: val bb = y2.toDouble - y1.toDouble Math.sqrt(Math.abs((aa * aa) + (bb * bb))) - } def fromSize(size: Size): Point = Point(size.width, size.height) @@ -130,3 +129,15 @@ object Point: x = (dividend.x % divisor.x + divisor.x) % divisor.x, y = (dividend.y % divisor.y + divisor.y) % divisor.y ) + + def random(dice: Dice, max: Int): Point = + Point(dice.rollFromZero(max), dice.rollFromZero(max)) + + def random(dice: Dice, max: Point): Point = + Point(dice.rollFromZero(max.x), dice.rollFromZero(max.y)) + + def random(dice: Dice, min: Int, max: Int): Point = + Point(dice.rollFromZero(max - min) + min, dice.rollFromZero(max - min) + min) + + def random(dice: Dice, min: Point, max: Point): Point = + Point(dice.rollFromZero(max.x - min.x) + min.x, dice.rollFromZero(max.y - min.y) + min.y) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Radians.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Radians.scala index ee2774de8..1c4221bfc 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Radians.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Radians.scala @@ -1,5 +1,6 @@ package indigo.shared.datatypes +import indigo.shared.dice.Dice import indigo.shared.time.Seconds import annotation.targetName @@ -30,6 +31,9 @@ object Radians: def mod(dividend: Radians, divisor: Radians): Radians = Radians((dividend % divisor + divisor) % divisor) + def random(dice: Dice): Radians = + TAU * dice.rollDouble + extension (r: Radians) def +(other: Radians): Radians = Radians(r + other) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Rectangle.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Rectangle.scala index c2ba3ccb0..a49dda005 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Rectangle.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Rectangle.scala @@ -1,6 +1,7 @@ package indigo.shared.datatypes import indigo.shared.collections.Batch +import indigo.shared.dice.Dice import indigo.shared.geometry.BoundingBox import indigo.shared.geometry.BoundingCircle @@ -262,3 +263,15 @@ object Rectangle: a.toBoundingBox.overlaps(b.toBoundingBox) def overlapping(a: Rectangle, b: Circle): Boolean = a.toBoundingBox.overlaps(b.toBoundingCircle) + + def random(dice: Dice, max: Int): Rectangle = + Rectangle(Point.random(dice, max), Size.random(dice, max)) + + def random(dice: Dice, max: Rectangle): Rectangle = + Rectangle(Point.random(dice, max.position), Size.random(dice, max.size)) + + def random(dice: Dice, min: Int, max: Int): Rectangle = + Rectangle(Point.random(dice, min, max), Size.random(dice, min, max)) + + def random(dice: Dice, min: Rectangle, max: Rectangle): Rectangle = + Rectangle(Point.random(dice, min.position, max.position), Size.random(dice, min.size, max.size)) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Size.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Size.scala index 8fe1ea5e7..dd076c55b 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Size.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Size.scala @@ -1,5 +1,6 @@ package indigo.shared.datatypes +import indigo.shared.dice.Dice import indigo.shared.geometry.Vertex final case class Size(width: Int, height: Int) derives CanEqual: @@ -80,3 +81,15 @@ object Size: width = (dividend.width % divisor.width + divisor.width) % divisor.width, height = (dividend.height % divisor.height + divisor.height) % divisor.height ) + + def random(dice: Dice, max: Int): Size = + Size(dice.rollFromZero(max), dice.rollFromZero(max)) + + def random(dice: Dice, max: Size): Size = + Size(dice.rollFromZero(max.width), dice.rollFromZero(max.height)) + + def random(dice: Dice, min: Int, max: Int): Size = + Size(dice.rollFromZero(max - min) + min, dice.rollFromZero(max - min) + min) + + def random(dice: Dice, min: Size, max: Size): Size = + Size(dice.rollFromZero(max.width - min.width) + min.width, dice.rollFromZero(max.height - min.height) + min.height) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector2.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector2.scala index a3df28051..044e77fe0 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector2.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector2.scala @@ -1,6 +1,7 @@ package indigo.shared.datatypes import indigo.shared.collections.Batch +import indigo.shared.dice.Dice import indigo.shared.geometry.Vertex final case class Vector2(x: Double, y: Double) derives CanEqual: @@ -192,3 +193,6 @@ object Vector2: x = (dividend.x % divisor.x + divisor.x) % divisor.x, y = (dividend.y % divisor.y + divisor.y) % divisor.y ) + + def random(dice: Dice): Vector2 = + Vector2(dice.rollDouble, dice.rollDouble) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector3.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector3.scala index ad5de56d5..bee53076c 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector3.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector3.scala @@ -1,6 +1,7 @@ package indigo.shared.datatypes import indigo.shared.collections.Batch +import indigo.shared.dice.Dice final case class Vector3(x: Double, y: Double, z: Double) derives CanEqual: @@ -158,3 +159,6 @@ object Vector3: y = (dividend.y % divisor.y + divisor.y) % divisor.y, z = (dividend.z % divisor.z + divisor.z) % divisor.z ) + + def random(dice: Dice): Vector3 = + Vector3(dice.rollDouble, dice.rollDouble, dice.rollDouble) diff --git a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector4.scala b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector4.scala index 99caa4123..4acc9e05f 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector4.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/datatypes/Vector4.scala @@ -1,6 +1,7 @@ package indigo.shared.datatypes import indigo.shared.collections.Batch +import indigo.shared.dice.Dice final case class Vector4(x: Double, y: Double, z: Double, w: Double) derives CanEqual: @@ -185,3 +186,6 @@ object Vector4: z = (dividend.z % divisor.z + divisor.z) % divisor.z, w = (dividend.w % divisor.w + divisor.w) % divisor.w ) + + def random(dice: Dice): Vector4 = + Vector4(dice.rollDouble, dice.rollDouble, dice.rollDouble, dice.rollDouble) diff --git a/indigo/indigo/src/main/scala/indigo/shared/geometry/Vertex.scala b/indigo/indigo/src/main/scala/indigo/shared/geometry/Vertex.scala index d83f42e34..e13b3524e 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/geometry/Vertex.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/geometry/Vertex.scala @@ -4,6 +4,7 @@ import indigo.shared.datatypes.Point import indigo.shared.datatypes.Radians import indigo.shared.datatypes.Size import indigo.shared.datatypes.Vector2 +import indigo.shared.dice.Dice /** A `Vertex` is another co-ordinate-like type that specifically represents a point on a graph. */ @@ -170,3 +171,6 @@ object Vertex: x = (dividend.x % divisor.x + divisor.x) % divisor.x, y = (dividend.y % divisor.y + divisor.y) % divisor.y ) + + def random(dice: Dice): Vertex = + Vertex(dice.rollDouble, dice.rollDouble) diff --git a/indigo/indigo/src/test/scala/indigo/shared/datatypes/PointSpecification.scala b/indigo/indigo/src/test/scala/indigo/shared/datatypes/PointSpecification.scala new file mode 100644 index 000000000..748caeee3 --- /dev/null +++ b/indigo/indigo/src/test/scala/indigo/shared/datatypes/PointSpecification.scala @@ -0,0 +1,38 @@ +package indigo.shared.datatypes + +import indigo.shared.dice.Dice +import org.scalacheck._ + +class PointSpecification extends Properties("Dice") { + + property("all random values are within the max range and >= 0") = Prop.forAll(Gen.choose(0, 500)) { max => + val dice = Dice.fromSeed(0) + val value = Point.random(dice, max) + + value.x >= 0 && value.y >= 0 && value.x <= max && value.y <= max + } + + property("all random values are within the max range (Point) and >= 0") = Prop.forAll(Gen.choose(0, 500)) { max => + val dice = Dice.fromSeed(0) + val value = Point.random(dice, Point(max)) + + value.x >= 0 && value.y >= 0 && value.x <= Point(max).x && value.y <= Point(max).y + } + + property("all random values are within the min / max range") = Prop.forAll(Gen.choose(-500, 0), Gen.choose(0, 500)) { + (min, max) => + val dice = Dice.fromSeed(0) + val value = Point.random(dice, min, max) + + value.x >= min && value.y >= min && value.x <= max && value.y <= max + } + + property("all random values are within the min / max range (Point)") = Prop.forAll(Gen.choose(-500, 0), Gen.choose(0, 500)) { + (min, max) => + val dice = Dice.fromSeed(0) + val value = Point.random(dice, Point(min), Point(max)) + + value.x >= Point(min).x && value.y >= Point(min).y && value.x <= Point(max).x && value.y <= Point(max).y + } + +} diff --git a/indigo/indigo/src/test/scala/indigo/shared/datatypes/RadiansSpecification.scala b/indigo/indigo/src/test/scala/indigo/shared/datatypes/RadiansSpecification.scala new file mode 100644 index 000000000..d27a590ee --- /dev/null +++ b/indigo/indigo/src/test/scala/indigo/shared/datatypes/RadiansSpecification.scala @@ -0,0 +1,15 @@ +package indigo.shared.datatypes + +import indigo.shared.dice.Dice +import org.scalacheck._ + +class RadiansSpecification extends Properties("Dice") { + + property("all random values are within the range of TAU / 2*PI") = Prop.forAll(Gen.long) { seed => + val dice = Dice.fromSeed(seed) + val value = Radians.random(dice) + + value.toDouble >= 0.0 && value.toDouble <= Radians.TAU.toDouble + } + +} diff --git a/indigo/indigo/src/test/scala/indigo/shared/datatypes/SizeSpecification.scala b/indigo/indigo/src/test/scala/indigo/shared/datatypes/SizeSpecification.scala new file mode 100644 index 000000000..f2bc6703f --- /dev/null +++ b/indigo/indigo/src/test/scala/indigo/shared/datatypes/SizeSpecification.scala @@ -0,0 +1,38 @@ +package indigo.shared.datatypes + +import indigo.shared.dice.Dice +import org.scalacheck._ + +class SizeSpecification extends Properties("Dice") { + + property("all random values are within the max range and >= 0") = Prop.forAll(Gen.choose(0, 500)) { max => + val dice = Dice.fromSeed(0) + val value = Size.random(dice, max) + + value.width >= 0 && value.height >= 0 && value.width <= max && value.height <= max + } + + property("all random values are within the max range (Size) and >= 0") = Prop.forAll(Gen.choose(0, 500)) { max => + val dice = Dice.fromSeed(0) + val value = Size.random(dice, Size(max)) + + value.width >= 0 && value.height >= 0 && value.width <= Size(max).width && value.height <= Size(max).height + } + + property("all random values are within the min / max range") = Prop.forAll(Gen.choose(-500, 0), Gen.choose(0, 500)) { + (min, max) => + val dice = Dice.fromSeed(0) + val value = Size.random(dice, min, max) + + value.width >= min && value.height >= min && value.width <= max && value.height <= max + } + + property("all random values are within the min / max range (Size)") = Prop.forAll(Gen.choose(-500, 0), Gen.choose(0, 500)) { + (min, max) => + val dice = Dice.fromSeed(0) + val value = Size.random(dice, Size(min), Size(max)) + + value.width >= Size(min).width && value.height >= Size(min).height && value.width <= Size(max).width && value.height <= Size(max).height + } + +}