
edu.princeton.cs.algs4.CollisionSystem Maven / Gradle / Ivy
Show all versions of algorithm Show documentation
/******************************************************************************
* Compilation: javac CollisionSystem.java
* Execution: java CollisionSystem n (n random particles)
* java CollisionSystem < input.txt (from a file)
* Dependencies: StdDraw.java Particle.java MinPQ.java
* Data files: https://algs4.cs.princeton.edu/61event/diffusion.txt
* https://algs4.cs.princeton.edu/61event/diffusion2.txt
* https://algs4.cs.princeton.edu/61event/diffusion3.txt
* https://algs4.cs.princeton.edu/61event/brownian.txt
* https://algs4.cs.princeton.edu/61event/brownian2.txt
* https://algs4.cs.princeton.edu/61event/billiards5.txt
* https://algs4.cs.princeton.edu/61event/pendulum.txt
*
* Creates n random particles and simulates their motion according
* to the laws of elastic collisions.
*
******************************************************************************/
package edu.princeton.cs.algs4;
import java.awt.Color;
/**
* The {@code CollisionSystem} class represents a collection of particles
* moving in the unit box, according to the laws of elastic collision.
* This event-based simulation relies on a priority queue.
*
* For additional documentation,
* see Section 6.1 of
* Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public class CollisionSystem {
private static final double HZ = 0.5; // number of redraw events per clock tick
private MinPQ pq; // the priority queue
private double t = 0.0; // simulation clock time
private Particle[] particles; // the array of particles
/**
* Initializes a system with the specified collection of particles.
* The individual particles will be mutated during the simulation.
*
* @param particles the array of particles
*/
public CollisionSystem(Particle[] particles) {
this.particles = particles.clone(); // defensive copy
}
// updates priority queue with all new events for particle a
private void predict(Particle a, double limit) {
if (a == null) return;
// particle-particle collisions
for (int i = 0; i < particles.length; i++) {
double dt = a.timeToHit(particles[i]);
if (t + dt <= limit)
pq.insert(new Event(t + dt, a, particles[i]));
}
// particle-wall collisions
double dtX = a.timeToHitVerticalWall();
double dtY = a.timeToHitHorizontalWall();
if (t + dtX <= limit) pq.insert(new Event(t + dtX, a, null));
if (t + dtY <= limit) pq.insert(new Event(t + dtY, null, a));
}
// redraw all particles
private void redraw(double limit) {
StdDraw.clear();
for (int i = 0; i < particles.length; i++) {
particles[i].draw();
}
StdDraw.show();
StdDraw.pause(20);
if (t < limit) {
pq.insert(new Event(t + 1.0 / HZ, null, null));
}
}
/**
* Simulates the system of particles for the specified amount of time.
*
* @param limit the amount of time
*/
public void simulate(double limit) {
// initialize PQ with collision events and redraw event
pq = new MinPQ();
for (int i = 0; i < particles.length; i++) {
predict(particles[i], limit);
}
pq.insert(new Event(0, null, null)); // redraw event
// the main event-driven simulation loop
while (!pq.isEmpty()) {
// get impending event, discard if invalidated
Event e = pq.delMin();
if (!e.isValid()) continue;
Particle a = e.a;
Particle b = e.b;
// physical collision, so update positions, and then simulation clock
for (int i = 0; i < particles.length; i++)
particles[i].move(e.time - t);
t = e.time;
// process event
if (a != null && b != null) a.bounceOff(b); // particle-particle collision
else if (a != null && b == null) a.bounceOffVerticalWall(); // particle-wall collision
else if (a == null && b != null) b.bounceOffHorizontalWall(); // particle-wall collision
else if (a == null && b == null) redraw(limit); // redraw event
// update the priority queue with new collisions involving a or b
predict(a, limit);
predict(b, limit);
}
}
/***************************************************************************
* An event during a particle collision simulation. Each event contains
* the time at which it will occur (assuming no supervening actions)
* and the particles a and b involved.
*
* - a and b both null: redraw event
* - a null, b not null: collision with vertical wall
* - a not null, b null: collision with horizontal wall
* - a and b both not null: binary collision between a and b
*
***************************************************************************/
private static class Event implements Comparable {
private final double time; // time that event is scheduled to occur
private final Particle a, b; // particles involved in event, possibly null
private final int countA, countB; // collision counts at event creation
// create a new event to occur at time t involving a and b
public Event(double t, Particle a, Particle b) {
this.time = t;
this.a = a;
this.b = b;
if (a != null) countA = a.count();
else countA = -1;
if (b != null) countB = b.count();
else countB = -1;
}
// compare times when two events will occur
public int compareTo(Event that) {
return Double.compare(this.time, that.time);
}
// has any collision occurred between when event was created and now?
public boolean isValid() {
if (a != null && a.count() != countA) return false;
if (b != null && b.count() != countB) return false;
return true;
}
}
/**
* Unit tests the {@code CollisionSystem} data type.
* Reads in the particle collision system from a standard input
* (or generates {@code N} random particles if a command-line integer
* is specified); simulates the system.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
StdDraw.setCanvasSize(600, 600);
// enable double buffering
StdDraw.enableDoubleBuffering();
// the array of particles
Particle[] particles;
// create n random particles
if (args.length == 1) {
int n = Integer.parseInt(args[0]);
particles = new Particle[n];
for (int i = 0; i < n; i++)
particles[i] = new Particle();
}
// or read from standard input
else {
int n = StdIn.readInt();
particles = new Particle[n];
for (int i = 0; i < n; i++) {
double rx = StdIn.readDouble();
double ry = StdIn.readDouble();
double vx = StdIn.readDouble();
double vy = StdIn.readDouble();
double radius = StdIn.readDouble();
double mass = StdIn.readDouble();
int r = StdIn.readInt();
int g = StdIn.readInt();
int b = StdIn.readInt();
Color color = new Color(r, g, b);
particles[i] = new Particle(rx, ry, vx, vy, radius, mass, color);
}
}
// create collision system and simulate
CollisionSystem system = new CollisionSystem(particles);
system.simulate(10000);
}
}
/******************************************************************************
* Copyright 2002-2018, Robert Sedgewick and Kevin Wayne.
*
* This file is part of algs4.jar, which accompanies the textbook
*
* Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne,
* Addison-Wesley Professional, 2011, ISBN 0-321-57351-X.
* http://algs4.cs.princeton.edu
*
*
* algs4.jar is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* algs4.jar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with algs4.jar. If not, see http://www.gnu.org/licenses.
******************************************************************************/