first commit

This commit is contained in:
Boris
2024-01-15 20:14:10 +00:00
commit 8c81ee28b7
3106 changed files with 474415 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
#BlueJ package file
dependency1.from=Environment
dependency1.to=Agent
dependency1.type=UsesDependency
dependency2.from=Environment
dependency2.to=EnvironmentView
dependency2.type=UsesDependency
dependency3.from=EnvironmentView
dependency3.to=Environment
dependency3.type=UsesDependency
dependency4.from=EnvironmentView
dependency4.to=Agent
dependency4.type=UsesDependency
objectbench.height=76
objectbench.width=741
package.editor.height=412
package.editor.width=633
package.editor.x=70
package.editor.y=80
package.numDependencies=4
package.numTargets=3
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=428
readme.editor.y=103
target1.editor.height=977
target1.editor.width=1090
target1.editor.x=407
target1.editor.y=30
target1.height=50
target1.name=Agent
target1.naviview.expanded=false
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=80
target1.x=340
target1.y=140
target2.editor.height=818
target2.editor.width=999
target2.editor.x=415
target2.editor.y=180
target2.height=50
target2.name=EnvironmentView
target2.naviview.expanded=true
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=120
target2.x=210
target2.y=230
target3.editor.height=867
target3.editor.width=912
target3.editor.x=129
target3.editor.y=68
target3.height=50
target3.name=Environment
target3.naviview.expanded=true
target3.showInterface=false
target3.type=ClassTarget
target3.typeParameters=
target3.width=100
target3.x=120
target3.y=50

View File

@@ -0,0 +1,14 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=Automaton(int)
comment0.text=\n\ Create\ a\ 1D\ automaton\ consisting\ of\ the\ given\ number\ of\ cells.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=void\ print()
comment1.text=\n\ Print\ the\ current\ state\ of\ the\ automaton.\n
comment2.params=
comment2.target=void\ update()
comment2.text=\n\ Update\ the\ automaton\ to\ its\ next\ state.\n
comment3.params=
comment3.target=void\ reset()
comment3.text=\n\ Reset\ the\ automaton.\n
numComments=4

View File

@@ -0,0 +1,83 @@
import java.util.Arrays;
/**
* Model a 1D elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29 - version 1
*/
public class Automaton
{
// The number of cells.
private final int numberOfCells;
// The state of the cells.
private int[] state;
/**
* Create a 1D automaton consisting of the given number of cells.
* @param numberOfCells The number of cells in the automaton.
*/
public Automaton(int numberOfCells)
{
this.numberOfCells = numberOfCells;
state = new int[numberOfCells];
// Seed the automaton with a single 'on' cell in the middle.
state[numberOfCells / 2] = 1;
}
/**
* Print the current state of the automaton.
*/
public void print()
{
for(int cellValue : state) {
if(cellValue == 1) {
System.out.print("*");
}
else {
System.out.print(" ");
}
}
System.out.println();
}
/**
* Update the automaton to its next state.
*/
public void update()
{
// Build the new state in a separate array.
int[] nextState = new int[state.length];
// Naively update the state of each cell
// based on the state of its two neighbors.
for(int i = 0; i < state.length; i++) {
int left, center, right;
if(i == 0) {
left = 0;
}
else {
left = state[i - 1];
}
center = state[i];
if(i + 1 < state.length) {
right = state[i + 1];
}
else {
right = 0;
}
nextState[i] = (left + center + right) % 2;
}
state = nextState;
}
/**
* Reset the automaton.
*/
public void reset()
{
Arrays.fill(state, 0);
// Seed the automaton with a single 'on' cell.
state[numberOfCells / 2] = 1;
}
}

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=AutomatonController(int)
comment0.text=\n\ Create\ an\ AutomatonController.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=AutomatonController()
comment1.text=\n\ Create\ an\ AutomatonController\ with\n\ a\ default\ number\ of\ cells.\n
comment2.params=numSteps
comment2.target=void\ run(int)
comment2.text=\n\ Run\ the\ automaton\ for\ the\ given\ number\ of\ steps.\n\ @param\ numSteps\ The\ number\ of\ steps.\n
comment3.params=
comment3.target=void\ step()
comment3.text=\n\ Run\ the\ automaton\ for\ a\ single\ step.\n
comment4.params=
comment4.target=void\ reset()
comment4.text=\n\ Reset\ the\ automaton.\n
numComments=5

View File

@@ -0,0 +1,59 @@
/**
* Set up and control an elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class AutomatonController
{
// The automaton.
private Automaton auto;
/**
* Create an AutomatonController.
* @param numberOfCells The number of cells in the automaton.
*/
public AutomatonController(int numberOfCells)
{
auto = new Automaton(numberOfCells);
auto.print();
}
/**
* Create an AutomatonController with
* a default number of cells.
*/
public AutomatonController()
{
this(50);
}
/**
* Run the automaton for the given number of steps.
* @param numSteps The number of steps.
*/
public void run(int numSteps)
{
for(int step = 1; step <= numSteps; step++) {
step();
}
}
/**
* Run the automaton for a single step.
*/
public void step()
{
auto.update();
auto.print();
}
/**
* Reset the automaton.
*/
public void reset()
{
auto.reset();
auto.print();
}
}

View File

@@ -0,0 +1,11 @@
Project: automaton
Aothors: David J. Barnes and Michael Kölling
This project is part of the material of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 7.

View File

@@ -0,0 +1,45 @@
#BlueJ package file
dependency1.from=AutomatonController
dependency1.to=Automaton
dependency1.type=UsesDependency
objectbench.height=76
objectbench.width=737
package.editor.height=400
package.editor.width=629
package.editor.x=70
package.editor.y=80
package.numDependencies=1
package.numTargets=2
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=53
readme.editor.y=23
target1.editor.height=876
target1.editor.width=955
target1.editor.x=132
target1.editor.y=34
target1.height=50
target1.name=Automaton
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=90
target1.x=170
target1.y=160
target2.editor.height=777
target2.editor.width=994
target2.editor.x=65
target2.editor.y=23
target2.height=50
target2.name=AutomatonController
target2.naviview.expanded=false
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=160
target2.x=70
target2.y=70

View File

@@ -0,0 +1,14 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=Automaton(int)
comment0.text=\n\ Create\ a\ 1D\ automaton\ consisting\ of\ the\ given\ number\ of\ cells.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=void\ print()
comment1.text=\n\ Print\ the\ current\ state\ of\ the\ automaton.\n
comment2.params=
comment2.target=void\ update()
comment2.text=\n\ Update\ the\ automaton\ to\ its\ next\ state.\n
comment3.params=
comment3.target=void\ reset()
comment3.text=\n\ Reset\ the\ automaton.\n
numComments=4

View File

@@ -0,0 +1,69 @@
import java.util.Arrays;
/**
* Model a 1D elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29 - version 2
*/
public class Automaton
{
// The number of cells.
private final int numberOfCells;
// The state of the cells.
private int[] state;
/**
* Create a 1D automaton consisting of the given number of cells.
* @param numberOfCells The number of cells in the automaton.
*/
public Automaton(int numberOfCells)
{
this.numberOfCells = numberOfCells;
state = new int[numberOfCells];
// Seed the automaton with a single 'on' cell in the middle.
state[numberOfCells / 2] = 1;
}
/**
* Print the current state of the automaton.
*/
public void print()
{
for(int cellValue : state) {
System.out.print(cellValue == 1 ? "*" : " ");
}
System.out.println();
}
/**
* Update the automaton to its next state.
*/
public void update()
{
// Build the new state in a separate array.
int[] nextState = new int[state.length];
int left = 0;
int center = state[0];
for(int i = 0; i < state.length; i++) {
int right = i + 1 < state.length ? state[i + 1] : 0;
nextState[i] = (left + center + right) % 2;
left = center;
center = right;
}
state = nextState;
}
/**
* Reset the automaton.
*/
public void reset()
{
Arrays.fill(state, 0);
// Seed the automaton with a single 'on' cell.
state[numberOfCells / 2] = 1;
}
}

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=AutomatonController(int)
comment0.text=\n\ Create\ an\ AutomatonController.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=AutomatonController()
comment1.text=\n\ Create\ an\ AutomatonController\ with\n\ a\ default\ number\ of\ cells.\n
comment2.params=numSteps
comment2.target=void\ run(int)
comment2.text=\n\ Run\ the\ automaton\ for\ the\ given\ number\ of\ steps.\n\ @param\ numSteps\ The\ number\ of\ steps.\n
comment3.params=
comment3.target=void\ step()
comment3.text=\n\ Run\ the\ automaton\ for\ a\ single\ step.\n
comment4.params=
comment4.target=void\ reset()
comment4.text=\n\ Reset\ the\ automaton.\n
numComments=5

View File

@@ -0,0 +1,60 @@
/**
* Set up and control an elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class AutomatonController
{
// The automaton.
private Automaton auto;
/**
* Create an AutomatonController.
* @param numberOfCells The number of cells in the automaton.
*/
public AutomatonController(int numberOfCells)
{
auto = new Automaton(numberOfCells);
auto.print();
}
/**
* Create an AutomatonController with
* a default number of cells.
*/
public AutomatonController()
{
this(50);
}
/**
* Run the automaton for the given number of steps.
* @param numSteps The number of steps.
*/
public void run(int numSteps)
{
for(int step = 1; step <= numSteps; step++) {
step();
}
}
/**
* Run the automaton for a single step.
*/
public void step()
{
auto.update();
auto.print();
}
/**
* Reset the automaton.
*/
public void reset()
{
auto.reset();
auto.print();
}
}

View File

@@ -0,0 +1,11 @@
Project: automaton
Aothors: David J. Barnes and Michael Kölling
This project is part of the material of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 7.

View File

@@ -0,0 +1,45 @@
#BlueJ package file
dependency1.from=AutomatonController
dependency1.to=Automaton
dependency1.type=UsesDependency
objectbench.height=76
objectbench.width=737
package.editor.height=400
package.editor.width=629
package.editor.x=70
package.editor.y=80
package.numDependencies=1
package.numTargets=2
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=53
readme.editor.y=23
target1.editor.height=774
target1.editor.width=867
target1.editor.x=454
target1.editor.y=65
target1.height=50
target1.name=Automaton
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=90
target1.x=170
target1.y=160
target2.editor.height=777
target2.editor.width=994
target2.editor.x=286
target2.editor.y=23
target2.height=50
target2.name=AutomatonController
target2.naviview.expanded=false
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=160
target2.x=70
target2.y=70

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=Automaton(int)
comment0.text=\n\ Create\ a\ 1D\ automaton\ consisting\ of\ the\ given\ number\ of\ cells.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=void\ print()
comment1.text=\n\ Print\ the\ current\ state\ of\ the\ automaton.\n
comment2.params=
comment2.target=void\ update()
comment2.text=\n\ Update\ the\ automaton\ to\ its\ next\ state.\n
comment3.params=
comment3.target=void\ reset()
comment3.text=\n\ Reset\ the\ automaton.\n
comment4.params=left\ center\ right
comment4.target=int\ calculateNextState(int,\ int,\ int)
comment4.text=\n\ Calculate\ the\ next\ state\ of\ the\ center\ cell\n\ given\ current\ left,\ center\ and\ right\ cell\n\ values.\n\ This\ implements\ Wolfram\ code\ 110.\n\ @see\ https\://en.wikipedia.org/wiki/Wolfram_code\n\ @param\ left\ The\ state\ of\ the\ cell\ to\ the\ left\ of\ center.\n\ @param\ center\ The\ state\ of\ the\ center\ cell.\n\ @param\ right\ The\ state\ of\ the\ cell\ to\ the\ right\ of\ center.\n\ @return\ The\ new\ value\ of\ center\ (0\ or\ 1).\n
numComments=5

View File

@@ -0,0 +1,86 @@
import java.util.*;
/**
* Model a 1D elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29 - version 3
*/
public class Automaton
{
// The number of cells.
private final int numberOfCells;
// The state of the cells.
private int[] state;
/**
* Create a 1D automaton consisting of the given number of cells.
* @param numberOfCells The number of cells in the automaton.
*/
public Automaton(int numberOfCells)
{
this.numberOfCells = numberOfCells;
// Allow an extra element to avoid 'fencepost' errors.
state = new int[numberOfCells + 1];
// Seed the automaton with a single 'on' cell.
state[numberOfCells / 2] = 1;
}
/**
* Print the current state of the automaton.
*/
public void print()
{
for(int cellValue : state) {
System.out.print(cellValue == 1 ? "*" : " ");
}
System.out.println();
}
/**
* Update the automaton to its next state.
*/
public void update()
{
// Build the new state in a separate array.
int[] nextState = new int[state.length];
// Use 0 for the non-existent value to the left of
// the first cell.
int left = 0;
int center = state[0];
for(int i = 0; i < numberOfCells; i++) {
int right = state[i + 1];
nextState[i] = calculateNextState(left, center, right);
left = center;
center = right;
}
state = nextState;
}
/**
* Reset the automaton.
*/
public void reset()
{
Arrays.fill(state, 0);
// Seed the automaton with a single 'on' cell in the middle.
state[numberOfCells / 2] = 1;
}
/**
* Calculate the next state of the center cell
* given current left, center and right cell
* values.
* This implements Wolfram code 110.
* @see https://en.wikipedia.org/wiki/Wolfram_code
* @param left The state of the cell to the left of center.
* @param center The state of the center cell.
* @param right The state of the cell to the right of center.
* @return The new value of center (0 or 1).
*/
private int calculateNextState(int left, int center, int right)
{
return (center + right + center * right + left * center * right) % 2;
}
}

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=AutomatonController(int)
comment0.text=\n\ Create\ an\ AutomatonController.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=AutomatonController()
comment1.text=\n\ Create\ an\ AutomatonController\ with\n\ a\ default\ number\ of\ cells.\n
comment2.params=numSteps
comment2.target=void\ run(int)
comment2.text=\n\ Run\ the\ automaton\ for\ the\ given\ number\ of\ steps.\n\ @param\ numSteps\ The\ number\ of\ steps.\n
comment3.params=
comment3.target=void\ step()
comment3.text=\n\ Run\ the\ automaton\ for\ a\ single\ step.\n
comment4.params=
comment4.target=void\ reset()
comment4.text=\n\ Reset\ the\ automaton.\n
numComments=5

View File

@@ -0,0 +1,59 @@
/**
* Set up and control an elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class AutomatonController
{
// The automaton.
private Automaton auto;
/**
* Create an AutomatonController.
* @param numberOfCells The number of cells in the automaton.
*/
public AutomatonController(int numberOfCells)
{
auto = new Automaton(numberOfCells);
auto.print();
}
/**
* Create an AutomatonController with
* a default number of cells.
*/
public AutomatonController()
{
this(50);
}
/**
* Run the automaton for the given number of steps.
* @param numSteps The number of steps.
*/
public void run(int numSteps)
{
for(int step = 1; step <= numSteps; step++) {
step();
}
}
/**
* Run the automaton for a single step.
*/
public void step()
{
auto.update();
auto.print();
}
/**
* Reset the automaton.
*/
public void reset()
{
auto.reset();
auto.print();
}
}

View File

@@ -0,0 +1,11 @@
Project: automaton
Aothors: David J. Barnes and Michael Kölling
This project is part of the material of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 7.

