Share
Explore

Unitied Earth Space Defense Force

Lecture lab book for the Kotlin-based UESEC Fleet Combat Simulation, focusing on synthetic integration using Companion Object factory methods and the Singleton Design Pattern.
This lab emphasizes object-oriented design principles while aligning with the assignment requirements. It provides a structured walkthrough with explanations and complete code to guide students through building a space battle simulation.

Lecture Lab Book: United Earth Space Defense Command Fleet Operations Combat Simulation ​
image.png

Lab Title: Modeling Space Battles with Kotlin - Companion Objects and Singletons

In this lab, you’ll design and implement a Kotlin-based simulation of a space battle between Federation and Romulan fleets, as part of your assignment for the United Earth Space Defense Command Fleet Operations Combat Simulation. The primary focus is to demonstrate synthetic integration—the seamless collaboration of multiple classes through method calls and shared field composition—while leveraging Kotlin’s Companion Object factory methods and the Singleton Design Pattern.

By the end of this lab, you’ll have a working combat simulation that:

Uses Companion Objects as factory methods to create spaceship instances.
Employs a Singleton to manage the combat simulation globally.
Integrates classes via method calls and shared data to simulate fleet battles.
This lab aligns with the UESEC simulation assignment and emphasizes object-oriented principles such as encapsulation, polymorphism, and modular design.

Learning Objectives

Understand and implement Companion Objects as factory methods to instantiate objects with controlled creation logic.
Apply the Singleton Design Pattern to manage a single, globally accessible combat simulation instance.
Demonstrate synthetic integration by connecting multiple classes (e.g., Starship, Fleet, CombatManager) through method calls and shared fields.
Simulate a space battle with randomized attack selections, energy management, and fleet status updates.
Reinforce Kotlin concepts: classes, mutable lists, randomization, and control structures.

Lab Prerequisites

Basic understanding of Kotlin syntax (classes, objects, loops, conditionals).
Familiarity with object-oriented programming (OOP) concepts.
Access to a Kotlin development environment (e.g., IntelliJ IDEA).

Lab Structure


Conceptual Overview: Introduction to Companion Objects and Singletons.
Class Design: Define the core classes with UML-inspired relationships.
Implementation: Step-by-step coding with explanations.
Execution: Run and test the simulation.
Reflection: Analyze the design and suggest improvements.

1. Conceptual Overview

Companion Objects as Factory Methods

In Kotlin, a companion object is a static-like construct within a class that can hold methods and properties tied to the class itself, not its instances.

We’ll use it as a factory method to:
Encapsulate ship creation logic.
Assign unique identifiers or initial configurations to each Starship.
Ensure consistency in how objects are instantiated.

Singleton Design Pattern

The Singleton pattern ensures a class has only one instance, providing a global point of access. Here, we’ll use it for the CombatManager to:

Centralize battle simulation logic.

Maintain a single source of truth for the simulation state.
Coordinate interactions between fleets.

Synthetic Integration

This lab integrates several classes:

Starship: Represents individual ships with energy levels and attack methods.

Fleet: Manages a collection of ships using a mutable list.

CombatManager: A Singleton that orchestrates the battle, selecting attackers and defenders, applying damage, and reporting status.
These classes will collaborate through method calls and shared field updates, showcasing a cohesive, purpose-driven design.

2. Class Design

UML-Inspired Relationships

image.png
Starship: Core entity with energy properties and attack/defense behaviors. Uses a Companion Object factory.

Fleet: Aggregates Starship instances, providing methods to manage the collection.

CombatManager: Singleton that drives the simulation, interacting with both fleets.

3. Implementation

Step 1: Define the Starship Class with Companion Object


import kotlin.random.Random
class Starship private constructor(
val name: String,
var shields: Int,
var phasers: Int,
var torpedoes: Int
) {
companion object Factory {
// Factory method to create Federation ships
fun createFederationShip(name: String): Starship {
return Starship(name, shields = 100, phasers = 80, torpedoes = 60)
}


// Factory method to create Romulan ships with different energy profiles
fun createRomulanShip(name: String): Starship {
return Starship(name, shields = 95, phasers = 75, torpedoes = 65)
}

}


fun firePhaser(target: Starship) {
if (phasers >= 15) {
println("$name fires Phaser at ${target.name}")
target.takeDamage(15)
phasers -= 10
} else {
println("$name has insufficient phaser energy!")
}

}


fun fireTorpedo(target: Starship) {
if (torpedoes >= 20) {
println("$name fires Photon Torpedo at ${target.name}")
target.takeDamage(25)
torpedoes -= 20
} else {
println("$name has insufficient torpedo energy!")
}

}


fun takeDamage(damage: Int) {
shields -= damage
println("Hit! Damage=$damage. ${name}'s shields now at $shields")
if (shields <= 0) println("$name has been destroyed!")
}


fun isDestroyed() = shields <= 0

override fun toString() = "$name: Shields=$shields, Phasers=$phasers, Torpedoes=$torpedoes"
}
Explanation:
The companion object Factory provides two factory methods to create ships with predefined energy levels, enforcing consistency.

Methods like firePhaser and fireTorpedo simulate attacks, deducting energy and applying damage via method calls to the target ship.

Step 2: Define the Fleet Class


class Fleet(val name: String) {
private val ships = mutableListOf<Starship>()

fun addShip(ship: Starship) {
ships.add(ship)

}


fun removeShip(ship: Starship) {
ships.remove(ship)

}


fun getRandomShip(): Starship? {
return if (ships.isNotEmpty()) ships[Random.nextInt(ships.size)] else null
}


fun isEliminated() = ships.isEmpty()

fun statusReport() {
println("$name Fleet Status:")
ships.forEach { println(" $it") }
}


fun removeDestroyedShips() {
ships.removeIf { it.isDestroyed() }

}

}
Explanation:
Fleet uses a MutableList to store ships, supporting dynamic fleet management.

getRandomShip uses Kotlin’s Random to select a ship, enabling randomized combat interactions.

Step 3: Define the CombatManager Singleton



object CombatManager {
private lateinit var federationFleet: Fleet
private lateinit var romulanFleet: Fleet
private var round = 0

fun initializeSimulation() {
federationFleet = Fleet("Federation")
romulanFleet = Fleet("Romulan")

// Populate Federation fleet using factory methods
federationFleet.addShip(Starship.createFederationShip("USS Enterprise"))
federationFleet.addShip(Starship.createFederationShip("USS Excelsior"))
federationFleet.addShip(Starship.createFederationShip("USS Defiant"))

// Populate Romulan fleet
romulanFleet.addShip(Starship.createRomulanShip("IRW Khazara"))
romulanFleet.addShip(Starship.createRomulanShip("IRW T'Met"))
romulanFleet.addShip(Starship.createRomulanShip("IRW Belak"))

println("UESEC Combat Simulation Initialized")
println("===================================")
reportStatus()

}


fun doCombatRound() {
round++
println("\nRound $round\n=========")

// Federation attacks Romulan
val fedShip = federationFleet.getRandomShip()
val romShip = romulanFleet.getRandomShip()
if (fedShip != null && romShip != null) {
val attackType = Random.nextBoolean()
if (attackType) fedShip.firePhaser(romShip) else fedShip.fireTorpedo(romShip)
}


// Romulan attacks Federation
val romAttacker = romulanFleet.getRandomShip()
val fedTarget = federationFleet.getRandomShip()
if (romAttacker != null && fedTarget != null) {
val attackType = Random.nextBoolean()
if (attackType) romAttacker.firePhaser(fedTarget) else romAttacker.fireTorpedo(fedTarget)
}

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.