Bonus Assignment: Wire World

 

Introduction

This assignment will lead you into the world of so called “Cellular Automata”. It's a big word for a small idea, which, however is extremely powerful. I will not give a general introduction, but a specific example – wireworld. The most famous example for cellular automata is Conway's "Game of Life" --- you might want to look that one up, too. Wireworld is slightly more complex.

This assignment will show the benefits of combining different data structures, here combining an array with a list. We store the data in both data structures, and, depending on the task, we access the more appropriate data structure.

THIS IS A BONUS ASSIGNMENT. IT HAS ITS CHALLENGING MOMENTS.

 

Introduction to Cellular Automata and Wireworld:

Imagine a grid of cells (or call it a 2 dimensional array, a matrix, a bunch of boxes arranged in a rectangle). Each of the cells can be in a so called state (or call it “can have a value from a set of values”, “can have a color from a set of colors”). In the following picture, The states are represented by colors. In wireworld, there are 4 possible states for each cell, which I call “background” (black), “head” (red), “tail” (blue), “wire” (white). Wire World is a simulation of an electric board, hence this image might remind you of an electric board with wires:


Again, we have single cells on a grid, each cell can have a state. The number of states is limited (here: 4 states). We are already close to the definition of cellular automata. The only thing missing is a set of rules to change the state of cells. In cellular automata, you create “generations of cell-grids”, the transition from one generation to the next is based on certain rules. These rules govern the change of state of a single cell, depending on the states of neighboring cells.

Wire World has an impressively simple set of rules:

·         if a cell is in state 0 (background), it will stay in state 0 (background)

·         if a cell is in state 1 (head), it will change to state 2 (tail)

·         if a cell is in state 2 (tail), it will change to state 3 (wire)

·         the interesting one: if a cell is in state 3 (wire), it will change to head if there are 1 or 2 of the 8 neighbors in state “head”, otherwise it will change stay in state wire.

So the cellular automaton “Wire World” does the following:

Look at a 2-dimensional array. This is called the n-th generation. Create a new 2D array, the (n+1) generation. For every cell in of the n-th generation, apply the rules above, and store the result in the corresponding cell in the (n+1) generation. After this, display the new generation, and proceed from generation (n+1) to (n+2) and so on. Here are some images from Wire Word that will give you an idea of what's happening (left to right: generation 0, generation1, generation 2, generation 3).


If you look at this figure, it seems that the read head and the blue tail are moving (and splitting). This is an interesting illusion. What happened from generation 0 to generation 1 is the following: The blue cell turned white (according to the rule “tale becomes wire”), the red cell turned blue (according to the rule “head becomes tail”), and the white cell right of the red one turned red (according to the rule “wire with one or two heads as neighbors becomes head”). In short, only single cells were switched, simulating a movement on the grid along the wire.

Note that you have an impression of something complex going on, involving the entire board. However, the rules are all defined for single cells. This is the nature of cellular automata. There is no central force ruling all, but the cells themselves act depending on a small neighborhood, causing an entire system to be able to behave in a complex way. Compare this to schools of fish, swarms of birds etc. ! (<= not part of the programming assignment.)

To give you an even better idea of wireworld, here is an executable java file, that you can start and play around with. Unfortunately, I will only give you the .jar --- since that's the program you should write (at least parts of it) ! Please play around with this program. You can get more information about Wire World in the internet, google it (that’s part of the assignment).

Click here to play with Wire World.

 

Task Definition

Here is your task: Program Wire World. You will be given a graphical grid-input editor. You have to program the actual logic of the game, and an output grid that shows the iterated generations.

You only need to program a simple GUI, which, once the logic has started to work, shows the output. No return to the editor has to be provided (in contrast, the .jar file above does provide such a return to the editor, which demands for a slightly more difficult code).

Don't panic, you will be given some support. This is a project, which might look big at first, but if you split up the programming task into small pieces, you will see that it's entirely doable.

 

Multiple Data Structures

Wire world basically iterates through a 2D array, looks at 8 neighbors of each cell, and determines a new value for the cell. However, background cells, which are the most frequent ones, do never change. That means, going through the array, there's a lot of idling: "if cell == 0 go to the next". In average, this idling comes into play for 80% of the cells. We can increase the performance by storing the indices (row, column) of non-background cells in a JAVA LinkedList. Traversing this list reaches the non-background cells only, having the data still stored in an array makes it easy to look at their neighbors (question: if we would NOT keep the array, but only use the linked list, what would be the order of magnitude of the program then? Would we gain speed?).