View File

@@ -0,0 +1,45 @@
#BlueJ package file
dependency1.from=AutomatonController
dependency1.to=Automaton
dependency1.type=UsesDependency
objectbench.height=76
objectbench.width=737
package.editor.height=400
package.editor.width=629
package.editor.x=70
package.editor.y=80
package.numDependencies=1
package.numTargets=2
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=53
readme.editor.y=23
target1.editor.height=769
target1.editor.width=980
target1.editor.x=375
target1.editor.y=141
target1.height=50
target1.name=Automaton
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=90
target1.x=170
target1.y=160
target2.editor.height=777
target2.editor.width=994
target2.editor.x=286
target2.editor.y=23
target2.height=50
target2.name=AutomatonController
target2.naviview.expanded=false
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=160
target2.x=70
target2.y=70

View File

@@ -0,0 +1,20 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=Automaton(int)
comment0.text=\n\ Create\ a\ 1D\ automaton\ consisting\ of\ the\ given\ number\ of\ cells.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=void\ print()
comment1.text=\n\ Print\ the\ current\ state\ of\ the\ automaton.\n
comment2.params=
comment2.target=void\ update()
comment2.text=\n\ Update\ the\ automaton\ to\ its\ next\ state.\n
comment3.params=
comment3.target=void\ reset()
comment3.text=\n\ Reset\ the\ automaton.\n
comment4.params=left\ center\ right
comment4.target=int\ calculateNextState(int,\ int,\ int)
comment4.text=\n\ Calculate\ the\ next\ state\ of\ the\ center\ cell\n\ given\ current\ left,\ center\ and\ right\ cell\n\ values.\n\ This\ implements\ Wolfram\ code\ 110.\n\ @see\ https\://en.wikipedia.org/wiki/Wolfram_code\n\ @param\ left\ The\ state\ of\ the\ cell\ to\ the\ left\ of\ center.\n\ @param\ center\ The\ state\ of\ the\ center\ cell.\n\ @param\ right\ The\ state\ of\ the\ cell\ to\ the\ right\ of\ center.\n\ @return\ The\ new\ value\ of\ center\ (0\ or\ 1).\n
comment5.params=left\ center\ right
comment5.target=int\ encodeTriplet(int,\ int,\ int)
comment5.text=\n\ Encode\ the\ 1/0\ triplet\ (left,\ center,\ right)\ as\ an\n\ integer\ value\ in\ the\ range\ 0-7.\n\ @param\ left\ The\ state\ of\ the\ cell\ to\ the\ left\ of\ center\ (0\ or\ 1).\n\ @param\ center\ The\ state\ of\ the\ center\ cell\ (0\ or\ 1).\n\ @param\ right\ The\ state\ of\ the\ cell\ to\ the\ right\ of\ center\ (0\ or\ 1).\n\ @return\ (left,center,right)\ interpreted\ as\ a\ 3-bit\ value.\n
numComments=6

View File

@@ -0,0 +1,104 @@
import java.util.*;
/**
* Model a 1D elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29 - version 4
*/
public class Automaton
{
// The number of cells.
private final int numberOfCells;
// The state of the cells.
private int[] state;
// The state table encoding the next-state changes.
private int[] stateTable;
/**
* Create a 1D automaton consisting of the given number of cells.
* @param numberOfCells The number of cells in the automaton.
*/
public Automaton(int numberOfCells)
{
this.numberOfCells = numberOfCells;
// Allow an extra element to avoid 'fencepost' errors.
state = new int[numberOfCells + 1];
stateTable = new int[] {
0, 1, 0, 0, 1, 0, 0, 1, // Wolfram code 146
};
// Seed the automaton with a single 'on' cell.
state[numberOfCells / 2] = 1;
}
/**
* Print the current state of the automaton.
*/
public void print()
{
for(int cellValue : state) {
System.out.print(cellValue == 1 ? "*" : " ");
}
System.out.println();
}
/**
* Update the automaton to its next state.
*/
public void update()
{
// Build the new state in a separate array.
int[] nextState = new int[state.length];
// Use 0 for the non-existent value to the left of
// the first cell.
int left = 0;
int center = state[0];
for(int i = 0; i < numberOfCells; i++) {
int right = state[i + 1];
nextState[i] = calculateNextState(left, center, right);
left = center;
center = right;
}
state = nextState;
}
/**
* Reset the automaton.
*/
public void reset()
{
Arrays.fill(state, 0);
// Seed the automaton with a single 'on' cell in the middle.
state[numberOfCells / 2] = 1;
}
/**
* Calculate the next state of the center cell
* given current left, center and right cell
* values.
* This implements Wolfram code 110.
* @see https://en.wikipedia.org/wiki/Wolfram_code
* @param left The state of the cell to the left of center.
* @param center The state of the center cell.
* @param right The state of the cell to the right of center.
* @return The new value of center (0 or 1).
*/
private int calculateNextState(int left, int center, int right)
{
return stateTable[encodeTriplet(left, center, right)];
}
/**
* Encode the 1/0 triplet (left, center, right) as an
* integer value in the range 0-7.
* @param left The state of the cell to the left of center (0 or 1).
* @param center The state of the center cell (0 or 1).
* @param right The state of the cell to the right of center (0 or 1).
* @return (left,center,right) interpreted as a 3-bit value.
*/
private int encodeTriplet(int left, int center, int right)
{
return left * 4 + center * 2 + right;
}
}

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=numberOfCells
comment0.target=AutomatonController(int)
comment0.text=\n\ Create\ an\ AutomatonController.\n\ @param\ numberOfCells\ The\ number\ of\ cells\ in\ the\ automaton.\n
comment1.params=
comment1.target=AutomatonController()
comment1.text=\n\ Create\ an\ AutomatonController\ with\n\ a\ default\ number\ of\ cells.\n
comment2.params=numSteps
comment2.target=void\ run(int)
comment2.text=\n\ Run\ the\ automaton\ for\ the\ given\ number\ of\ steps.\n\ @param\ numSteps\ The\ number\ of\ steps.\n
comment3.params=
comment3.target=void\ step()
comment3.text=\n\ Run\ the\ automaton\ for\ a\ single\ step.\n
comment4.params=
comment4.target=void\ reset()
comment4.text=\n\ Reset\ the\ automaton.\n
numComments=5

View File

@@ -0,0 +1,59 @@
/**
* Set up and control an elementary cellular automaton.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class AutomatonController
{
// The automaton.
private Automaton auto;
/**
* Create an AutomatonController.
* @param numberOfCells The number of cells in the automaton.
*/
public AutomatonController(int numberOfCells)
{
auto = new Automaton(numberOfCells);
auto.print();
}
/**
* Create an AutomatonController with
* a default number of cells.
*/
public AutomatonController()
{
this(50);
}
/**
* Run the automaton for the given number of steps.
* @param numSteps The number of steps.
*/
public void run(int numSteps)
{
for(int step = 1; step <= numSteps; step++) {
step();
}
}
/**
* Run the automaton for a single step.
*/
public void step()
{
auto.update();
auto.print();
}
/**
* Reset the automaton.
*/
public void reset()
{
auto.reset();
auto.print();
}
}

View File

@@ -0,0 +1,11 @@
Project: automaton
Aothors: David J. Barnes and Michael Kölling
This project is part of the material of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 7.

View File

@@ -0,0 +1,45 @@
#BlueJ package file
dependency1.from=AutomatonController
dependency1.to=Automaton
dependency1.type=UsesDependency
objectbench.height=76
objectbench.width=737
package.editor.height=400
package.editor.width=629
package.editor.x=70
package.editor.y=80
package.numDependencies=1
package.numTargets=2
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=53
readme.editor.y=23
target1.editor.height=720
target1.editor.width=938
target1.editor.x=449
target1.editor.y=137
target1.height=50
target1.name=Automaton
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=90
target1.x=170
target1.y=160
target2.editor.height=777
target2.editor.width=994
target2.editor.x=286
target2.editor.y=23
target2.height=50
target2.name=AutomatonController
target2.naviview.expanded=false
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=160
target2.x=70
target2.y=70

