Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import javafx.animation.AnimationTimer;
- import javafx.application.Application;
- import javafx.scene.Group;
- import javafx.scene.Scene;
- import javafx.scene.canvas.Canvas;
- import javafx.scene.canvas.GraphicsContext;
- import javafx.scene.paint.Color;
- import javafx.stage.Stage;
- import java.util.Random;
- import static java.lang.Math.sqrt;
- import static java.lang.System.exit;
- import static java.lang.System.out;
- /*
- * Program to simulate segregation.
- * See : http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/
- *
- * NOTE:
- * - JavaFX first calls method init() and then method start() far below.
- * - To test uncomment call to test() first in init() method!
- *
- */
- // Extends Application because of JavaFX (just accept for now)
- public class Neighbours extends Application {
- class Actor {
- final Color color; // Color an existing JavaFX class
- boolean isSatisfied; // false by default
- Actor(Color color) { // Constructor to initialize
- this.color = color;
- }
- }
- // Below is the *only* accepted instance variable (i.e. variables outside any method)
- // This variable may *only* be used in methods init() and updateWorld()
- Actor[][] world; // The world is a square matrix of Actors
- // Random object
- static Random rand = new Random();
- // This is the method called by the timer to update the world
- // (i.e move unsatisfied) approx each 1/60 sec.
- void updateWorld() {
- // % of surrounding neighbours that are like me
- double threshold = 0.7;
- // TODO update world
- for (int i = 0; i < (world.length - 1); i++) {
- for (int j = 0; j < (world.length - 1); j++) {
- if (world[i][j] != null) {
- world[i][j].isSatisfied = isSatisfied(world, i, j, threshold);
- if(!world[i][j].isSatisfied) {
- while (world[i][j] != null) {
- int rx = rand.nextInt(world.length);
- int ry = rand.nextInt(world.length);
- if(isValidLocation(world.length, rx, ry)) {
- world[rx][ry] = world[i][j];
- world[i][j] = null;
- }
- }
- }
- }
- }
- }
- }
- // This method initializes the world variable with a random distribution of Actors
- // Method automatically called by JavaFX runtime
- // That's why we must have "@Override" and "public" (just accept for now)
- @Override
- public void init() {
- //test(); // <---------------- Uncomment to TEST!
- // %-distribution of RED, BLUE and NONE
- double[] dist = {0.25, 0.25, 0.50};
- // Number of locations (places) in world (must be a square)
- int nLocations = 900; // Should also try 90 000
- int width = (int)sqrt(nLocations);
- // TODO initialize the world
- world = new Actor[width][width];
- Actor[] entities = new Actor[nLocations];
- for (int i = 0, k = 0; i < entities.length; i++) {
- if(i <= (int)(dist[0]*nLocations)) {
- entities[(int)k++] = new Actor(Color.RED);
- } else if (i <= (int)(dist[0]*nLocations + dist[1]*nLocations)) {
- entities[(int)k++] = new Actor(Color.BLUE);
- } else {
- entities[(int)k++] = null;
- }
- }
- shuffleActorArray(entities);
- for (int i = 0; i < width; i++) {
- System.arraycopy(entities, i * width + 0, world[i], 0, width);
- }
- // Should be last
- fixScreenSize(nLocations);
- while (true) {
- updateWorld();
- }
- }
- // --------------- Methods ------------------------------
- // TODO Many ...
- Boolean isSatisfied(Actor[][] world, int x, int y, double threshold) {
- Boolean[] neighbors = {true, true, true, true};
- Actor neighbor;
- if (y < world.length) {
- neighbor = world[x][y + 1];
- if (neighbor != null) {
- neighbors[0] = neighbor.color == world[x][y].color;
- } else {
- neighbors[0] = true;
- }
- } else {
- neighbors[0] = true;
- }
- if (y > 0) {
- neighbor = world[x][y - 1];
- if (neighbor != null) {
- neighbors[1] = neighbor.color == world[x][y].color;
- } else {
- neighbors[1] = true;
- }
- } else {
- neighbors[1] = true;
- }
- if (x < world.length) {
- neighbor = world[x + 1][y];
- if (neighbor != null) {
- neighbors[2] = neighbor.color == world[x][y].color;
- } else {
- neighbors[2] = true;
- }
- } else {
- neighbors[2] = true;
- }
- if (x > 0) {
- neighbor = world[x - 1][y];
- if (neighbor != null) {
- neighbors[3] = neighbor.color == world[x][y].color;
- } else {
- neighbors[3] = true;
- }
- } else {
- neighbors[3] = true;
- }
- int i = 0;
- for (Boolean b : neighbors) {
- if(b){
- i++;
- }
- }
- return threshold < i / neighbors.length;
- }
- // Check if inside world
- boolean isValidLocation(int size, int row, int col) {
- return 0 <= row && row < size && 0 <= col && col < size;
- }
- // ----------- Utility methods -----------------
- // TODO (general method possible reusable elsewhere)
- void shuffleActorArray(Actor[] array) {
- int n = array.length;
- // Loop over array.
- for (int i = 0; i < array.length; i++) {
- // Get a random index of the array past the current index.
- // ... The argument is an exclusive bound.
- // It will not go past the array's end.
- int randomValue = i + rand.nextInt(n - i);
- // Swap the random element with the present element.
- Actor randomElement = array[randomValue];
- array[randomValue] = array[i];
- array[i] = randomElement;
- }
- }
- // ------- Testing -------------------------------------
- // Here you run your tests i.e. call your logic methods
- // to see that they really work. Important!!!!
- void test() {
- // A small hard coded world for testing
- Actor[][] testWorld = new Actor[][]{
- {new Actor(Color.RED), new Actor(Color.RED), null},
- {null, new Actor(Color.BLUE), null},
- {new Actor(Color.RED), null, new Actor(Color.BLUE)}
- };
- double th = 0.5; // Simple threshold used for testing
- int size = testWorld.length;
- out.println(isValidLocation(size, 0, 0));
- out.println(!isValidLocation(size, -1, 0));
- out.println(!isValidLocation(size, 0, 3));
- // TODO
- exit(0);
- }
- // ******************** NOTHING to do below this row, it's JavaFX stuff **************
- double width = 500; // Size for window
- double height = 500;
- final double margin = 50;
- double dotSize;
- void fixScreenSize(int nLocations) {
- // Adjust screen window
- dotSize = 9000 / nLocations;
- if (dotSize < 1) {
- dotSize = 2;
- }
- width = sqrt(nLocations) * dotSize + 2 * margin;
- height = width;
- }
- long lastUpdateTime;
- final long INTERVAL = 450_000_000; //450_000_000
- @Override
- public void start(Stage primaryStage) throws Exception {
- // Build a scene graph
- Group root = new Group();
- Canvas canvas = new Canvas(width, height);
- root.getChildren().addAll(canvas);
- GraphicsContext gc = canvas.getGraphicsContext2D();
- // Create a timer
- AnimationTimer timer = new AnimationTimer() {
- // This method called by FX, parameter is the current time
- public void handle(long now) {
- long elapsedNanos = now - lastUpdateTime;
- if (elapsedNanos > INTERVAL) {
- updateWorld();
- renderWorld(gc);
- lastUpdateTime = now;
- }
- }
- };
- Scene scene = new Scene(root);
- primaryStage.setScene(scene);
- primaryStage.setTitle("Simulation");
- primaryStage.show();
- timer.start(); // Start simulation
- }
- // Render the state of the world to the screen
- public void renderWorld(GraphicsContext g) {
- g.clearRect(0, 0, width, height);
- int size = world.length;
- for (int row = 0; row < size; row++) {
- for (int col = 0; col < size; col++) {
- int x = (int) (dotSize * col + margin);
- int y = (int) (dotSize * row + margin);
- if (world[row][col] != null) {
- g.setFill(world[row][col].color);
- g.fillOval(x, y, dotSize, dotSize);
- }
- }
- }
- }
- public static void main(String[] args) {
- launch(args);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement