-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoidSimulator.java
153 lines (133 loc) · 6.14 KB
/
BoidSimulator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* *****************************************************************************
* Compilation: javac BoidSimulator.java
* Execution: java BoidSimuator
* Dependencies: KdTreeST.java Boid.java Hawk.java
*
* Implementation of a boid simulator using the KdTreeST data type,
* supplemented with the method nearest(Point2D p, int k).
*
* Note: This code is a bit hacked together. Apologies for any messy
* code. Interactivity features and other tweaks by Evan Sparano (Fall 2013).
*
* Instructions for using the boid simulator:
* Press "o" to zoom out.
* Press "i" to zoom in.
* Press "t" to track the center of mass of all boids.
* Press "h" to track the hawk.
* Press "m" to manually control the camera.
* While in "manual" mode, use arrow keys to control camera movement.
*
**************************************************************************** */
import java.awt.event.KeyEvent;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom;
public class BoidSimulator {
// mode selection constants
private static final char MANUAL_MODE = 'm';
private static final char TRACKING_MODE = 't';
private static final char HAWK_MODE = 'h';
// camera movement constants
private static final double ZOOM_FACTOR = 1.1;
private static final double CAMERA_SPEED = 0.05;
private static char mode = TRACKING_MODE; // start in "tracking" mode
private static Iterable<Boid> lookUpBoids(KdTreeST<Boid> bkd, Iterable<Point2D> points) {
Queue<Boid> values = new Queue<Boid>();
for (Point2D p : points) {
values.enqueue(bkd.get(p));
}
return values;
}
public static void main(String[] args) {
Hawk hawk = new Hawk(0.5, 0.3);
int NUM_BOIDS = 1000;
// Each boid tracks a number of nearest neighbors equal to FRIENDS
int FRIENDS = 10;
Boid[] boids = new Boid[NUM_BOIDS];
double meanX, meanY;
double radius = 0.5;
double currentX = 0.5;
double currentY = 0.5;
// Generate random boids.
for (int i = 0; i < NUM_BOIDS; i++) {
double startX = StdRandom.uniform();
double startY = StdRandom.uniform();
double velX = (StdRandom.uniform() - 0.5)/1000;
double velY = (StdRandom.uniform() - 0.5)/1000;
boids[i] = new Boid(startX, startY, velX, velY);
}
StdDraw.enableDoubleBuffering();
while (true) {
// process keyboard input
if (StdDraw.isKeyPressed(KeyEvent.VK_I)) // press "i" to zoom in
radius *= 1/ZOOM_FACTOR;
if (StdDraw.isKeyPressed(KeyEvent.VK_O)) // press "o" to zoom out
radius *= ZOOM_FACTOR;
if (StdDraw.isKeyPressed(KeyEvent.VK_M)) // press "m" to enter
mode = MANUAL_MODE; // "manual" mode
if (StdDraw.isKeyPressed(KeyEvent.VK_H)) // press "h" to enter
mode = HAWK_MODE; // "hawk" mode
if (StdDraw.isKeyPressed(KeyEvent.VK_T)) // press "t" to enter
mode = TRACKING_MODE; // "tracking" mode
// scale pen radius relative to zoom
StdDraw.setPenRadius(0.01*(0.5/radius));
StdDraw.setXscale(currentX - radius, currentX + radius);
StdDraw.setYscale(currentY - radius, currentY + radius);
// draw all boids and calculate their meanX and meanY
meanX = 0;
meanY = 0;
for (int i = 0; i < NUM_BOIDS; i++) {
meanX += boids[i].x()/NUM_BOIDS;
meanY += boids[i].y()/NUM_BOIDS;
boids[i].draw();
}
// draw the hawk
hawk.draw();
// follow center of mass in tracking mode
if (mode == TRACKING_MODE) {
currentX = meanX;
currentY = meanY;
}
// allow user to control movement in manual mode
else if (mode == MANUAL_MODE) {
// press "up arrow" to pan upwards
if (StdDraw.isKeyPressed(KeyEvent.VK_UP))
currentY += radius*CAMERA_SPEED;
// press "down arrow" to pan downwards
if (StdDraw.isKeyPressed(KeyEvent.VK_DOWN))
currentY -= radius*CAMERA_SPEED;
// press "left arrow" to pan to the left
if (StdDraw.isKeyPressed(KeyEvent.VK_LEFT))
currentX -= radius*CAMERA_SPEED;
// press "right arrow" to pan to the right
if (StdDraw.isKeyPressed(KeyEvent.VK_RIGHT))
currentX += radius*CAMERA_SPEED;
}
// follow hawk in hawk mode
else if (mode == HAWK_MODE) {
currentX = hawk.x();
currentY = hawk.y();
}
// The entire KdTree must be rebuilt every frame. Since the boids
// are random, we expect a roughly balanced tree, despite the
// lack of balancing in KdTreeST.
KdTreeST<Boid> bkd = new KdTreeST<Boid>();
for (int i = 0; i < NUM_BOIDS; i++) {
bkd.put(boids[i].position(), boids[i]);
}
for (int i = 0; i < NUM_BOIDS; i++) {
Iterable<Point2D> kNearestPoints = bkd.nearest(boids[i].position(), FRIENDS);
Iterable<Boid> kNearest = lookUpBoids(bkd, kNearestPoints);
boids[i].updatePositionAndVelocity(kNearest, hawk);
}
// The hawk will chase the nearest boid.
Boid closestBoid = bkd.get(bkd.nearest(hawk.position()));
hawk.updatePositionAndVelocity(closestBoid);
// hawk.updatePositionAndVelocity(bkd.nearest(new Boid(hawk.x(), hawk.y())));
StdDraw.show();
StdDraw.pause(20);
StdDraw.clear();
}
}
}