View File

@@ -0,0 +1,20 @@
#BlueJ class context
comment0.params=
comment0.target=Cell()
comment0.text=\n\ Set\ the\ initial\ state\ to\ be\ DEAD.\n
comment1.params=initialState
comment1.target=Cell(int)
comment1.text=\n\ Set\ the\ initial\ state.\n\ @param\ initialState\ The\ initial\ state\n
comment2.params=
comment2.target=int\ getNextState()
comment2.text=\n\ Determine\ this\ cell's\ next\ state,\ based\ on\ the\n\ state\ of\ its\ neighbors.\n\ This\ is\ an\ implementation\ of\ the\ rules\ for\ Brian's\ Brain.\n\ @return\ The\ next\ state.\n
comment3.params=neighborList
comment3.target=void\ setNeighbors(java.util.ArrayList)
comment3.text=\n\ Receive\ the\ list\ of\ neighboring\ cells\ and\ take\n\ a\ copy.\n\ @param\ neighborList\ Neighboring\ cells.\n
comment4.params=
comment4.target=int\ getState()
comment4.text=\n\ Get\ the\ state\ of\ this\ cell.\n\ @return\ The\ state.\n
comment5.params=state
comment5.target=void\ setState(int)
comment5.text=\n\ Set\ the\ state\ of\ this\ cell.\n\ @param\ The\ state.\n
numComments=6

View File

@@ -0,0 +1,97 @@
import java.util.*;
/**
* A cell in a 2D cellular automaton.
* The cell has multiple possible states.
* This is an implementation of the rules for Brian's Brain.
* @see https://en.wikipedia.org/wiki/Brian%27s_Brain
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class Cell
{
// The possible states.
public static final int ALIVE = 0, DEAD = 1, DYING = 2;
// The number of possible states.
public static final int NUM_STATES = 3;
// The cell's state.
private int state;
// The cell's neighbors.
private Cell[] neighbors;
/**
* Set the initial state to be DEAD.
*/
public Cell()
{
this(DEAD);
}
/**
* Set the initial state.
* @param initialState The initial state
*/
public Cell(int initialState)
{
state = initialState;
neighbors = new Cell[0];
}
/**
* Determine this cell's next state, based on the
* state of its neighbors.
* This is an implementation of the rules for Brian's Brain.
* @return The next state.
*/
public int getNextState()
{
if(state == DEAD) {
// Count the number of neighbors that are alive.
int aliveCount = 0;
for(Cell n : neighbors) {
if(n.getState() == ALIVE) {
aliveCount++;
}
}
return aliveCount == 2 ? ALIVE : DEAD;
}
else if(state == DYING) {
return DEAD;
}
else {
return DYING;
}
}
/**
* Receive the list of neighboring cells and take
* a copy.
* @param neighborList Neighboring cells.
*/
public void setNeighbors(ArrayList<Cell> neighborList)
{
neighbors = new Cell[neighborList.size()];
neighborList.toArray(neighbors);
}
/**
* Get the state of this cell.
* @return The state.
*/
public int getState()
{
return state;
}
/**
* Set the state of this cell.
* @param The state.
*/
public void setState(int state)
{
this.state = state;
}
}

View File

@@ -0,0 +1,29 @@
#BlueJ class context
comment0.params=
comment0.target=Environment()
comment0.text=\n\ Create\ an\ environment\ with\ the\ default\ size.\n
comment1.params=numRows\ numCols
comment1.target=Environment(int,\ int)
comment1.text=\n\ Create\ an\ environment\ with\ the\ given\ size.\n\ @param\ numRows\ The\ number\ of\ rows.\n\ @param\ numCols\ The\ number\ of\ cols;\n
comment2.params=
comment2.target=void\ step()
comment2.text=\n\ Run\ the\ automaton\ for\ one\ step.\n
comment3.params=
comment3.target=void\ reset()
comment3.text=\n\ Reset\ the\ state\ of\ the\ automaton\ to\ all\ DEAD.\n
comment4.params=
comment4.target=void\ randomize()
comment4.text=\n\ Generate\ a\ random\ setup.\n
comment5.params=row\ col\ state
comment5.target=void\ setCellState(int,\ int,\ int)
comment5.text=\n\ Set\ the\ state\ of\ one\ cell.\n\ @param\ row\ The\ cell's\ row.\n\ @param\ col\ The\ cell's\ col.\n\ @param\ state\ The\ cell's\ state.\n
comment6.params=
comment6.target=Cell[][]\ getCells()
comment6.text=\n\ Return\ the\ grid\ of\ cells.\n\ @return\ The\ grid\ of\ cells.\n
comment7.params=numRows\ numCols
comment7.target=void\ setup(int,\ int)
comment7.text=\n\ Setup\ a\ new\ environment\ of\ the\ given\ size.\n\ @param\ numRows\ The\ number\ of\ rows.\n\ @param\ numCols\ The\ number\ of\ cols;\n
comment8.params=
comment8.target=void\ setupNeighbors()
comment8.text=\n\ Give\ to\ a\ cell\ a\ list\ of\ its\ neighbors.\n
numComments=9

View File

@@ -0,0 +1,161 @@
import java.security.SecureRandom;
import java.util.*;
/**
* Maintain the environment for a 2D cellular automaton.
*
* @author David J. Barnes
* @version 2016.02.29
*/
public class Environment
{
// Default size for the environment.
private static final int DEFAULT_ROWS = 50;
private static final int DEFAULT_COLS = 50;
// The grid of cells.
private Cell[][] cells;
// Visualization of the environment.
private final EnvironmentView view;
/**
* Create an environment with the default size.
*/
public Environment()
{
this(DEFAULT_ROWS, DEFAULT_COLS);
}
/**
* Create an environment with the given size.
* @param numRows The number of rows.
* @param numCols The number of cols;
*/
public Environment(int numRows, int numCols)
{
setup(numRows, numCols);
randomize();
view = new EnvironmentView(this, numRows, numCols);
view.showCells();
}
/**
* Run the automaton for one step.
*/
public void step()
{
int numRows = cells.length;
int numCols = cells[0].length;
// Build a record of the next state of each cell.
int[][] nextStates = new int[numRows][numCols];
// Ask each cell to determine its next state.
for(int row = 0; row < numRows; row++) {
int[] rowOfStates = nextStates[row];
for(int col = 0; col < numCols; col++) {
rowOfStates[col] = cells[row][col].getNextState();
}
}
// Update the cells' states.
for(int row = 0; row < numRows; row++) {
int[] rowOfStates = nextStates[row];
for(int col = 0; col < numCols; col++) {
setCellState(row, col, rowOfStates[col]);
}
}
}
/**
* Reset the state of the automaton to all DEAD.
*/
public void reset()
{
int numRows = cells.length;
int numCols = cells[0].length;
for(int row = 0; row < numRows; row++) {
for(int col = 0; col < numCols; col++) {
setCellState(row, col, Cell.DEAD);
}
}
}
/**
* Generate a random setup.
*/
public void randomize()
{
int numRows = cells.length;
int numCols = cells[0].length;
SecureRandom rand = new SecureRandom();
for(int row = 0; row < numRows; row++) {
for(int col = 0; col < numCols; col++) {
setCellState(row, col, rand.nextInt(Cell.NUM_STATES));
}
}
}
/**
* Set the state of one cell.
* @param row The cell's row.
* @param col The cell's col.
* @param state The cell's state.
*/
public void setCellState(int row, int col, int state)
{
cells[row][col].setState(state);
}
/**
* Return the grid of cells.
* @return The grid of cells.
*/
public Cell[][] getCells()
{
return cells;
}
/**
* Setup a new environment of the given size.
* @param numRows The number of rows.
* @param numCols The number of cols;
*/
private void setup(int numRows, int numCols)
{
cells = new Cell[numRows][numCols];
for(int row = 0; row < numRows; row++) {
for (int col = 0; col < numCols; col++) {
cells[row][col] = new Cell();
}
}
setupNeighbors();
}
/**
* Give to a cell a list of its neighbors.
*/
private void setupNeighbors()
{
int numRows = cells.length;
int numCols = cells[0].length;
// Allow for 8 neighbors plus the cell.
ArrayList<Cell> neighbors = new ArrayList<>(9);
for(int row = 0; row < numRows; row++) {
for(int col = 0; col < numCols; col++) {
Cell cell = cells[row][col];
// This process will also include the cell.
for(int dr = -1; dr <= 1; dr++) {
for(int dc = -1; dc <= 1; dc++) {
int nr = (numRows + row + dr) % numRows;
int nc = (numCols + col + dc) % numCols;
neighbors.add(cells[nr][nc]);
}
}
// The neighbours should not include the cell at
// (row,col) so remove it.
neighbors.remove(cell);
cell.setNeighbors(neighbors);
neighbors.clear();
}
}
}
}

