diff --git a/src/Body.java b/src/Body.java index 6a37e5b..9772392 100644 --- a/src/Body.java +++ b/src/Body.java @@ -53,6 +53,10 @@ public class Body { return SpaceDraw.massToRadius(mass); } + public double mass() { + return mass; + } + // Returns a new body that is formed by the collision of this body and 'b'. The impulse // of the returned body is the sum of the impulses of 'this' and 'b'. public Body merge(Body b) { diff --git a/src/BodyForceMap.java b/src/BodyForceMap.java index ab12eeb..5f4d67f 100644 --- a/src/BodyForceMap.java +++ b/src/BodyForceMap.java @@ -3,21 +3,55 @@ // public class BodyForceMap { - //TODO: declare variables. + private int size = 0; + private int capacity; + private Body[] keys; + private Vector3[] values; + + public BodyForceMap() { + this(4); + } // Initializes this map with an initial capacity. // Precondition: initialCapacity > 0. public BodyForceMap(int initialCapacity) { - - //TODO: define constructor. + this.capacity = initialCapacity; + this.keys = new Body[this.capacity]; + this.values = new Vector3[this.capacity]; } // Adds a new key-value association to this map. If the key already exists in this map, // the value is replaced and the old value is returned. Otherwise 'null' is returned. // Precondition: key != null. public Vector3 put(Body key, Vector3 force) { + if (size == capacity) { + doubleCapacity(); + } - //TODO: implement method. + int left = 0; + int right = size - 1; + while (left <= right) { + int middle = left + (right - left) / 2; + if (keys[middle] == key) { + Vector3 v = values[middle]; + values[middle] = force; + return v; + } else if (keys[middle].mass() < key.mass()) { + right = middle - 1; + } else { + left = middle + 1; + } + } + + int insert = right + 1; + + for (int i = size; i > insert; i--) { + keys[i] = keys[i - 1]; + values[i] = values[i - 1]; + } + size++; + keys[insert] = key; + values[insert] = force; return null; } @@ -25,8 +59,52 @@ public class BodyForceMap { // associated with the specified body. Returns 'null' if the key is not contained in this map. // Precondition: key != null. public Vector3 get(Body key) { + int left = 0; + int right = size - 1; + + while (left <= right) { + int middle = left + ((right - left) / 2); + int middleLeft = left + (middle - left) / 2; + int middleRight = middle + (right - middle) / 2; + + if (keys[middle] == key) { + return values[middle]; + } + + if (keys[middleLeft].mass() == keys[middle].mass()) { + for (int i = middleLeft; i < middle; i++) { + if (keys[i] == key) + return values[i]; + } + } + if (keys[middle].mass() == keys[middleRight].mass()) { + for (int i = middle; i < middleRight; i++) { + if (keys[i] == key) + return values[i]; + } + } + + if (keys[middle].mass() < key.mass()) { + right = middle - 1; + } else { + left = middle + 1; + } + } - //TODO: implement method. return null; } + + private void doubleCapacity() { + capacity *= 2; + Body[] tmpKeys = new Body[capacity]; + Vector3[] tmpValues = new Vector3[capacity]; + + for (int i = 0; i < size; i++) { + tmpKeys[i] = keys[i]; + tmpValues[i] = values[i]; + } + + keys = tmpKeys; + values = tmpValues; + } } diff --git a/src/BodyQueue.java b/src/BodyQueue.java index f40d41e..10dd685 100644 --- a/src/BodyQueue.java +++ b/src/BodyQueue.java @@ -5,13 +5,20 @@ // public class BodyQueue { - //TODO: declare variables. + private int capacity; + private int head = 0; + private int tail = 0; + private Body[] queue; + + public BodyQueue() { + this(4); + } // Initializes this queue with an initial capacity. // Precondition: initialCapacity > 0. public BodyQueue(int initialCapacity) { - - //TODO: define constructor. + this.capacity = initialCapacity; + this.queue = new Body[this.capacity]; } // Initializes this queue as an independent copy of the specified queue. @@ -19,28 +26,50 @@ public class BodyQueue { // and vice versa. // Precondition: q != null. public BodyQueue(BodyQueue q) { - - //TODO: define constructor. + this.capacity = q.capacity; + this.head = q.size(); + this.tail = 0; + this.queue = new Body[this.capacity]; + for (int i = 0; i < q.size(); i++) { + this.queue[i] = q.queue[i]; + } } // Adds the specified body 'b' to this queue. public void add(Body b) { - - //TODO: implement method. + queue[head] = b; + head = (head + 1) % capacity; + if (head == tail) { + doubleCapacity(); + head = capacity / 2; + } } // Retrieves and removes the head of this queue, or returns 'null' // if this queue is empty. public Body poll() { - - //TODO: implement method. - return null; + if (tail == head) { + return null; + } + Body b = queue[tail]; + queue[tail] = null; + tail = (tail + 1) % capacity; + return b; } // Returns the number of bodies in this queue. public int size() { + return (head - tail + capacity) % capacity; + } - //TODO: implement method. - return -1; + private void doubleCapacity() { + Body[] tmp = new Body[capacity * 2]; + for (int i = head, j = 0; i < tail + capacity; i++, j++) { + tmp[j] = queue[i % capacity]; + } + head = capacity; + tail = 0; + capacity *= 2; + queue = tmp; } } diff --git a/src/Simulation.java b/src/Simulation.java index 8cc8449..ddb2094 100644 --- a/src/Simulation.java +++ b/src/Simulation.java @@ -41,14 +41,14 @@ public class Simulation { public static void main(String[] args) { // simulation CodeDraw cd = new CodeDraw(); - Body[] bodies = new Body[NUMBER_OF_BODIES]; - Vector3[] forceOnBody = new Vector3[bodies.length]; + BodyQueue bodies = new BodyQueue(); + BodyForceMap forceOnBody = new BodyForceMap(); Random random = new Random(2022); - for (int i = 0; i < bodies.length; i++) { - bodies[i] = new Body( - Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length, // kg + for (int i = 0; i < NUMBER_OF_BODIES; i++) { + bodies.add(new Body( + Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / NUMBER_OF_BODIES, // kg new Vector3( 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, @@ -59,15 +59,21 @@ public class Simulation { 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3 ) - ); + )); } double seconds = 0; // simulation loop while (true) { + BodyQueue newBodies = new BodyQueue(bodies); + Body[] tmp = new Body[bodies.size()]; + for (int i = 0; bodies.size() > 0; i++) { + tmp[i] = bodies.poll(); + } seconds++; // each iteration computes the movement of the celestial bodies within one second. + /* // merge bodies that have collided for (int i = 0; i < bodies.length; i++) { for (int j = i + 1; j < bodies.length; j++) { @@ -86,22 +92,23 @@ public class Simulation { } } } + */ // for each body (with index i): compute the total force exerted on it. - for (int i = 0; i < bodies.length; i++) { - forceOnBody[i] = new Vector3(); // begin with zero - for (int j = 0; j < bodies.length; j++) { - if (i != j) { - Vector3 forceToAdd = bodies[i].gravitationalForce(bodies[j]); - forceOnBody[i] = forceOnBody[i].plus(forceToAdd); + for (Body b1 : tmp) { + Vector3 force = new Vector3(); // begin with zero + for (Body b2 : tmp) { + if (b1 != b2) { + force = force.plus(b1.gravitationalForce(b2)); } } + forceOnBody.put(b1, force); } // now forceOnBody[i] holds the force vector exerted on body with index i. // for each body (with index i): move it according to the total force exerted on it. - for (int i = 0; i < bodies.length; i++) { - bodies[i].move(forceOnBody[i]); + for (Body body : tmp) { + body.move(forceOnBody.get(body)); } // show all movements in the canvas only every hour (to speed up the simulation) @@ -110,7 +117,7 @@ public class Simulation { cd.clear(Color.BLACK); // draw new positions - for (Body body : bodies) { + for (Body body : tmp) { body.draw(cd); } @@ -118,6 +125,7 @@ public class Simulation { cd.show(); } + bodies = newBodies; } }