Using the list together with an array does not change the order of magnitude of the algorithm (it's always O(n)), but reduces the constant. The program will be, in average, 5 times faster (20% of non-background cells). This is important if you have really big grids (10000x10000) and you want a real-time simulation.

Help!

To make this program appear as simple as it actually is, let’s break it down into tasks. These tasks will also define a basic skeleton that suggest classes, methods etc.

(A)                        For this, create a new Netbeans Project, and create a CellArray class that first has to provide the basic data structure: a 2D array (please call it currentGeneration). Size it reasonably, e.g. 64x64

(B) Import the editor jar-file. The TA will tell you how. After that is done, you can just call a method which will (1) open the graphical editor, and (2) on exit, will copy its edited 2D array into the output array that is provided by you.

(C) Write the GUI:

a.      Extend your class from JPanel

b.     Create a frame

c.      Add yourself to the frame

d.      Override the paintComponent(…) method. The paintComponent method has to paint the grid. In order to do so, traverse the 2D array, look which state each cell has (0,1,2,3), define a color accordingly, and draw a filled rectangle at the corresponding position. Example: let’s say your loop is at a position row=13, column = 27, and your graphical squares have an edge-length of SIZE pixels. Check what’s the state of myArray[13][27]. Set the drawing color accordingly (…if state=… the g.setColor(…) …). The graphical coordinates of the box depend on the index of the cell you are examining. The coordinates are: x = column*size, here 27*SIZE; y = row*SIZE, here 13*size.

e.      TEST your code so far: call the input editor, edit some input grid, click “DONE”, and draw your own board. The board should show exactly the edited array, of course!

(D)                        You are half way through already, would you believe that? Go and get a coffee.

(E) Now implement the game logic. In order to do so, you have to traverse through the grid, look at the states of the cells (you did the same for the graphics already, you might want to copy some lines from there), and implement the rules based on the state of each cell. You have to be careful, there’s one tricky thing here: the new generation MUST be a new array, you can not copy the changes into the original array. So: create a “nextGeneration” 2D array. Traverse through the currentGeneration array, apply the rules, store the result in the newGeneration array. Then, when that’s done, make the currentGeneration array the newGeneration array (currentGeneration = newGeneration, i.e. re-reference. Do NOT copy. Too slow!). Visualize, re-compute the next generation and YOU ARE DONE. Yes, it is that simple. As usual, there are some little details, so let’s get down to them:

a.      The newGeneration array has to be of the same size as the currentGeneration array.

b.     Since in the wire-rule, you have to check for neighbors, you do not want to traverse the entire currentArray, but leave a margin of one cell to all sides. That prevents out of boundary errors. So your loop should be from 1 to NUMBEROFCOLUMNS-2 for columns, and from 1 to NUMBEROFROWS for rows. Please notice, it’s from 1, not from 0!

c.      First implement the simple rules, which are the background, the head and the tail rule. There’s no neighborhood check. It’s a simple “if tail in currentGeneration Array, then make it wire in nextGeneration array.” Etc.

d.      Test your logic with this subset of rules. The next generation should look like the previous one, yet with “dying” heads and tails. They won’t move, since the “wire” rule is still missing.

e.      Implement the “wire” rule. For this one, you have to check the neighbors of your current cell. Write a simple method “public int checkNeighbors(int column, int row), that takes as input the indices of the currently examined cell, and check the neighbors, which are the cells with index: [column-1][row-1] for top left neighbor, [column][row-1] for top neighbor etc. You have to check 8 neighbors. Check if they are “head”. If so, increase a counter (which at the beginning of your method is initialized to 0). When you are done with 8 neighbors, return the counter value.

f.      Test your program again. Now that all is implemented, it should behave like the example .jar file.

(F) So far, you have implemented the game based on an array only. Now extend it to use an additional linked list: when you read in the array from the editor, create a linked list of the indices of foreground cells. Change the nested for loop to an iteration through this list.

(G)  You are done. Be proud.

 

Code parts

Here is the jar file for the editor:  WireWorld.jar

How to use it: copy wireworld.jar to your project folder. In netbeans, right click on your projects, select 'properties', select 'libraries'. That opens a window to import libraries. Press the button "add Jar file". Select the 'wireworld.jar' file.

After you did these steps, you have to add " import wireworld.*; " in your code. The class wireworld.jar contains a class "BoardInput", which is the input-editor. Just instantiate an object of this class, passing your 2D array to its constructor (BoardInput b = new BoardInput(board)). That will show the editor. When the editor finishes, its result is stored in the array "board" that you passed to it.

Further Information

This is a BONUS assignment. You are only allowed to work on it, if you finished the Shape Abstraction assignment! It is NOT a replacement assignment for the shape abstraction. In short: if you do NOT hand in the shape abstraction, this assignment is invalid!

Deadline is Sunday, 2/26.

Points: implementation of wire world with array only: 5 points. Using the list: 10 points.

Good luck!