View File

@@ -0,0 +1,17 @@
#BlueJ class context
comment0.params=env\ rows\ cols
comment0.target=EnvironmentView(Environment,\ int,\ int)
comment0.text=\n\ Constructor\ for\ objects\ of\ class\ EnvironmentView\n\ @param\ env\n
comment1.params=rows\ cols
comment1.target=void\ setupGrid(int,\ int)
comment1.text=\n\ Setup\ a\ new\ environment\ of\ the\ given\ size.\n\ @param\ rows\ The\ number\ of\ rows.\n\ @param\ cols\ The\ number\ of\ cols;\n
comment2.params=
comment2.target=void\ showCells()
comment2.text=\n\ Show\ the\ states\ of\ the\ cells.\n
comment3.params=
comment3.target=void\ setupControls()
comment3.text=\n\ Set\ up\ the\ animation\ controls.\n
comment4.params=speedPercentage
comment4.target=void\ setDelay(int)
comment4.text=\n\ Set\ the\ animation\ delay.\n\ @param\ speedPercentage\ (100-speedPercentage)\ as\ a\ percentage\ of\ the\ LONGEST_DELAY.\n
numComments=5

View File

@@ -0,0 +1,271 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
/**
* A GUI for the environment, with runtime controls.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class EnvironmentView extends JFrame
{
// The longest delay for the animation, in milliseconds.
private static final int LONGEST_DELAY = 1000;
// Colors for the different cell states.
private static final Color[] colors = {
Color.WHITE, // Alive
new Color(68, 100, 129), // Dead
new Color(204, 196, 72), // Dying
};
private GridView view;
private final Environment env;
private boolean running;
private int delay;
/**
* Constructor for objects of class EnvironmentView
* @param env
*/
public EnvironmentView(Environment env, int rows, int cols)
{
super("2D Cellular Automaton");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocation(20, 20);
this.env = env;
this.running = false;
setDelay(50);
setupControls();
setupGrid(rows, cols);
pack();
setVisible(true);
}
/**
* Setup a new environment of the given size.
* @param rows The number of rows.
* @param cols The number of cols;
*/
private void setupGrid(int rows, int cols)
{
Container contents = getContentPane();
view = new GridView(rows, cols);
contents.add(view, BorderLayout.CENTER);
}
/**
* Show the states of the cells.
*/
public void showCells()
{
Cell[][] cells = env.getCells();
if(!isVisible()) {
setVisible(true);
}
view.preparePaint();
for(int row = 0; row < cells.length; row++) {
Cell[] cellRow = cells[row];
int numCols = cellRow.length;
for(int col = 0; col < numCols; col++) {
int state = cellRow[col].getState();
view.drawMark(col, row, colors[state]);
}
}
view.repaint();
}
/**
* Set up the animation controls.
*/
private void setupControls()
{
// Continuous running.
final JButton run = new JButton("Run");
run.addActionListener(e -> {
if(!running) {
running = true;
try {
new Runner().execute();
}
catch(Exception ex) {
}
}
});
// Single stepping.
final JButton step = new JButton("Step");
step.addActionListener(e -> {
running = false;
env.step();
showCells();
});
// Pause the animation.
final JButton pause = new JButton("Pause");
pause.addActionListener(e -> running = false);
// Reset of the environment
final JButton reset = new JButton("Reset");
reset.addActionListener(e -> {
running = false;
env.reset();
showCells();
});
// Randomize the environment.
final JButton randomize = new JButton("Random");
randomize.addActionListener(e -> {
running = false;
env.randomize();
showCells();
});
Container contents = getContentPane();
// A speed controller.
final JSlider speedSlider = new JSlider(0, 100);
speedSlider.addChangeListener(e -> {
setDelay(speedSlider.getValue());
});
Container speedPanel = new JPanel();
speedPanel.setLayout(new GridLayout(2, 1));
speedPanel.add(new JLabel("Animation Speed", SwingConstants.CENTER));
speedPanel.add(speedSlider);
contents.add(speedPanel, BorderLayout.NORTH);
// Place the button controls.
JPanel controls = new JPanel();
controls.add(run);
controls.add(step);
controls.add(pause);
controls.add(reset);
controls.add(randomize);
contents.add(controls, BorderLayout.SOUTH);
}
/**
* Set the animation delay.
* @param speedPercentage (100-speedPercentage) as a percentage of the LONGEST_DELAY.
*/
private void setDelay(int speedPercentage)
{
delay = (int) ((100.0 - speedPercentage) * LONGEST_DELAY / 100);
}
/**
* Provide stepping of the animation.
*/
private class Runner extends SwingWorker<Boolean, Void>
{
@Override
/**
* Repeatedly single-step the environment as long
* as the animation is running.
*/
public Boolean doInBackground()
{
while(running) {
env.step();
showCells();
try {
Thread.sleep(delay);
}
catch(InterruptedException e) {
}
}
return true;
}
}
/**
* Provide a graphical view of a rectangular grid.
*/
@SuppressWarnings("serial")
private class GridView extends JPanel
{
private final int GRID_VIEW_SCALING_FACTOR = 10;
private final int gridWidth, gridHeight;
private int xScale, yScale;
private Dimension size;
private Graphics g;
private Image fieldImage;
/**
* Create a new GridView component.
*/
public GridView(int height, int width)
{
gridHeight = height;
gridWidth = width;
size = new Dimension(0, 0);
}
/**
* Tell the GUI manager how big we would like to be.
*/
@Override
public Dimension getPreferredSize()
{
return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
gridHeight * GRID_VIEW_SCALING_FACTOR);
}
/**
* Prepare for a new round of painting. Since the component
* may be resized, compute the scaling factor again.
*/
public void preparePaint()
{
if(! size.equals(getSize())) {
size = getSize();
fieldImage = view.createImage(size.width, size.height);
g = fieldImage.getGraphics();
xScale = size.width / gridWidth;
if(xScale < 1) {
xScale = GRID_VIEW_SCALING_FACTOR;
}
yScale = size.height / gridHeight;
if(yScale < 1) {
yScale = GRID_VIEW_SCALING_FACTOR;
}
}
}
/**
* Paint on grid location on this field in a given color.
*/
public void drawMark(int x, int y, Color color)
{
g.setColor(color);
g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
}
/**
* The field view component needs to be redisplayed. Copy the
* internal image to screen.
*/
@Override
public void paintComponent(Graphics g)
{
if(fieldImage != null) {
Dimension currentSize = getSize();
if(size.equals(currentSize)) {
g.drawImage(fieldImage, 0, 0, null);
}
else {
// Rescale the previous image.
g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
}
}
}
}
}

