CSC352 Game of Life, 2 Threads
--D. Thiebaut (talk) 15:40, 28 February 2017 (EST)
Threaded Game of Life in Java
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; /* Game of life D. Thiebaut Heavily adapted from code found in java section at this URL: https://rosettacode.org/wiki/Conway%27s_Game_of_Life#Java This code works in console mode, displaying successive generations of the game of life on the screen, and clearing the screen between each one. The initial pattern is defined in the array dish (as in petri dish). To compile and run: javac GameOfLife.java java GameOfLife */ class data { static String[] dish= { " ", " # ", " # # ### ", " ## ", " ", " # ", " # # ", " ## ", " ", " " }; static String[] dish2= { " ", " # ", " # # ### ", " ## ", " ", " # ", " # # ", " ## ", " ", " ", " ", " ", " # ", " # # ", " ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " }; } /* * This is the thread class that will work on 1/2 of the * dish array. If Id == 0, then work on low rows, * if Id == 1, then work on high rows. */ class MyThread extends Thread{ int Id; // the Id of the thread, 0, or 1. int gens = 3000; BlockingQueue<Integer> sendQ; BlockingQueue<Integer> receiveQ; MyThread( int Id, int gens, BlockingQueue<Integer> sendQ, BlockingQueue<Integer> receiveQ ) { this.Id = Id; this.gens = gens; this.sendQ = sendQ; this.receiveQ = receiveQ; } /* * This will apply life repeatedly to the half of the * dish array that belongs to this thread. * @see java.lang.Thread#run() */ public void run(){ int midRow = data.dish.length / 2; for (int i= 0;i < gens;i++) { //System.out.println("Generation " + i + ":\n\n\n"); String[] newGen; if ( Id==0 ) newGen = life( 0, midRow ); else newGen = life( midRow, data.dish.length ); // wait for life to have finished. // send a token, wait for token try { sendQ.put( 1 ); receiveQ.take( ); } catch (InterruptedException e) { e.printStackTrace(); } // now safe to copy new generation into dish if ( Id==0 ) copyDish( newGen, 0, midRow ); else copyDish( newGen, midRow, data.dish.length ); // wait for copy operation to be done. // send a token, wait for token try { sendQ.put( 1 ); receiveQ.take( ); } catch (InterruptedException e) { e.printStackTrace(); } } } private static void copyDish( String[] newGen, int startRow, int endRow ) { // copy newGen into dish for ( int row= startRow; row < endRow; row++ ) { data.dish[row] = newGen[row]; } } private static String[] life( int startRow, int endRow ){ /* Given an array of string representing the current population of cells in a petri dish, computes the new generation of cells according to the rules of the game. A new array of strings is returned. */ String[] newGen= new String[ data.dish.length ]; for ( int row= startRow; row < endRow; row++ ) {//each row newGen[row]= ""; for ( int i= 0; i < data.dish[row].length(); i++ ) {//each char in the row int neighbors = 0; char current = data.dish[row].charAt(i); // loop in a block that is 3x3 around the current cell // and count the number of '#' cells. for ( int r=row-1; r<=row+1; r++ ) { // make sure we wrap around from bottom to top int realr = r; if ( r==-1 ) realr = data.dish.length-1; if ( r==data.dish.length) realr = 0; for ( int j=i-1; j<=i+1; j++ ) { // make sure we wrap around from left to right int realj = j; if ( j==-1 ) realj = data.dish[row].length()-1; if ( j==data.dish[row].length() ) realj = 0; if (r==row && j==i ) continue; // current cell is not its // neighbor if (data.dish[realr].charAt(realj) == '#' ) neighbors++; } } if ( current=='#' ) if (neighbors < 2 || neighbors > 3) newGen[row] += " "; else newGen[row] += "#"; if ( current==' ' ) if ( neighbors == 3 ) newGen[row] += "#"; else newGen[row] += " "; } } return newGen; } } public class GameOfLife2Threads{ // static variables are global to all objects instanciated from the class. public static void main(String[] args){ // display original generation print( data.dish ); BlockingQueue<Integer> queue01 = new ArrayBlockingQueue<Integer>(2); BlockingQueue<Integer> queue10 = new ArrayBlockingQueue<Integer>(2); // create 2 workers MyThread t0=new MyThread( 0, 3000, queue01, queue10 ); MyThread t1=new MyThread( 1, 3000, queue10, queue01 ); // start 2 workers t0.start(); t1.start(); // wait for the 2 threads to be done try { t1.join(); t0.join(); } catch (InterruptedException ie) { ie.printStackTrace(); } // display final generation print( data.dish ); } public static void clearScreen(){ /* brings the cursor home (top-left), so that the next generation will be printed over the current one. */ final String ANSI_CLS = "\u001b[2J"; final String ANSI_HOME = "\u001b[H"; System.out.print( ANSI_HOME); System.out.flush(); } public static void print( String[] dish ) { /* just display all the lines of the array of strings. */ clearScreen(); System.out.println( new String(new char[dish[0].length()] ).replace('\0', '-' ) ); for ( String s: dish ) System.out.println(s); } }