Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
# casymo
# Casimo

### About the project
A sophisticated casino simulation built with Scala 3 and Scala.js, featuring realistic customer behavior, multiple casino games, and real-time data visualization.

### Live demo
A live demo can be found through the [repo GitHub's page](https://nickghignatti.github.io/casimo/)

### Documentation
All the documentation is accessible at the following link: [Casimo documentation](https://nickghignatti.github.io/casimo/docs)

### Local dev
Prerequisites
- JDK 17+
- Node.js 16+ (for Scala.js)
- sbt 1.10.11+

```shell
# Clone the repository
git clone https://github.com/nickghignatti/casimo.git
cd casimo

# Run the application
npm run dev
```

### Testing
```shell
# Run all tests
sbt "+backendJVM/test"

# Run with coverage
sbt "coverage; backendJVM/test; coverageReport"
```

### Code coverage

[![codecov](https://codecov.io/gh/NickGhignatti/casimo/branch/master/graph/badge.svg)](https://codecov.io/gh/NickGhignatti/casimo)
[![codecov](https://codecov.io/gh/NickGhignatti/casimo/branch/master/graph/badge.svg)](https://codecov.io/gh/NickGhignatti/casimo)

### License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

### Authors
- [Marco Galeri](https://github.com/Fre0Grella)
- [Nicolò Ghignatti](https://github.com/NickGhignatti)
- [Luca Patrignani](https://github.com/luca-patrignani)
81 changes: 81 additions & 0 deletions backend/src/main/scala/utils/Result.scala
Original file line number Diff line number Diff line change
@@ -1,29 +1,110 @@
package utils

/** A type representing either a successful value or an error.
*
* `Result[T, E]` is similar to `Either[E, T]` but with more intuitive naming
* where `T` represents the success type and `E` represents the error type.
* This is commonly used for error handling without exceptions.
*
* @tparam T
* the type of the success value
* @tparam E
* the type of the error value
* @example
* {{{ val success: Result[Int, String] = Result.Success(42) val failure:
* Result[Int, String] = Result.Failure("Something went wrong")
*
* val doubled = success.map(_ * 2) // Result.Success(84) val errorResult =
* failure.map(_ * 2) // Result.Failure("Something went wrong") }}}
*/
enum Result[+T, +E]:
/** Represents a successful result containing a value of type `T`.
*
* @param value
* the successful value
*/
case Success(value: T)

/** Represents a failed result containing an error of type `E`.
*
* @param error
* the error value
*/
case Failure(error: E)

/** Transforms the success value using the provided function, leaving failures
* unchanged.
*
* @param f
* the function to apply to the success value
* @tparam U
* the type of the transformed value
* @return
* a new Result with the transformed value if this is a Success, or the
* same Failure if this is a Failure
*/
def map[U](f: T => U): Result[U, E] = this match
case Success(value) => Success(f(value))
case Failure(error) => Failure(error)

/** Applies a function that returns a Result to the success value, flattening
* the result. This is useful for chaining operations that might fail.
*
* @param f
* the function to apply to the success value
* @tparam U
* the success type of the returned Result
* @tparam F
* the error type of the returned Result
* @return
* the result of applying f if this is a Success, or the same Failure if
* this is a Failure
*/
def flatMap[U, F](f: T => Result[U, F]): Result[U, E | F] = this match
case Success(value) => f(value)
case Failure(error) => Failure(error)

/** Returns the success value if this is a Success, otherwise returns the
* default value.
*
* @param default
* the value to return if this is a Failure
* @tparam U
* the type of the default value (must be a supertype of T)
* @return
* the success value or the default value
*/
def getOrElse[U >: T](default: U): U = this match
case Success(value) => value
case Failure(_) => default

/** Returns true if this Result is a Success, false otherwise.
*
* @return
* true if Success, false if Failure
*/
def isSuccess: Boolean = this match
case Success(_) => true
case Failure(_) => false

/** Returns true if this Result is a Failure, false otherwise.
*
* @return
* true if Failure, false if Success
*/
def isFailure: Boolean = !isSuccess

/** Companion object for Result containing utility methods and extensions.
*/
object Result:
extension [A](result: Result[A, A])
/** Converts a Result where both success and error types are the same to an
* Option. Success values are converted to Some, and Failure values are
* converted to None.
*
* @return
* Some(value) if Success, None if Failure
*/
def option(): Option[A] =
result match
case Result.Success(value) => Some(value)
Expand Down
124 changes: 124 additions & 0 deletions backend/src/main/scala/utils/Vector2D.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,154 @@ package utils

import scala.util.Random

/** A 2D vector with double precision coordinates.
*
* Represents a point or direction in 2D space with x and y components.
* Provides common vector operations including arithmetic, dot product,
* magnitude calculation, and normalization.
*
* @param x
* the x-coordinate component
* @param y
* the y-coordinate component
*/
case class Vector2D(x: Double, y: Double):

/** Adds two vectors component-wise.
*
* @param other
* the vector to add
* @return
* a new vector with the sum of corresponding components
*/
def +(other: Vector2D): Vector2D =
Vector2D(this.x + other.x, this.y + other.y)

/** Subtracts two vectors component-wise.
*
* @param other
* the vector to subtract
* @return
* a new vector with the difference of corresponding components
*/
def -(other: Vector2D): Vector2D =
Vector2D(this.x - other.x, this.y - other.y)

/** Multiplies the vector by a scalar value.
*
* @param scalar
* the scalar value to multiply by
* @return
* a new vector with both components scaled
*/
def *(scalar: Double): Vector2D = Vector2D(this.x * scalar, this.y * scalar)

/** Divides the vector by a scalar value.
*
* @param scalar
* the scalar value to divide by (should not be zero)
* @return
* a new vector with both components divided by the scalar
*/
def /(scalar: Double): Vector2D = Vector2D(this.x / scalar, this.y / scalar)

/** Computes the dot product of this vector with another vector.
*
* The dot product is useful for determining the angle between vectors and
* for projection calculations.
*
* @param other
* the other vector
* @return
* the dot product as a scalar value
*/
def dot(other: Vector2D): Double = this.x * other.x + this.y * other.y

/** Returns the negation of this vector (unary minus operator).
*
* @return
* a new vector with both components negated
*/
def unary_- : Vector2D = Vector2D(-this.x, -this.y)

/** Calculates the magnitude (length) of this vector.
*
* Uses the Euclidean distance formula: √(x² + y²)
*
* @return
* the magnitude as a non-negative double
*/
def magnitude: Double = Math.sqrt(x * x + y * y)

/** Returns a normalized version of this vector (unit vector).
*
* A normalized vector has magnitude 1.0 and points in the same direction. If
* this vector has zero magnitude, returns the same vector unchanged.
*
* @return
* a new vector with magnitude 1.0, or the original vector if magnitude is
* 0
*/
def normalize: Vector2D = if (magnitude == 0.0) this else this / magnitude

/** Generates a random vector within a square area around this vector.
*
* Creates a new vector where each component is randomly chosen within the
* range [this.component - radius, this.component + radius].
*
* @param radius
* the maximum distance from this vector's components
* @return
* a new random vector within the specified area
*/
def around(radius: Double): Vector2D = Vector2D(
Random.between(this.x - radius, this.x + radius),
Random.between(this.y - radius, this.y + radius)
)

/** Companion object for Vector2D containing utility methods and constants.
*/
object Vector2D:
/** The zero vector (origin point).
*
* A constant representing the vector with both components equal to 0.0.
*/
val zero: Vector2D = Vector2D(0.0, 0.0)

/** Creates a zero vector.
*
* Alternative constructor that returns the zero vector without parameters.
*
* @return
* the zero vector Vector2D(0.0, 0.0)
*/
def apply(): Vector2D = zero

/** Calculates the Euclidean distance between two vectors.
*
* Computes the magnitude of the difference vector between the two points.
*
* @param u
* the first vector
* @param v
* the second vector
* @return
* the distance between the vectors as a non-negative double
*/
def distance(u: Vector2D, v: Vector2D): Double =
(v - u).magnitude

/** Calculates the unit direction vector from one point to another.
*
* Returns a normalized vector pointing from the first vector to the second.
* If the vectors are the same, returns the zero vector.
*
* @param from
* the starting vector
* @param to
* the target vector
* @return
* a unit vector pointing from 'from' to 'to'
*/
def direction(from: Vector2D, to: Vector2D): Vector2D =
(to - from).normalize
Loading