View File

@@ -0,0 +1,15 @@
Project: brain
Aothors: David J. Barnes and Michael Kölling
This project is part of the material of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
It is discussed in chapter 7.
An implementation of the 2D cellular automaton known as Brian's Brain.
See https://en.wikipedia.org/wiki/Brian%27s_Brain

View File

@@ -0,0 +1,67 @@
#BlueJ package file
dependency1.from=Environment
dependency1.to=Cell
dependency1.type=UsesDependency
dependency2.from=Environment
dependency2.to=EnvironmentView
dependency2.type=UsesDependency
dependency3.from=EnvironmentView
dependency3.to=Environment
dependency3.type=UsesDependency
dependency4.from=EnvironmentView
dependency4.to=Cell
dependency4.type=UsesDependency
objectbench.height=76
objectbench.width=741
package.editor.height=412
package.editor.width=633
package.editor.x=70
package.editor.y=80
package.numDependencies=4
package.numTargets=3
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=700
readme.editor.width=900
readme.editor.x=53
readme.editor.y=23
target1.editor.height=818
target1.editor.width=999
target1.editor.x=798
target1.editor.y=92
target1.height=50
target1.name=EnvironmentView
target1.naviview.expanded=false
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=120
target1.x=210
target1.y=230
target2.editor.height=945
target2.editor.width=954
target2.editor.x=206
target2.editor.y=214
target2.height=50
target2.name=Environment
target2.naviview.expanded=true
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=100
target2.x=120
target2.y=50
target3.editor.height=777
target3.editor.width=969
target3.editor.x=88
target3.editor.y=23
target3.height=50
target3.name=Cell
target3.naviview.expanded=true
target3.showInterface=false
target3.type=ClassTarget
target3.typeParameters=
target3.width=80
target3.x=340
target3.y=140

View File

@@ -0,0 +1,14 @@
#BlueJ class context
comment0.params=
comment0.target=LogAnalyzer()
comment0.text=\n\ Create\ an\ object\ to\ analyze\ hourly\ web\ accesses.\n
comment1.params=
comment1.target=void\ analyzeHourlyData()
comment1.text=\n\ Analyze\ the\ hourly\ access\ data\ from\ the\ log\ file.\n
comment2.params=
comment2.target=void\ printHourlyCounts()
comment2.text=\n\ Print\ the\ hourly\ counts.\n\ These\ should\ have\ been\ set\ with\ a\ prior\n\ call\ to\ analyzeHourlyData.\n
comment3.params=
comment3.target=void\ printData()
comment3.text=\n\ Print\ the\ lines\ of\ data\ read\ by\ the\ LogfileReader\n
numComments=4

View File

@@ -0,0 +1,58 @@
/**
* Read web server data and analyse hourly access patterns.
*
* @author David J. Barnes and Michael Kölling.
* @version 2016.02.29
*/
public class LogAnalyzer
{
// Where to calculate the hourly access counts.
private int[] hourCounts;
// Use a LogfileReader to access the data.
private LogfileReader reader;
/**
* Create an object to analyze hourly web accesses.
*/
public LogAnalyzer()
{
// Create the array object to hold the hourly
// access counts.
hourCounts = new int[24];
// Create the reader to obtain the data.
reader = new LogfileReader();
}
/**
* Analyze the hourly access data from the log file.
*/
public void analyzeHourlyData()
{
while(reader.hasNext()) {
LogEntry entry = reader.next();
int hour = entry.getHour();
hourCounts[hour]++;
}
}
/**
* Print the hourly counts.
* These should have been set with a prior
* call to analyzeHourlyData.
*/
public void printHourlyCounts()
{
System.out.println("Hr: Count");
for(int hour = 0; hour < hourCounts.length; hour++) {
System.out.println(hour + ": " + hourCounts[hour]);
}
}
/**
* Print the lines of data read by the LogfileReader
*/
public void printData()
{
reader.printData();
}
}

View File

@@ -0,0 +1,26 @@
#BlueJ class context
comment0.params=logline
comment0.target=LogEntry(java.lang.String)
comment0.text=\n\ Decompose\ a\ log\ line\ so\ that\ the\ individual\ fields\n\ are\ available.\n\ @param\ logline\ A\ single\ line\ from\ the\ log.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ This\ should\ be\ in\ the\ format\:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ year\ month\ day\ hour\ minute\ etc.\n
comment1.params=year\ month\ day\ hour\ minute
comment1.target=LogEntry(int,\ int,\ int,\ int,\ int)
comment1.text=\n\ Create\ a\ LogEntry\ from\ the\ individual\ components.\n\ @param\ year\ The\ year\n\ @param\ month\ The\ month\ (1-12)\n\ @param\ day\ The\ day\ (1-31)\n\ @param\ hour\ The\ hour\ (0-23)\n\ @param\ minute\ The\ minute\ (0-59)\n
comment2.params=
comment2.target=int\ getHour()
comment2.text=\n\ Return\ the\ hour.\n\ @return\ The\ hour\ field\ from\ the\ log\ line.\n
comment3.params=
comment3.target=int\ getMinute()
comment3.text=\n\ Return\ the\ minute.\n\ @return\ The\ minute\ field\ from\ the\ log\ line.\n
comment4.params=
comment4.target=java.lang.String\ toString()
comment4.text=\n\ Create\ a\ string\ representation\ of\ the\ data.\n\ This\ is\ not\ necessarily\ identical\ with\ the\n\ text\ of\ the\ original\ log\ line.\n\ @return\ A\ string\ representing\ the\ data\ of\ this\ entry.\n
comment5.params=otherEntry
comment5.target=int\ compareTo(LogEntry)
comment5.text=\n\ Compare\ the\ date/time\ combination\ of\ this\ log\ entry\n\ with\ another.\n\ @param\ otherEntry\ The\ other\ entry\ to\ compare\ against.\n\ @return\ A\ negative\ value\ if\ this\ entry\ comes\ before\ the\ other.\n\ \ \ \ \ \ \ \ \ A\ positive\ value\ if\ this\ entry\ comes\ after\ the\ other.\n\ \ \ \ \ \ \ \ \ Zero\ if\ the\ entries\ are\ the\ same.\n
comment6.params=
comment6.target=java.util.Calendar\ getWhen()
comment6.text=\n\ Return\ the\ Calendar\ object\ representing\ this\ event.\n\ @return\ The\ Calendar\ for\ this\ event.\n
comment7.params=
comment7.target=void\ setWhen()
comment7.text=\n\ Create\ an\ equivalent\ Calendar\ object\ from\ the\ data\ values.\n
numComments=8

View File

