Tuesday 9 December 2008

Chunk16 Code Removed - Second Draft


2358 words

The Chunk 16 application draws a random picture to the screen about every second. It weighs in at a little over 100 lines and can be run as an applet or an application by simply clicking on an appropriate link. There is no need to struggle with applet permissions, digitally signing jar files or setting up a jnlp file for Java WebStart.
This chapter should help clarify the basics of programming, so you are ready to tackle the special features of Processing. We will go through each topic in order of difficulty, exploring each structure as we go.

Variables declared within a code block are only usable within that block. The local variables declared on lines 33 and 34 are usable at any point within the draw function. None of the other functions are aware of their existence.
Functions are extremely useful structures that allow us to use the same code in various places by calling the function's signature. The signature of a function is its first line. If we have a function with the signature:
void drawCircles(int a)
then we call it like so:
drawCircles(400);
If there is a function with the same name but a different signature it is known as an overloaded function:
drawCircles(int a, String col)
we could call the second overloaded function like so:
drawCircles(400, "red");

Code that is repeated frequently is an indication that a function is required. The repetitive portion of the code should be moved into a function with any parameters required. This helps with code reuse, making the program easier to maintain and cuts down the program's length. Any errors/modifications are confined to one place and can be easily corrected.
A simple function is usually used to change some global variable's value. It doesn't accept any parameters and returns no value. The changeColour() function line 105 provides us with an example. It has a void return type and empty parameter brackets.
Some functions can be passed messages, informing them of value/s to change or use. drawCircles3(int) on line 118 accepts an integer which it uses to draw a circle using the ellipses method.
A function can be used to perform some calculation and return a value. These type of functions must contain the return type in their signature. The getSW function on line 135 returns an int value which can be used to set the stroke weight.
A function can also both accept parameters and return a value. We havent used this type of user defined function in chunk 16.
As well as user defined functions there are also inbuilt functions:
The size function accepts two integers which are used to set the size of the display window.
The rect(int, int, int, int) function accepts four parameters which it uses to draw a rectangle.
The random function is an overloaded function because it can accept either one or two parameters and can return a float or an integer. In chunk 16 we mostly use integers so we need to round down any floats. Examples of using round(random(int, int)) can be found in many places in Chunk 16 as it outputs randomized patterns by varying the values of stroke width, colour, height. shapes to use, width, interval and patternsPerPicture.

If there were no loops in our code, then our programs wouldn't last long, or they would have to contain a huge amount of repetitive code.
Looping structures all consist of the same basic format. A conditional statement followed by the block of code to repeat.
The if block isnt really a looping construct but as it follows the same type of format we will discuss it here.
The basic form of an if statement is as follows:

The functionality of an if block can be extended by adding an else block:

The if block can be even further extended with else if blocks.
The else and else if blocks cant be used on their own and must be proceeded by an if statement.
Examples of using if, else if and else consructs are on lines 36 and line 124.

while blocks allow us to repeat a section of code until a condition or conditions become true or false. The opening clause contains the condition and this is followed by a statement block. Statement blocks, in looping structures, are always enclosed by curly brackets, unless there is only one such statement. Sometimes a while statement is used to increment a simple counter.

Here the loop is repeated 10 times.

This while loop calls the getInput function until the value of input is equal to the value of valid.
Examples of while loops are on lines: 42, 51 and 57.
The draw method has a lot of while methods that seem to be performing a similar function.

A do while loop is very much like an upside down while loop. Do while loops are used when we need a block of code to execute at least once. This means that the statement block, is executed once, before the conditional is checked.
The layout of a do while loop has the following structure:

We haven't used a do while loop but it would be simpleto implement if needed.

The for loop allows us to specify the number of times a code block will repeat. We use an int to state the amount of iterations. A for loop takes a start value, an exit loop conditional clause and the amount the looping integer will be changed by. For loops can be incremented or decremented.
It sounds a lot more complex than it is in practice!

The statement block performs some operation/s until the exit condition is met.
In this example the integer is declared and initialised within the loop, making the integers scope local in the loop. However the integer can be declared elsewhere, thus changing its scope.


We use a for loop to control how many patterns are used to make a picture:

As long as count's value, is less than the constant, patternsPerPicture the statements in the for loop will execute. Each time the loop is repeated the value of n is increased by one. If we changed the loop to start at one, then we would need to change the conditional to count<=patternsPerPicture+1;
When the for loop is finished the value of patternsPerPicture is changed to a random number between 2 and 50, the variables count and design are reset to zero before the for loop is entered again.

Another example of the for loop can be seen in the drawCircles(int) function.
Here the value of n is increased by the gap parameter. This for loop stops at a random number between the centre and edge of the display window.

Another branching structure uses a switch to determine which block of code to run. In Java the switch value must be an integer, a byte, a short, char or enumerated type.
Its basic outline follows this pattern:

**************************
In this example, if the switch statement has a value of 1, 3, or 4 then the statements in the code blocks for 1, 2 or 4 will execute. To stop them executing the code in the other cases break is used to exit the switch. In the case of the switch having a value of 4 the loop is exited by returning a value. break and return allow the switch block to be exited cleanly.
If switch has a value of 2 it doesnt have a code block of its own and continues so it executes the case 3 code block before exiting with break.
If the switch has a value of 5, 9 or some number that doesnt have a case statement then the default case will carried out before the block is exited.
In chunk 16 we have a large case statement (Line 40) which has cases for switch values of 1-9.
The design variable used in the switch is a random number between 1 and 9 inclusive.
In this section we will make chunk 16 more maintainable.
Firstly, it would be better if the pattern always started with a plain black background! Remove the statement on line 36 and add background(0) at line 35:


We can remove the line code in case 5 to its own function(line 63). Lets try omitting the break statement so the lines function is always covered up by the pattern in case 6.
Much better, we will leave lines in now!

Place the doLines function with the other functions

Looking at our case statements we can see that cases 1,3,4,6,7 and 9 all use duplicate code. Our switch block would be much neater and easier to maintain if we could encapsulate duplications in a function.
We will move case 1's code to a function called repeat shapes and place it with the other functions
******
The only difference between case 1 and case 3 is the interval variable. We can accomodate this by passing it as a parameter to the function.
It is now possible to remove all the while loops that use the drawCircles2 function with the new function. We still have while loops, that use the drawSquares and drawCircle3 functions. Lets deal with those cases too.
******
We can place a noFill() statement to the start of the for loop and remove all noFill() statements from the switch block.
If the case that makes filled circles didnt change colour so often we might see some more interesting shapes created. I added a 50/50 chance of this happening, to the else statement in the drawShapes method. See if you can work out how this works in the repeatShapes function.
By adjusting the repeatShapes function and removing some repetitive code from the case statements, our switch block now looks like this:
******
The one remaining change we could attempt is to do something about the cases where large filled shapes are drawn over the top of our funky patterns. Later in the book, we will learn how to use transparent colours, so for the moment lets leave our switch statement as it is.
Examine the switch block in the getSW function, you should notice something strange... The whole switch block can be replaced by one statement!
The getSW function now looks like this:
******
Our code is now much leaner and easier to maintain and this will help us when we start the next modification which will involve arrays.

An array is a can be thought of as a container for a collection of objects of the same type. This container, has an index, so that each object it holds, can be easily fetched. To declare an array:
int [] midxy;
arrays can be filled in a variety of ways. The capacity of the array can be set when it is declared and initialized:
boolean [] recs=new boolean[9];
It can also be initialized by listing its members:
int [] midxy={100,300,500};
A quick way of populating an array is to use a for loop:
The array recs contains 9 boolean values and we are going to use it to design a new function. So far all our patterns are positioned around the centre point of the screen. We are going to use the recs array to draw out a symetrical pattern, in a grid like the tic tac toe game.
Copy the following code into processing and run it.
*********
As you can see this is a quick sketch of our new shape function. Experiment by commenting and uncommenting the code between the asterisks. The statement after the last line of asterisks is drawing the square at the centre of the screen. It is using the value in midxy[1] as its centre point. Change one of the first 2 values in the rect function to a zero. Change both values to 2. See if you can place the square in each position in the grid. It would get tedious typing values like (width/3)/2+width/3*2 so we'll put them in an array.
The values in midxy will find the centre of each of the 9 squares no matter what the size of the display window is. (But it must be a square!) Try changing the size of the display window in the setup method.
In order to keep our pattern symmetrical we are going to place the 9 squares into 3 groups. There will be a corner group, a side group and the central square. The 9 squares dont all have to be used in the pattern, so we are going to use boolean values, to decide whether the squares are used. A boolean value can be true or false but not null.
Our first step will be to move the code from our experiment into the chunk 16 program. If we type /* */ we can simply paste in all the experimental code between the asterisks and Processing will ignore it.
Try to make a new function that uses the recs array to help manage drawing the 9 squares in our grid. Call the function drawSectors or any name you like.
We already have a function for populating the recs array with default values at the start of the function.
Use random numbers to decide whether each of the 3 groups are populated.
Write some code that sets the value of the relevant array position to true if a shape will be drawn there.
Write some code that uses the recs array to control where shapes will be drawn.
Use the rect(int,int,int,int)function to begin with.
Place a call to the repeatSectors function somewhere in the switch block of the draw function.
Add some randomisation to make the patterns vary as much as possible.
if you get stuck use the reference section in Processing, google what you are trying to do or check the solution provided at the end of this section.
This is a very challenging function to write and could take a good few hours to solve but its early days yet and this will get you thinking like a programmer. When your super duper function is completed you can use your artistic flair to make it dazzling!
************************
void drawSectors(){
...
}
************************

1 comment:

  1. Im not sure if the code in the text is part of the word count or not.
    I have deleted the comments section and most of the section on variables to get the word count down.
    Ive probably done this all wrong!
    So I wont start on the next version yet.

    ReplyDelete