botgob

Untitled

Jan 29th, 2021
838
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.85 KB | None | 0 0
  1. import javafx.animation.AnimationTimer;
  2. import javafx.application.Application;
  3. import javafx.scene.Group;
  4. import javafx.scene.Scene;
  5. import javafx.scene.canvas.Canvas;
  6. import javafx.scene.canvas.GraphicsContext;
  7. import javafx.scene.paint.Color;
  8. import javafx.stage.Stage;
  9.  
  10. import java.util.Arrays;
  11. import java.util.Random;
  12.  
  13. import static java.lang.Math.round;
  14. import static java.lang.Math.sqrt;
  15. import static java.lang.System.*;
  16.  
  17. /*
  18.  *  Program to simulate segregation.
  19.  *  See : http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/
  20.  *
  21.  * NOTE:
  22.  * - JavaFX first calls method init() and then method start() far below.
  23.  * - To test uncomment call to test() first in init() method!
  24.  *
  25.  */
  26. // Extends Application because of JavaFX (just accept for now)
  27.  
  28. public class Neighbours extends Application {
  29.  
  30.     Random rand = new Random();
  31.  
  32.  
  33.     class Actor {
  34.         final Color color;        // Color an existing JavaFX class
  35.         boolean isSatisfied;      // false by default
  36.  
  37.         Actor(Color color) {      // Constructor to initialize
  38.             this.color = color;
  39.         }
  40.     }
  41.     // A class to keep track of the index of a null. Much simpler solution than working with matrix.
  42.     class Node{
  43.         int i;
  44.         int j;
  45.         Node(int i, int j){
  46.             this.i = i;
  47.             this.j = j;
  48.         }
  49.     }
  50.  
  51.     // Below is the *only* accepted instance variable (i.e. variables outside any method)
  52.     // This variable may *only* be used in methods init() and updateWorld()
  53.     Actor[][] world;              // The world is a square matrix of Actors
  54.  
  55.     // This is the method called by the timer to update the world
  56.     // (i.e move unsatisfied) approx each 1/60 sec.
  57.     void updateWorld() {
  58.         // % of surrounding neighbours that are like me
  59.         // Resets all of the actors to not be satisfied.
  60.         for (int i = 0; i < world.length; i++){
  61.             for (int j = 0; j < world.length; j++){
  62.                 if (world[i][j] != null){
  63.                     world[i][j].isSatisfied = false;
  64.                 }
  65.             }
  66.         }
  67.         double threshold = 0.7;
  68.         // Finds all nulls in the world array
  69.         Node[] nullArray = findNulls(world);
  70.         // Finds all the satisfied actors and sets isSatisfied = true
  71.         findSatisfied(world, threshold);
  72.         // Shuffles the null array
  73.         shuffleArray(nullArray);
  74.         // Switches an unsatisfied actor to an empty slot.
  75.         switchPlaces(world,nullArray);
  76.  
  77.  
  78.  
  79.  
  80.         // TODO update world
  81.     }
  82.  
  83.     // This method initializes the world variable with a random distribution of Actors
  84.     // Method automatically called by JavaFX runtime
  85.     // That's why we must have "@Override" and "public" (just accept for now)
  86.     @Override
  87.     public void init() {
  88.         //test();    // <---------------- Uncomment to TEST!
  89.  
  90.         // %-distribution of RED, BLUE and NONE
  91.         double[] dist = {0.25, 0.25, 0.50};
  92.         // Number of locations (places) in world (must be a square)
  93.         int nLocations = 90000;   // Should also try 90 000
  94.  
  95.         // TODO initialize the world
  96.         Actor[] worldArr = generateDistribution(nLocations,dist);
  97.         world = toMatrix(worldArr);
  98.         // Should be last
  99.         fixScreenSize(nLocations);
  100.     }
  101.  
  102.     // ---------------  Methods ------------------------------
  103.  
  104.     // TODO Many ...
  105.  
  106.  
  107.     void switchPlaces(Actor[][] world, Node[] nullArray){
  108.         int count = 0;
  109.         for (int i = 0; i < world.length; i++){
  110.             for (int j = 0; j < world.length; j++){
  111.                 // Switches if the current actor != null and it isnt satisfied. Also makes sure count doesn't
  112.                 // go out of bounds.
  113.  
  114.                 if (world[i][j] != null && !world[i][j].isSatisfied && nullArray[count] != null){
  115.                     // Gets the indexes of the empty spot
  116.                     int x = nullArray[count].j;
  117.                     int y = nullArray[count].i;
  118.                     // Code for switching the spots
  119.                     world[y][x] = world[i][j];
  120.                     // Sets the current actor to satisfied so that the code doesn't switch its place again
  121.                     // in the current update. It should only be switched once per update.
  122.                     world[y][x].isSatisfied = true;
  123.                     world[i][j] = null;
  124.                     count++;
  125.                 } else if (nullArray[count] == null){
  126.                     count++;
  127.                 }
  128.             }
  129.         }
  130.     }
  131.  
  132.  
  133.     // Code to find all the neighbours around one actor. Then checks if the actor is satisfied with
  134.     // its current placement. If it is the actors isSatified boolean turns true.
  135.     void findSatisfied(Actor[][] world, double threshold){
  136.         for (int i = 0; i < world.length; i++){
  137.             for (int j = 0; j < world[i].length; j++){
  138.                 if (world[i][j] != null){
  139.                     Actor[] tmp = new Actor[8];
  140.                     int tmpCount = 0;
  141.                     // Code to check the neighbours. Wrote this before I found the isValidPlacement method.
  142.                     if (i - 1 >= 0){
  143.                         tmp[tmpCount] = world[i - 1][j];
  144.                         tmpCount++;
  145.                         if (j + 1 < world.length){
  146.                             tmp[tmpCount] = world[i - 1][j + 1];
  147.                             tmpCount++;
  148.                         }
  149.                         if (j - 1 >= 0){
  150.                             tmp[tmpCount] = world[i - 1][j - 1];
  151.                             tmpCount++;
  152.                         }
  153.                     }
  154.                     if (i + 1 < world.length) {
  155.                         tmp[tmpCount] = world[i + 1][j];
  156.                         tmpCount++;
  157.                         if (j - 1 >= 0){
  158.                             tmp[tmpCount] = world[i + 1][j - 1];
  159.                             tmpCount++;
  160.                         }
  161.                         if (j + 1 < world.length){
  162.                             tmp[tmpCount] = world[i + 1][j + 1];
  163.                             tmpCount++;
  164.                         }
  165.                     }
  166.                     if (j + 1 < world.length){
  167.                         tmp[tmpCount] = world[i][j + 1];
  168.                         tmpCount++;
  169.                     }
  170.                     if (j - 1 >= 0){
  171.                         tmp[tmpCount] = world[i][j - 1];
  172.                         tmpCount++;
  173.                     }
  174.                     // Uses method getNeighbourPercent to find out the percent of neighbours
  175.                     // that has the same color as current actor.
  176.                     double percent = getNeighbourPercent(tmp, world[i][j].color);
  177.                     if (percent >= threshold){
  178.                         world[i][j].isSatisfied = true;
  179.                     }
  180.                 }
  181.             }
  182.         }
  183.     }
  184.  
  185.     // Checks 8 actors in a list, then calculates the amount in percent. The percentage of which
  186.     // color is decided by the color you put in when calling the method.
  187.     double getNeighbourPercent(Actor[] neigh, Color color){
  188.         int redAmount = 0;
  189.         int blueAmount = 0;
  190.         int totalColor = neigh.length;
  191.         double totalColorPercent;
  192.         for (int i = 0; i < neigh.length; i++){
  193.             if (neigh[i] == null){
  194.                 totalColor--;
  195.             } else if (neigh[i].color == Color.RED){
  196.                 redAmount++;
  197.             } else if (neigh[i].color == Color.BLUE){
  198.                 blueAmount++;
  199.             }
  200.         }
  201.         // To not get divided by zero
  202.         if (totalColor == 0){
  203.             return 0.0;
  204.         }
  205.         if (color == Color.RED){
  206.             totalColorPercent = (double) redAmount / totalColor;
  207.         } else {
  208.             totalColorPercent = (double) blueAmount / totalColor;
  209.         }
  210.         return totalColorPercent;
  211.     }
  212.     // Shuffles an array of nodes. It generates a random number, then switches
  213.     // the current Node with the one at the random number index. Can change it
  214.     // to void.
  215.     Node[] shuffleArray(Node[] oldList){
  216.         for (int i = 0; i < oldList.length; i++){
  217.             int randomIndexToSwap = rand.nextInt(oldList.length);
  218.             Node temp = oldList[randomIndexToSwap];
  219.             oldList[randomIndexToSwap] = oldList[i];
  220.             oldList[i] = temp;
  221.         }
  222.         return oldList;
  223.     }
  224.     // Finds the nulls in the world array and creates a Node array, each node having the index of
  225.     // one of the nulls.
  226.     Node[] findNulls(Actor[][] world){
  227.         int worldLength = world.length * world.length;
  228.         Node[] nodeArr = new Node[(int) worldLength];
  229.         int tmp = 0;
  230.         for (int i = 0; i < world.length; i++){
  231.             for (int j = 0; j < world[i].length; j++){
  232.                 if (world[i][j] == null){
  233.                     nodeArr[tmp] = new Node(i,j);
  234.                     tmp++;
  235.                 }
  236.             }
  237.         }
  238.         return nodeArr;
  239.     }
  240.     // Same as the other shuffleArray, only this one takes an Actor array.
  241.     Actor[] shuffleArray(Actor[] oldList){
  242.  
  243.         for (int i = 0; i < oldList.length; i++){
  244.             int randomIndexToSwap = rand.nextInt(oldList.length);
  245.             Actor temp = oldList[randomIndexToSwap];
  246.             oldList[randomIndexToSwap] = oldList[i];
  247.             oldList[i] = temp;
  248.         }
  249.  
  250.         return oldList;
  251.     }
  252.     // Generates the distribution of the world. It creates an array with
  253.     // (for example) 25% red 25% blue 50% nulls. First all the reds, then blue and then nulls.
  254.     // After that it shuffles the array to get a somewhat equal spread across the world.
  255.     Actor[] generateDistribution(int length, double[] doubArr){
  256.  
  257.         Actor[] newArray = new Actor[length];
  258.         int amountBlue = 0;
  259.         int amountRed = 0;
  260.         int amountNull = 0;
  261.         for (int i = 0; i < newArray.length; i++) {
  262.             if (amountRed < (int) (doubArr[0] * length)){
  263.                 newArray[i] = new Actor(Color.RED);
  264.                 amountRed++;
  265.             } else if (amountBlue < (int) (doubArr[1] * length)){
  266.                 newArray[i] = new Actor(Color.BLUE);
  267.                 amountBlue++;
  268.             } else if (amountNull < (int) (int) (doubArr[2] * length)){
  269.                 newArray[i] = null;
  270.                 amountNull++;
  271.             }
  272.         }
  273.         shuffleArray(newArray);
  274.         return  newArray;
  275.     }
  276.  
  277.     // Turns an array to a matrix. (2d array)
  278.     Actor[][] toMatrix(Actor[] arr){
  279.         int size = (int) StrictMath.sqrt(arr.length);
  280.         Actor[][] m = new Actor[size][size];
  281.         int temp = -1;
  282.         for(int i = 0;i<arr.length;i++){
  283.             int l = i%size;
  284.             if(l == 0){
  285.                 temp++;
  286.             }
  287.             m[temp][l] = arr[i];
  288.         }
  289.         return m;
  290.     }
  291.     // Turns a 2d array to a regular array.
  292.     Actor[] toArr(Actor[][] m){
  293.         int size = m.length*m.length;
  294.         Actor[] temp = new Actor[size];
  295.         int count = 0;
  296.         for(int i = 0; i < m.length; i++){
  297.             for(int n = 0; n<m.length;n++){
  298.                 temp[count] = m[i][n];
  299.                 count++;
  300.             }
  301.         }
  302.         return temp;
  303.     }
  304.  
  305.     // Check if inside world
  306.     boolean isValidLocation(int size, int row, int col) {
  307.         return 0 <= row && row < size && 0 <= col && col < size;
  308.     }
  309.  
  310.     // ----------- Utility methods -----------------
  311.  
  312.     // TODO (general method possible reusable elsewhere)
  313.  
  314.     // ------- Testing -------------------------------------
  315.  
  316.     // Here you run your tests i.e. call your logic methods
  317.     // to see that they really work. Important!!!!
  318.     void test() {
  319.         // A small hard coded world for testing
  320.         Actor[][] testWorld = new Actor[][]{
  321.                 {   new Actor(Color.RED),   new Actor(Color.RED),    null},
  322.                 {   null,                   new Actor(Color.BLUE),   null},
  323.                 {   new Actor(Color.RED),   null,                    new Actor(Color.BLUE)}
  324.         };
  325.         double th = 0.5;   // Simple threshold used for testing
  326.  
  327.         int size = testWorld.length;
  328.         /*
  329.         out.println(isValidLocation(size, 0, 0));
  330.         out.println(!isValidLocation(size, -1, 0));
  331.         out.println(!isValidLocation(size, 0, 3));
  332.         */
  333.         findSatisfied(testWorld,th);
  334.         for (int i = 0; i < testWorld.length; i++){
  335.             for (int j = 0; j < testWorld.length; j++){
  336.                 if (testWorld[i][j] != null){
  337.                     out.println(testWorld[i][j].isSatisfied);
  338.                 }
  339.             }
  340.         }
  341.  
  342.  
  343.         // TODO
  344.  
  345.  
  346.         exit(0);
  347.     }
  348.     void testMethod(Actor[][] world){
  349.         world[0][0].isSatisfied = true;
  350.     }
  351.     // ******************** NOTHING to do below this row, it's JavaFX stuff  **************
  352.  
  353.     double width = 500;   // Size for window
  354.     double height = 500;
  355.     final double margin = 50;
  356.     double dotSize;
  357.  
  358.     void fixScreenSize(int nLocations) {
  359.         // Adjust screen window
  360.         dotSize = 9000 / nLocations;
  361.         if (dotSize < 1) {
  362.             dotSize = 2;
  363.         }
  364.         width = sqrt(nLocations) * dotSize + 2 * margin;
  365.         height = width;
  366.     }
  367.  
  368.     long lastUpdateTime;
  369.     final long INTERVAL = 450_000_000;
  370.  
  371.  
  372.     @Override
  373.     public void start(Stage primaryStage) throws Exception {
  374.  
  375.         // Build a scene graph
  376.         Group root = new Group();
  377.         Canvas canvas = new Canvas(width, height);
  378.         root.getChildren().addAll(canvas);
  379.         GraphicsContext gc = canvas.getGraphicsContext2D();
  380.  
  381.         // Create a timer
  382.         AnimationTimer timer = new AnimationTimer() {
  383.             // This method called by FX, parameter is the current time
  384.             public void handle(long now) {
  385.                 long elapsedNanos = now - lastUpdateTime;
  386.                 if (elapsedNanos > INTERVAL) {
  387.                     updateWorld();
  388.                     renderWorld(gc);
  389.                     lastUpdateTime = now;
  390.                 }
  391.             }
  392.         };
  393.  
  394.         Scene scene = new Scene(root);
  395.         primaryStage.setScene(scene);
  396.         primaryStage.setTitle("Simulation");
  397.         primaryStage.show();
  398.  
  399.         timer.start();  // Start simulation
  400.     }
  401.  
  402.  
  403.     // Render the state of the world to the screen
  404.     public void renderWorld(GraphicsContext g) {
  405.         g.clearRect(0, 0, width, height);
  406.         int size = world.length;
  407.         for (int row = 0; row < size; row++) {
  408.             for (int col = 0; col < size; col++) {
  409.                 int x = (int) (dotSize * col + margin);
  410.                 int y = (int) (dotSize * row + margin);
  411.                 if (world[row][col] != null) {
  412.                     g.setFill(world[row][col].color);
  413.                     g.fillOval(x, y, dotSize, dotSize);
  414.                 }
  415.             }
  416.         }
  417.     }
  418.  
  419.     public static void main(String[] args) {
  420.         launch(args);
  421.     }
  422.  
  423. }
  424.  
Advertisement
Add Comment
Please, Sign In to add comment