@@ -0,0 +1,140 @@
import java.util.Calendar;
/**
* Store the data from a single line of a
* web-server log file.
* Individual fields are made available via
* accessors such as getHour() and getMinute().
*
* @author David J. Barnes and Michael Kölling.
* @version 2016.02.29
*/
public class LogEntry implements Comparable<LogEntry>
{
// Where the data values extracted from a single
// log line are stored.
private int[] dataValues;
// The equivalent Calendar object for the log time.
private Calendar when;
// At which index in dataValues the different fields
// from a log line are stored.
private static final int YEAR = 0, MONTH = 1, DAY = 2,
HOUR = 3, MINUTE = 4;
// The number of fields. If more fields are added, e.g. for
// seconds or a status code, then this value must be increased
// to match.
private static final int NUMBER_OF_FIELDS = 5;
/**
* Decompose a log line so that the individual fields
* are available.
* @param logline A single line from the log.
* This should be in the format:
* year month day hour minute etc.
*/
public LogEntry(String logline)
{
// The array to store the data for a single line.
dataValues = new int[NUMBER_OF_FIELDS];
// Break up the log line.
LoglineTokenizer tokenizer = new LoglineTokenizer();
tokenizer.tokenize(logline,dataValues);
setWhen();
}
/**
* Create a LogEntry from the individual components.
* @param year The year
* @param month The month (1-12)
* @param day The day (1-31)
* @param hour The hour (0-23)
* @param minute The minute (0-59)
*/
public LogEntry(int year, int month, int day, int hour, int minute)
{
// The array to store the data for a single line.
dataValues = new int[NUMBER_OF_FIELDS];
dataValues[YEAR] = year;
dataValues[MONTH] = month;
dataValues[DAY] = day;
dataValues[HOUR] = hour;
dataValues[MINUTE] = minute;
setWhen();
}
/**
* Return the hour.
* @return The hour field from the log line.
*/
public int getHour()
{
return dataValues[HOUR];
}
/**
* Return the minute.
* @return The minute field from the log line.
*/
public int getMinute()
{
return dataValues[MINUTE];
}
/**
* Create a string representation of the data.
* This is not necessarily identical with the
* text of the original log line.
* @return A string representing the data of this entry.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
for(int value : dataValues) {
// Prefix a leading zero on single digit numbers.
if(value < 10) {
buffer.append('0');
}
buffer.append(value);
buffer.append(' ');
}
// Drop any trailing space.
return buffer.toString().trim();
}
/**
* Compare the date/time combination of this log entry
* with another.
* @param otherEntry The other entry to compare against.
* @return A negative value if this entry comes before the other.
* A positive value if this entry comes after the other.
* Zero if the entries are the same.
*/
public int compareTo(LogEntry otherEntry)
{
// Use the equivalent Calendars comparison method.
return when.compareTo(otherEntry.getWhen());
}
/**
* Return the Calendar object representing this event.
* @return The Calendar for this event.
*/
private Calendar getWhen()
{
return when;
}
/**
* Create an equivalent Calendar object from the data values.
*/
private void setWhen()
{
when = Calendar.getInstance();
// Adjust from 1-based month and day to 0-based.
when.set(dataValues[YEAR],
dataValues[MONTH] - 1, dataValues[DAY] - 1,
dataValues[HOUR], dataValues[MINUTE]);
}
}

View File

@@ -0,0 +1,11 @@
#BlueJ class context
comment0.params=
comment0.target=LogfileCreator()
comment0.text=\n\ Create\ log\ files.\n
comment1.params=filename\ numEntries
comment1.target=boolean\ createFile(java.lang.String,\ int)
comment1.text=\n\ Create\ a\ file\ of\ random\ log\ entries.\n\ @param\ filename\ The\ file\ to\ write.\n\ @param\ numEntries\ How\ many\ entries.\n\ @return\ true\ if\ successful,\ false\ otherwise.\n
comment2.params=
comment2.target=LogEntry\ createEntry()
comment2.text=\n\ Create\ a\ single\ (random)\ entry\ for\ a\ log\ file.\n\ @return\ A\ log\ entry\ containing\ random\ data.\n
numComments=3

View File

@@ -0,0 +1,69 @@
import java.io.*;
import java.util.*;
/**
* A class for creating log files of random data.
*
* @author David J. Barnes and Michael Kölling
* @version 2016.02.29
*/
public class LogfileCreator
{
private Random rand;
/**
* Create log files.
*/
public LogfileCreator()
{
rand = new Random();
}
/**
* Create a file of random log entries.
* @param filename The file to write.
* @param numEntries How many entries.
* @return true if successful, false otherwise.
*/
public boolean createFile(String filename, int numEntries)
{
boolean success = false;
if(numEntries > 0) {
try (FileWriter writer = new FileWriter(filename)) {
LogEntry[] entries = new LogEntry[numEntries];
for(int i = 0; i < numEntries; i++) {
entries[i] = createEntry();
}
Arrays.sort(entries);
for(int i = 0; i < numEntries; i++) {
writer.write(entries[i].toString());
writer.write('\n');
}
success = true;
}
catch(IOException e) {
System.err.println("There was a problem writing to " + filename);
}
}
return success;
}
/**
* Create a single (random) entry for a log file.
* @return A log entry containing random data.
*/
public LogEntry createEntry()
{
int year = 2016;
int month = 1 + rand.nextInt(12);
// Avoid the complexities of days-per-month.
int day = 1 + rand.nextInt(28);
int hour = rand.nextInt(24);
int minute = rand.nextInt(60);
return new LogEntry(year, month, day, hour, minute);
}
}

View File

@@ -0,0 +1,29 @@
#BlueJ class context
comment0.params=
comment0.target=LogfileReader()
comment0.text=\n\ Create\ a\ LogfileReader\ to\ supply\ data\ from\ a\ default\ file.\n
comment1.params=filename
comment1.target=LogfileReader(java.lang.String)
comment1.text=\n\ Create\ a\ LogfileReader\ that\ will\ supply\ data\n\ from\ a\ particular\ log\ file.\ \n\ @param\ filename\ The\ file\ of\ log\ data.\n
comment2.params=
comment2.target=boolean\ hasNext()
comment2.text=\n\ Does\ the\ reader\ have\ more\ data\ to\ supply?\n\ @return\ true\ if\ there\ is\ more\ data\ available,\n\ \ \ \ \ \ \ \ \ false\ otherwise.\n
comment3.params=
comment3.target=LogEntry\ next()
comment3.text=\n\ Analyze\ the\ next\ line\ from\ the\ log\ file\ and\n\ make\ it\ available\ via\ a\ LogEntry\ object.\n\ \n\ @return\ A\ LogEntry\ containing\ the\ data\ from\ the\n\ \ \ \ \ \ \ \ \ next\ log\ line.\n
comment4.params=
comment4.target=void\ remove()
comment4.text=\n\ Remove\ an\ entry.\n\ This\ operation\ is\ not\ permitted.\n
comment5.params=
comment5.target=java.lang.String\ getFormat()
comment5.text=\n\ @return\ A\ string\ explaining\ the\ format\ of\ the\ data\n\ \ \ \ \ \ \ \ \ in\ the\ log\ file.\n
comment6.params=
comment6.target=void\ reset()
comment6.text=\n\ Set\ up\ a\ fresh\ iterator\ to\ provide\ access\ to\ the\ data.\n\ This\ allows\ a\ single\ file\ of\ data\ to\ be\ processed\n\ more\ than\ once.\n
comment7.params=
comment7.target=void\ printData()
comment7.text=\n\ Print\ the\ data.\n
comment8.params=data
comment8.target=void\ createSimulatedData(java.util.ArrayList)
comment8.text=\n\ Provide\ a\ sample\ of\ simulated\ data.\n\ NB\:\ To\ simplify\ the\ creation\ of\ this\ data,\ no\n\ days\ after\ the\ 28th\ of\ a\ month\ are\ ever\ generated.\n\ @param\ data\ Where\ to\ store\ the\ simulated\ LogEntry\ objects.\n
numComments=9

View File

