aboutsummaryrefslogtreecommitdiff
path: root/Week14 Route 66/src/com/camilstaps/route66/Model.java
diff options
context:
space:
mode:
authorCamil Staps2015-05-29 13:17:53 +0200
committerCamil Staps2015-05-29 13:17:53 +0200
commit3ccaa674fdbd3408d4cbea3ed9abb02c14433b9c (patch)
treec51dbe974566b4c437500fbf6894b626b203d265 /Week14 Route 66/src/com/camilstaps/route66/Model.java
parentHack to make it seem to be working (diff)
licensing; reorganisation; javadoc; cleanup
Diffstat (limited to 'Week14 Route 66/src/com/camilstaps/route66/Model.java')
-rw-r--r--Week14 Route 66/src/com/camilstaps/route66/Model.java189
1 files changed, 189 insertions, 0 deletions
diff --git a/Week14 Route 66/src/com/camilstaps/route66/Model.java b/Week14 Route 66/src/com/camilstaps/route66/Model.java
new file mode 100644
index 0000000..6e43e29
--- /dev/null
+++ b/Week14 Route 66/src/com/camilstaps/route66/Model.java
@@ -0,0 +1,189 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.camilstaps.route66;
+
+import java.util.ArrayList;
+import java.util.Observable;
+import javax.swing.JFrame;
+
+/**
+ * Route 66 model with crossing
+ *
+ * The class model holds all cars in the simulation.
+ *
+ * @author Pieter Koopman, Camil Staps
+ */
+public class Model extends Observable {
+
+ private final Car [] cars;
+ public static final int
+ DIRECTIONS = 4,
+ NUMBEROFCARS = 5 * DIRECTIONS; // total number of cars in system
+
+ private final ArrayList<JFrame> views;
+
+ /**
+ * Crossing attributes:
+ *
+ * allowed - which direction is currently allowed; if East is allowed, West
+ * is also allowed, etc.
+ * crossingWaiting - whether or not the crossing is waiting for cars to
+ * leave the crossing to switch (i.e. orange)
+ * lastCrossingChange - when the crossing switched the last time
+ * MIN_CROSS_TIME - the minimum time the crossing should wait before
+ * switching again after the last switch
+ */
+ private Direction allowed = Direction.East;
+ private boolean crossingWaiting = false;
+ private long lastCrossingChange = 0;
+ private static final int MIN_CROSS_TIME = 1000;
+
+ /**
+ * Constructor: create all cars
+ */
+ public Model() {
+ views = new ArrayList<>();
+ cars = new Car [NUMBEROFCARS];
+ for (int c = 0; c < NUMBEROFCARS; c += 1) {
+ cars[c] = new Car(c, this);
+ }
+ }
+
+ /**
+ * add the view to this model. It will be repainted upon an update
+ * @param view
+ */
+ public void addView(JFrame view) {
+ views.add(view);
+ }
+
+ public Car[] getCars() {
+ return cars;
+ }
+
+ /**
+ * Get a car from the model
+ * @param i numbers of required car
+ * @return the car itself (not a copy)
+ */
+ public Car getCar(int i) {
+ return cars[i];
+ }
+
+ /**
+ * Repaint all views, and notify all drivers to reconsider driving
+ */
+ public synchronized void update() {
+ for (JFrame view: views) {
+ view.repaint();
+ }
+ notifyAll();
+ }
+
+ /**
+ * Check if a location is safe for a car to go to. This should always be
+ * checked by a driver before actually driving.
+ * @param car
+ * @param requested_location
+ * @return
+ */
+ public synchronized boolean isSafeLocation(Car car, int requested_location) {
+ // Check that we don't collide with the car in front of us
+ Car that_car = cars[car.getNumber() < DIRECTIONS ? car.getNumber() + NUMBEROFCARS - DIRECTIONS : car.getNumber() - DIRECTIONS];
+ boolean ok = !(that_car.getLocation() > requested_location &&
+ that_car.getLocation() < requested_location + Car.CARLENGTH + Car.MINCARSPACE);
+
+ // If we have to wait for the crossing... well, do that.
+ if (car.isInFrontOfCrossing() && !isCrossingAllowed(car.getDirection())) {
+ ok = doCrossingRequest();
+ }
+
+ if (!ok) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {}
+ }
+
+ return ok;
+ }
+
+ /**
+ * Check if there are any cars on the crossing
+ * @return
+ */
+ public synchronized boolean isCarsOnCrossing() {
+ for (Car car : cars) {
+ if (car.isOnCrossing()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Switch the crossing
+ */
+ public synchronized void doSwitchCrossing() {
+ crossingWaiting = true;
+
+ while (isCarsOnCrossing()) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ if (allowed == Direction.East || allowed == Direction.West) {
+ allowed = Direction.North;
+ } else {
+ allowed = Direction.East;
+ }
+
+ crossingWaiting = false;
+ lastCrossingChange = System.currentTimeMillis();
+ }
+
+ /**
+ * Check if crossing in some direction is allowed
+ * @param direction
+ * @return
+ */
+ public synchronized boolean isCrossingAllowed(Direction direction) {
+ return !crossingWaiting && (direction == allowed || Direction.opposite(direction) == allowed);
+ }
+
+ /**
+ * Try to switch the crossing
+ * This may return false without even trying to switch, if it's too early to
+ * ask (see {@link Model#MIN_CROSS_TIME}) or if a request has been made already.
+ * @return
+ */
+ public synchronized boolean doCrossingRequest() {
+ if (crossingWaiting || System.currentTimeMillis() - lastCrossingChange < MIN_CROSS_TIME) {
+ return false;
+ }
+ doSwitchCrossing();
+ return true;
+ }
+}