@@ -0,0 +1,161 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Random;
import java.util.Scanner;
/**
* A class to read information from a file of web server accesses.
* Currently, the log file is assumed to contain simply
* date and time information in the format:
*
* year month day hour minute
* Log entries are sorted into ascending order of date.
*
* @author David J. Barnes and Michael Kölling.
* @version 2016.02.29
*/
public class LogfileReader implements Iterator<LogEntry>
{
// The data format in the log file.
private String format;
// Where the file's contents are stored in the form
// of LogEntry objects.
private ArrayList<LogEntry> entries;
// An iterator over entries.
private Iterator<LogEntry> dataIterator;
/**
* Create a LogfileReader to supply data from a default file.
*/
public LogfileReader()
{
this("weblog.txt");
}
/**
* Create a LogfileReader that will supply data
* from a particular log file.
* @param filename The file of log data.
*/
public LogfileReader(String filename)
{
// The format for the data.
format = "Year Month(1-12) Day Hour Minute";
// Where to store the data.
entries = new ArrayList<>();
// Attempt to read the complete set of data from file.
boolean dataRead;
try{
// Locate the file with respect to the current environment.
URL fileURL = getClass().getClassLoader().getResource(filename);
if(fileURL == null) {
throw new FileNotFoundException(filename);
}
Scanner logfile = new Scanner(new File(fileURL.toURI()));
// Read the data lines until the end of file.
while(logfile.hasNextLine()) {
String logline = logfile.nextLine();
// Break up the line and add it to the list of entries.
LogEntry entry = new LogEntry(logline);
entries.add(entry);
}
logfile.close();
dataRead = true;
}
catch(FileNotFoundException | URISyntaxException e) {
System.out.println("Problem encountered: " + e);
dataRead = false;
}
// If we couldn't read the log file, use simulated data.
if(!dataRead) {
System.out.println("Failed to read the data file: " + filename);
System.out.println("Using simulated data instead.");
createSimulatedData(entries);
}
// Sort the entries into ascending order.
Collections.sort(entries);
reset();
}
/**
* Does the reader have more data to supply?
* @return true if there is more data available,
* false otherwise.
*/
public boolean hasNext()
{
return dataIterator.hasNext();
}
/**
* Analyze the next line from the log file and
* make it available via a LogEntry object.
*
* @return A LogEntry containing the data from the
* next log line.
*/
public LogEntry next()
{
return dataIterator.next();
}
/**
* Remove an entry.
* This operation is not permitted.
*/
public void remove()
{
System.err.println("It is not permitted to remove entries.");
}
/**
* @return A string explaining the format of the data
* in the log file.
*/
public String getFormat()
{
return format;
}
/**
* Set up a fresh iterator to provide access to the data.
* This allows a single file of data to be processed
* more than once.
*/
public void reset()
{
dataIterator = entries.iterator();
}
/**
* Print the data.
*/
public void printData()
{
for(LogEntry entry : entries) {
System.out.println(entry);
}
}
/**
* Provide a sample of simulated data.
* NB: To simplify the creation of this data, no
* days after the 28th of a month are ever generated.
* @param data Where to store the simulated LogEntry objects.
*/
private void createSimulatedData(ArrayList<LogEntry> data)
{
LogfileCreator creator = new LogfileCreator();
// How many simulated entries we want.
int numEntries = 100;
for(int i = 0; i < numEntries; i++) {
data.add(creator.createEntry());
}
}
}

View File

@@ -0,0 +1,8 @@
#BlueJ class context
comment0.params=
comment0.target=LoglineTokenizer()
comment0.text=\n\ Construct\ a\ LogLineAnalyzer\n
comment1.params=logline\ dataLine
comment1.target=void\ tokenize(java.lang.String,\ int[])
comment1.text=\n\ Tokenize\ a\ log\ line.\ Place\ the\ integer\ values\ from\n\ it\ into\ an\ array.\ The\ number\ of\ tokens\ on\ the\ line\n\ must\ be\ sufficient\ to\ fill\ the\ array.\n\n\ @param\ logline\ The\ line\ to\ be\ tokenized.\n\ @param\ dataLine\ Where\ to\ store\ the\ values.\n
numComments=2

View File

@@ -0,0 +1,43 @@
import java.util.Scanner;
/**
* Break up line from a web server log file into
* its separate fields.
* Currently, the log file is assumed to contain simply
* integer date and time information.
*
* @author David J. Barnes and Michael Kolling.
* @version 2016.02.29
*/
public class LoglineTokenizer
{
/**
* Construct a LogLineAnalyzer
*/
public LoglineTokenizer()
{
}
/**
* Tokenize a log line. Place the integer values from
* it into an array. The number of tokens on the line
* must be sufficient to fill the array.
*
* @param logline The line to be tokenized.
* @param dataLine Where to store the values.
*/
public void tokenize(String logline, int[] dataLine)
{
try {
// Scan the logline for integers.
Scanner tokenizer = new Scanner(logline);
for(int i = 0; i < dataLine.length; i++) {
dataLine[i] = tokenizer.nextInt();
}
}
catch(java.util.NoSuchElementException e) {
System.out.println("Insuffient data items on log line: " + logline);
throw e;
}
}
}

View File

@@ -0,0 +1,24 @@
Project: weblog-analyzer
Aothors: David J. Barnes and Michael Kölling
This project is part of the material for chapter 7 of the book
Objects First with Java - A Practical Introduction using BlueJ
Sixth edition
David J. Barnes and Michael Kölling
Pearson Education, 2016
Purpose of project: To provide an illustration of the use of arrays.
How to start this project: Create a LogAnalyzer object.
The LogfileReader expects to read a file, weblog.txt,
containing lines of data in the format:
year month day hour minute
month values are in the range 1-12 and day values in the range 1-31.
If the sample file cannot be found, the reader will create some simulated
data. Alternatively, use the LogfileCreator to create some random data.
Use its createFile method to give a file name and the number of entries
to create.

View File

@@ -0,0 +1,99 @@
#BlueJ package file
dependency1.from=LogAnalyzer
dependency1.to=LogfileReader
dependency1.type=UsesDependency
dependency2.from=LogAnalyzer
dependency2.to=LogEntry
dependency2.type=UsesDependency
dependency3.from=LogfileReader
dependency3.to=LogEntry
dependency3.type=UsesDependency
dependency4.from=LogfileCreator
dependency4.to=LogEntry
dependency4.type=UsesDependency
dependency5.from=LogEntry
dependency5.to=LoglineTokenizer
dependency5.type=UsesDependency
dependency6.from=LogfileReader
dependency6.to=LogfileCreator
dependency6.type=UsesDependency
objectbench.height=76
objectbench.width=859
package.editor.height=479
package.editor.width=751
package.editor.x=70
package.editor.y=80
package.numDependencies=6
package.numTargets=5
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.editor.height=707
readme.editor.width=830
readme.editor.x=151
readme.editor.y=60
target1.editor.height=892
target1.editor.width=1119
target1.editor.x=149
target1.editor.y=86
target1.height=60
target1.name=LogfileCreator
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=120
target1.x=500
target1.y=60
target2.editor.height=784
target2.editor.width=986
target2.editor.x=131
target2.editor.y=292
target2.height=60
target2.name=LogfileReader
target2.naviview.expanded=true
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=110
target2.x=230
target2.y=140
target3.editor.height=700
target3.editor.width=900
target3.editor.x=53
target3.editor.y=23
target3.height=60
target3.name=LoglineTokenizer
target3.naviview.expanded=false
target3.showInterface=false
target3.type=ClassTarget
target3.typeParameters=
target3.width=130
target3.x=490
target3.y=320
target4.editor.height=621
target4.editor.width=853
target4.editor.x=54
target4.editor.y=23
target4.height=60
target4.name=LogAnalyzer
target4.naviview.expanded=true
target4.showInterface=false
target4.type=ClassTarget
target4.typeParameters=
target4.width=120
target4.x=80
target4.y=60
target5.editor.height=800
target5.editor.width=989
target5.editor.x=53
target5.editor.y=23
target5.height=60
target5.name=LogEntry
target5.naviview.expanded=true
target5.showInterface=false
target5.type=ClassTarget
target5.typeParameters=
target5.width=110
target5.x=370
target5.y=230

File diff suppressed because it is too large Load Diff