We close our semester today with a discussion of finding things quickly with the binary search. We will illustrate the algorithm and implement it in the context of a dictionary/spell-checker.
Earlier in the semester we discussed the linear search. Let’s revisit that algorithm first by locating a spice in our spice rack. What happens when we’ve got 100 spices? 1000? 1e6? N? In the worst case, how many spices might we need to check? In the best case? On average? The Voyage of the Dawn Treader plays on the inefficiency of this algorithm.
We’ll then read about a better way from Computational Fairy Tales by Jeremy Kubica. That better way is called the binary search. Let’s see it with our spices. It works by maintaining a window in which the target element must appear. That window can be halved by examining its middle element and determining on which side of it the target element lies. The list very quickly gets whittled down. Unlike the linear search, the binary search can only be applied to arrays that are sorted.
I think this algorithm demonstrates a significant point. The ultra-fast binary search wasn’t the computer’s idea. It is just as happy to perform linear searches. The good idea, the intelligence, was a human idea. The computer is not really that good at math; we’re the ones writing the expressions. It’s not really a chef; we’re the ones organizing code into reusable chunks. It’s not a philosopher; that was us wondering something about are data. It’s not a pilot; that was us at its helm. It’s not a factory worker; that was us avoiding mindless repetition. It’s not a scribe; we told it what to read and write. It’s not a creator; we are. The computer only amplifies ideas that you have in your head. This class has been about getting those ideas out to the machine.
Here’s your TODO list for next time:
See you next class!
P.S. It’s time for a haiku!
To solve big problems
Throw away half the data
Like in politics
P.P.S. Here’s the code we wrote together…
package lecture1213;
public class YouAintGottaDictionaryException extends Exception {
public YouAintGottaDictionaryException() {
super("You ain't gotta dictionary, foobag. Get 1.");
}
}
package lecture1213;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Dictionary {
private ArrayList<String> words;
public Dictionary() throws YouAintGottaDictionaryException {
words = new ArrayList<>();
File file = new File("/usr/share/dict/words");
try {
Scanner in = new Scanner(file);
while (in.hasNextLine()) {
words.add(in.nextLine());
}
Collections.sort(words);
} catch (FileNotFoundException e) {
throw new YouAintGottaDictionaryException();
}
}
public boolean containsLinear(String target) {
for (String word : words) {
if (word.equals(target)) {
return true;
}
}
return false;
}
public boolean containsBinary(String target) {
int first = 0;
int last = words.size() - 1;
while (first <= last) {
int middle = (first + last) / 2;
// System.out.printf("%d %d %d%n", first, last, middle);
int order = target.compareTo(words.get(middle));
if (order < 0) {
last = middle - 1;
} else if (order > 0) {
first = middle + 1;
} else {
return true;
}
}
return false;
}
}
package lecture1213;
import lecture1129.Stopwatch;
public class Words {
public static void main(String[] args) throws YouAintGottaDictionaryException {
Dictionary dictionary = new Dictionary();
String[] words = {
"hey",
"hay",
"hayyyyyyy",
"zoo",
"yeah",
"yay",
"yea",
"rumplestiltskin",
"chris",
"incest",
"princess",
"princest",
"poverty",
"gutter",
"alabama",
"euphemism",
"good",
"one",
"foobag"
};
Stopwatch timer = new Stopwatch();
timer.start();
for (String word : words) {
System.out.println(dictionary.containsBinary(word));
}
double elapsed = timer.stop();
System.out.println(elapsed);
}
}
package lecture1213;
public class ForSomeReasonYouDontHaveADictionaryInstalledOnYourMachineSorryException extends Exception {
public ForSomeReasonYouDontHaveADictionaryInstalledOnYourMachineSorryException() {
super("No hay un diccionario.");
}
}
package lecture1213;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Dictionary {
private ArrayList<String> words;
public Dictionary() throws ForSomeReasonYouDontHaveADictionaryInstalledOnYourMachineSorryException {
File file = new File("/usr/share/dict/words");
try {
words = new ArrayList<>();
Scanner in = new Scanner(file);
while (in.hasNextLine()) {
words.add(in.nextLine());
}
Collections.sort(words);
} catch (FileNotFoundException e) {
throw new ForSomeReasonYouDontHaveADictionaryInstalledOnYourMachineSorryException();
}
}
public boolean containsLinear(String target) {
for (String word : words) {
if (word.equals(target)) {
return true;
}
}
return false;
}
public boolean containsBinary(String target) {
int first = 0;
int last = words.size() - 1;
while (first <= last) {
int iMiddle = (first + last) / 2;
int order = target.compareTo(words.get(iMiddle));
if (order == 0) {
return true;
} else if (order < 0) {
last = iMiddle - 1;
} else {
first = iMiddle + 1;
}
}
return false;
}
}
package lecture1213;
import lecture1129.Stopwatch;
public class Main {
public static void main(String[] args) throws ForSomeReasonYouDontHaveADictionaryInstalledOnYourMachineSorryException {
String[] words = {
"eucalyptus",
"Chris",
"periwinkle",
"longest",
"word",
"xylophone",
"super...",
"antidisestablishmentarianism",
"accuse",
"puce",
"scoot",
"scoop",
"finals",
"java",
"c++",
"lonely",
"\u3422"
};
Dictionary dictionary = new Dictionary();
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
for (String word : words) {
System.out.println(word + " -> " + dictionary.containsBinary(word));
}
stopwatch.stop();
System.out.println(stopwatch.getElapsedSeconds());
}
}
Today we welcome Marc Harter of Applied Data Consultants as our guest. When I first moved to this town, one of my students told me about this guy named Marc that he worked with. This Marc apparently had an amazing knowledge of web technologies, and most of it was self-taught. A little later I got an email from Marc asking if he could audit some classes so he could learn more. I—given my insatiable desire to see what other people have in their fridges—suggested that we instead get together regularly at his house. I’d share what I knew about C++ and Haskell, and he would help me learn guitar. We met a few times, but it turned out that I just couldn’t keep up with his fervor for learning.
So, we have with us this afternoon a professional learner. But he’s also a published author, a musician, a father of three, and a husband of one. Marc, thanks for stopping in to see us.
Also, this is our last meeting. We will have no final exam in this class.
Enjoy your break!
P.S. It’s time for a haiku!
]]>What’s nice about school:
You have time to learn the stuff
Once the homework’s in
It’s the last week! Given that we’re all stressed and ready to be done, let’s play a game today. Just kidding, let’s make one instead. We’re going to implement Lights Out, which started off as a handheld game from Tiger Electronics:
The game is played on a 5×5 grid of lights, some of which are on and some of which are off. Your task is turn all of them off. But here’s the thing: when you press a button, you toggle it and its 4-neighbors. We’ll write a graphical application that listens to mouse clicks, detects a win state, and saves and loads board configurations. Here’s our checklist:
Here’s your TODO to complete before we meet again:
See you next class!
P.S. It’s time for a haiku!
I used to play games
Making them’s even harder
It’s that final boss
P.P.S. Here’s the code we wrote together…
package lecture1211;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class LightsOutFrame extends JFrame implements MouseListener {
private static final int PIXELS = 100;
private static final int GAP = 2;
private LightsOutPanel panel;
private boolean[][] board;
public LightsOutFrame() {
board = new boolean[5][5];
// board[2][3] = true;
panel = new LightsOutPanel();
panel.setPreferredSize(new Dimension(PIXELS * 5, PIXELS * 5));
panel.addMouseListener(this);
add(panel);
JMenuItem saveLevel = new JMenuItem("Save level");
JMenu menu = new JMenu("Level");
JMenuBar menuBar = new JMenuBar();
menu.add(saveLevel);
menuBar.add(menu);
setJMenuBar(menuBar);
saveLevel.addActionListener(e -> {
saveLevel();
});
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private void saveLevel() {
try {
PrintWriter out = new PrintWriter(new File("/Users/johnch/Desktop/level"));
for (int r = 0; r < 5; ++r) {
for (int c = 0; c < 5; ++c) {
out.print(board[r][c] + " ");
}
out.println();
}
out.close();
} catch (IOException e) {
System.out.println(e);
}
}
class LightsOutPanel extends JPanel {
public void paintComponent(Graphics g) {
for (int r = 0; r < 5; ++r) {
for (int c = 0; c < 5; ++c) {
// (c, r)
if (board[r][c]) {
g.setColor(Color.YELLOW);
} else {
g.setColor(Color.BLACK);
}
g.fillRect(c * PIXELS + GAP, r * PIXELS + GAP, PIXELS - 2 * GAP, PIXELS - 2 * GAP);
}
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
// System.out.println(e);
int r = e.getY() / PIXELS;
int c = e.getX() / PIXELS;
flop(c, r);
flop(c + 1, r);
flop(c - 1, r);
flop(c, r - 1);
flop(c, r + 1);
repaint();
if (isWin()) {
JOptionPane.showMessageDialog(this, "A winner is you!");
}
}
private void flop(int c,
int r) {
if (r >= 0 && r < 5 && c >= 0 && c < 5) {
board[r][c] = !board[r][c];
}
}
private boolean isWin() {
for (int r = 0; r < 5; ++r) {
for (int c = 0; c < 5; ++c) {
if (board[r][c]) {
return false;
}
}
}
return true;
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
package lecture1211;
public class LightsOut {
public static void main(String[] args) {
new LightsOutFrame();
}
}
package lecture1211;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class LightsOutFrame extends JFrame implements MouseListener {
private static final int PIXELS = 50;
private static final int BORDER = 3;
private boolean[][] board;
public LightsOutFrame() {
board = new boolean[5][5];
// board[2][4] = true;
LightsOutPanel panel = new LightsOutPanel();
add(panel);
panel.addMouseListener(this);
panel.setPreferredSize(new Dimension(5 * PIXELS, 5 * PIXELS));
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private class LightsOutPanel extends JPanel {
public void paintComponent(Graphics g) {
for (int r = 0; r < 5; ++r) {
for (int c = 0; c < 5; ++c) {
if (board[r][c]) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(c * PIXELS + BORDER, r * PIXELS + BORDER, PIXELS - BORDER * 2, PIXELS - BORDER * 2);
}
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
int r = e.getY() / PIXELS;
int c = e.getX() / PIXELS;
flip(c, r);
flip(c + 1, r);
flip(c - 1, r);
flip(c, r - 1);
flip(c, r + 1);
repaint();
if (isWin()) {
JOptionPane.showMessageDialog(this, "You winned!");
}
}
private boolean isWin() {
for (int r = 0; r < 5; ++r) {
for (int c = 0; c < 5; ++c) {
if (board[r][c]) {
return false;
}
}
}
return true;
}
private void flip(int c,
int r) {
if (c >= 0 && c < 5 && r >= 0 && r < 5) {
board[r][c] = !board[r][c];
}
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
package lecture1211;
public class LightsOut {
public static void main(String[] args) {
new LightsOutFrame();
}
}
Today, we examine one of the less glamorous aspects of writing code: testing it. There are three big reasons to write systematic tests of your software:
There’s are psychological reasons too. It’s way better to discover your own errors than to have someone else tell you your code’s broken. See SpecCheckers.
To demonstrate what it means to test our code, we will use the popular JUnit testing framework for Java. We write a method for each feature under test. These methods have the following form:
@Test
public void testFeatureA() {
Foo f = new Foo();
int expectedValue = ...;
int actualValue = f.featureA();
Assert.assertEquals("Foo.featureA didn't do what I expected it to do when...",
expectedValue,
actualValue);
}
When we run this code as a JUnit test suite in a modern development environment, we get a nice report of which features are passing and which are failing.
So, let’s write some unit tests against your ArrayList implementations from last class!
If you are curious how the folks behind the OpenJDK project chose to implement ArrayList, see their open source solution.
Here’s your TODO to complete before we meet again:
See you next class!
P.S. Here’s the code we wrote together…
package lecture1208;
public class StringList {
int N;
String[] a;
public StringList() {
N = 0;
a = new String[2];
}
public void add(String element) {
if (N >= a.length) {
String[] b = new String[a.length * 2];
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}
a = b;
}
a[N] = element;
N++;
}
public void remove(int index) {
String[] dst = new String[a.length - 1];
for (int i = 0; i < a.length; i++) {
if (i < index) {
dst[i] = a[i];
}
if (i > index) {
dst[i - 1] = a[i];
}
}
a = dst;
N--;
}
public int size() {
return N;
}
public boolean contains(String str) {
for (int i = 0; i < N; ++i) {
if (a[i].equals(str)) {
return true;
}
}
return false;
}
public String get(int index) {
return a[index];
}
public boolean isEmpty() {
return N == 0;
}
public int indexOf(String needle) {
// int counter = 0;
// while (!a[counter].equals(needle)) {
// counter++;
// }
// return counter;
for (int i = 0; i < N; ++i) {
if (a[i].equals(needle)) {
return i;
}
}
return -1;
}
}
package lecture1208;
import org.junit.Assert;
import org.junit.Test;
public class Tests {
@Test
public void testEmpty() {
StringList list = new StringList();
Assert.assertEquals("I tried calling size on an empty list, but :(", 0, list.size());
Assert.assertEquals("I tried asking an empty list if it contained hope, but :(", false, list.contains("hope"));
Assert.assertEquals("I tried asking an empty list if it was empty, but :(", true, list.isEmpty());
Assert.assertEquals("I tried getting indexOf(hope) on an empty list, but :(", -1, list.indexOf("hope"));
}
@Test
public void testOnesie() {
StringList list = new StringList();
list.add("hope");
Assert.assertEquals("I tried calling size on a 1-list, but :(", 1, list.size());
Assert.assertEquals("I tried asking a 1-list if it contained hope, but :(", true, list.contains("hope"));
Assert.assertEquals("I tried asking a 1-list if it was empty, but :(", false, list.isEmpty());
Assert.assertEquals("I tried getting element 0 from a 1-list, but :(", "hope", list.get(0));
Assert.assertEquals("I tried getting indexOf(hope) on a 1-list, but :(", 0, list.indexOf("hope"));
}
@Test
public void testRemoveFromOnesie() {
StringList list = new StringList();
list.add("hope");
list.remove(0);
Assert.assertEquals("I tried calling size on an empty list, but :(", 0, list.size());
Assert.assertEquals("I tried asking an empty list if it contained hope, but :(", false, list.contains("hope"));
Assert.assertEquals("I tried asking an empty list if it was empty, but :(", true, list.isEmpty());
}
@Test
public void testLotsies() {
StringList list = new StringList();
list.add("hope");
list.add("element");
list.add("failure");
list.add("success");
Assert.assertEquals("I tried calling size on a 4-list, but :(", 4, list.size());
Assert.assertEquals("I tried asking a 4-list if it contained hope, but :(", true, list.contains("hope"));
Assert.assertEquals("I tried asking a 4-list if it contained hope, but :(", true, list.contains("element"));
Assert.assertEquals("I tried asking a 4-list if it contained hope, but :(", true, list.contains("failure"));
Assert.assertEquals("I tried asking a 4-list if it contained hope, but :(", true, list.contains("success"));
Assert.assertEquals("I tried asking a 4-list if it was empty, but :(", false, list.isEmpty());
Assert.assertEquals("I tried getting element 0 from a 1-list, but :(", "hope", list.get(0));
Assert.assertEquals("I tried getting element 1 from a 1-list, but :(", "element", list.get(1));
Assert.assertEquals("I tried getting element 2 from a 1-list, but :(", "failure", list.get(2));
Assert.assertEquals("I tried getting element 3 from a 1-list, but :(", "success", list.get(3));
Assert.assertEquals("I tried getting indexOf(hope) on a 1-list, but :(", 0, list.indexOf("hope"));
Assert.assertEquals("I tried getting indexOf(element) on a 1-list, but :(", 1, list.indexOf("element"));
Assert.assertEquals("I tried getting indexOf(failure) on a 1-list, but :(", 2, list.indexOf("failure"));
Assert.assertEquals("I tried getting indexOf(success) on a 1-list, but :(", 3, list.indexOf("success"));
}
}
package lecture1208;
public class GrowableArray {
private String[] currentStringArray;
private int nelements;
public GrowableArray() {
currentStringArray = new String[10];
nelements = 0;
}
public String get(int i) {
return currentStringArray[i];
}
public boolean isEmpty() {
return nelements == 0;
}
public void remove(int index) {
String[] newArray = new String[currentStringArray.length - 1];
for (int i = 0; i < index; i++) {
newArray[i] = currentStringArray[i];
}
for (int i = index; i < newArray.length; i++) {
newArray[i] = currentStringArray[i + 1];
}
currentStringArray = newArray;
--nelements;
}
public boolean contains(String string) {
boolean isTrue = false;
for (int i = 0; i < nelements; i++) {
if (currentStringArray[i].equals(string)) {
isTrue = true;
}
}
return isTrue;
}
public int indexOf(String s) {
for (int i = 0; i < nelements; i++) {
if (currentStringArray[i].equals(s)) {
return i;
}
}
return -1;
}
public int size() {
return nelements;
}
public void add(String s) {
if (nelements == currentStringArray.length) {
String[] moar = new String[2 * nelements];
System.arraycopy(currentStringArray, 0, moar, 0, nelements);
currentStringArray = moar;
}
currentStringArray[nelements] = s;
++nelements;
}
}
package lecture1208;
import org.junit.Assert;
import org.junit.Test;
public class Tests {
@Test
public void testEmpty() {
GrowableArray list = new GrowableArray();
Assert.assertEquals("I tried asking an empty list if it was empty, but...", true, list.isEmpty());
Assert.assertEquals("I tried asking an empty list its size, but...", 0, list.size());
Assert.assertEquals("I tried asking an empty list if it had hope, but...", false, list.contains("hope"));
}
@Test
public void testOnesie() {
GrowableArray list = new GrowableArray();
list.add("hope");
Assert.assertEquals("I tried asking a 1 list if it was empty, but...", false, list.isEmpty());
Assert.assertEquals("I tried asking a 1 list its size, but...", 1, list.size());
Assert.assertEquals("I tried asking a 1 list if it had hope, but...", true, list.contains("hope"));
Assert.assertEquals("I tried asking a 1 list about indexOf hope, but...", 0, list.indexOf("hope"));
list.remove(0);
Assert.assertEquals("I tried asking an empty list if it was empty, but...", true, list.isEmpty());
Assert.assertEquals("I tried asking an empty list its size, but...", 0, list.size());
Assert.assertEquals("I tried asking an empty list if it had hope, but...", false, list.contains("hope"));
}
@Test
public void testLotsies() {
GrowableArray list = new GrowableArray();
list.add("hope");
list.add("peace");
list.add("joy");
list.add("love");
Assert.assertEquals("I tried asking a 4 list if it was empty, but...", false, list.isEmpty());
Assert.assertEquals("I tried asking a 4 list its size, but...", 4, list.size());
Assert.assertEquals("I tried asking a 4 list if it had hope, but...", true, list.contains("hope"));
Assert.assertEquals("I tried asking a 4 list if it had peace, but...", true, list.contains("peace"));
Assert.assertEquals("I tried asking a 4 list if it had joy, but...", true, list.contains("joy"));
Assert.assertEquals("I tried asking a 4 list if it had love, but...", true, list.contains("love"));
Assert.assertEquals("I tried asking a 4 list if it had love , but...", false, list.contains("love "));
Assert.assertEquals("I tried asking a 4 list about indexOf hope, but...", 0, list.indexOf("hope"));
Assert.assertEquals("I tried asking a 4 list about indexOf peace, but...", 1, list.indexOf("peace"));
Assert.assertEquals("I tried asking a 4 list about indexOf joy, but...", 2, list.indexOf("joy"));
Assert.assertEquals("I tried asking a 4 list about indexOf love, but...", 3, list.indexOf("love"));
Assert.assertEquals("I tried asking a 4 list about indexOf love , but...", -1, list.indexOf("love "));
// list.remove(0);
// Assert.assertEquals("I tried asking an empty list if it was empty, but...", true, list.isEmpty());
// Assert.assertEquals("I tried asking an empty list its size, but...", 0, list.size());
// Assert.assertEquals("I tried asking an empty list if it had hope, but...", false, list.contains("hope"));
}
}
Today, December 6, is National Growable Array Day. We will celebrate growable arrays everywhere by growing one of our own growable arrays, right here, in our classroom. I hope you wore your festive gear.
Behind every growable array is an plain old ungrowable array. When that ungrowable array gets filled up, a new and larger ungrowable array is made—containing both the old contents plus some empty cells waiting to be filled. Like the phoenix, the old one dies while the new one takes its place.
The growable array that we use in Java is ArrayList. These growable arrays can hold elements of any object type—but not primitives. We will constrain the problem a bit: we’ll only hold Strings.
Each row of the classroom will take on two of the behaviors/methods that growable arrays tend to support:
get, which returns the element at the given indexremove, which removes the element at the given indexadd, which adds an element at the end of the list (be careful, the list might be “full”)size, which reports how many elements are in the listcontains, which reports whether or not a list contains the given elementindexOf, which reports where a given element occursisEmpty, which reports whether or not the list is emptyPlease write your solutions down on paper, consult with your rowmates, and elect one of you to provide your solution on the board.
Check each other’s work. If your collective solution passes all tests, I’ll grant an extra credit participation point to everyone in attendance.
Here’s your TODO to complete before we meet again:
See you next class!
P.S. It’s time for a haiku!
“What’s already done,
do not do.” But they forget
I am never done
P.P.S. Here’s the code we wrote together…
package lecture1206;
import java.lang.reflect.Array;
public class StringList {
int N;
String [] a;
public StringList () {
int N = 0;
String [] a = new String[2];
}
public void add(String element) {
if(N >= a.length) {
String[] b = new String[a.length*2];
for(int i = 0; i < a.length; i++) {
b[i] = a[i];
}
a = b;
}
a[N] = element;
N++;
}
public void remove(int index) {
String[] dst = new String[a.length - 1];
for (int i = 0; i < a.length; i++) {
if(i < index) {
dst[i] = a[i];
}
if(i > index) {
dst[i - 1] = a[i];
}
}
a = dst;
N--;
}
public int size() {
return N;
}
public boolean contains(String str) {
for (int i = 0; i < a.length;++i) {
if (a[i].equals(str)){
return true;
}
}
return false;
}
public String get(int index) {
return a[index];
}
public boolean isEmpty() {
return N == 0;
}
public int indexOf(String[] s, String a) {
int counter = 0;
while (!s[counter].equals(a)) {
counter++;
}
return counter;
}
}
package lecture1206;
public class GrowableArray {
private String[] currentStringArray;
public GrowableArray() {
currentStringArray = new String[10];
}
public String get(int i) {
return currentStringArray[i];
}
public boolean isEmpty() {
for (String s : currentStringArray) {
if (s != null) {
return false;
}
}
return true;
}
public void remove(int index) {
String[] newArray = new String[currentStringArray.length - 1];
for (int i = 0; i < index; i++) {
newArray[i] = currentStringArray[i];
}
for (int i = index; i < newArray.length; i++) {
newArray[i] = currentStringArray[i + 1];
}
currentStringArray = newArray;
}
public boolean contains(String string) {
boolean isTrue = false;
for (int i = 0; i < currentStringArray.length; i++) {
if (currentStringArray[i].equals(string)) {
isTrue = true;
}
}
return isTrue;
}
public int indexOf(String s) {
for (int i = 0; i < currentStringArray.length; i++) {
if (currentStringArray[i].equals(s)) {
return i;
}
}
return -1;
}
public int size() {
int length = 0;
for (int i = 0; i < currentStringArray.length; ++i) {
if (!get(i).isEmpty()) {
length++;
}
}
return length;
}
}
Today we welcome John Huss of Integrated Computer Solutions as our guest. John brings us the perspective of working for a small company. You’ll have to excuse me for using this class as an opportunity to reunite with old friends. John is a friend I haven’t seen since 2003. He and I were classmates at the University of Northern Iowa, just like you folks are classmates. The importance of your classmates post-school is hard to underestimate. I even married one of mine.
Fourteen years was a long time ago, but I remember respecting John for his ability to be a good student without getting in trouble with the teachers. I have a faint memory of getting the chalk or eraser thrown at me by one of our professors. I think John was beside me when that happened. In fact, I think the professor missed and hit John instead. Is that what happened? If so, I’m sorry.
But what I remember the most about John is seeing him up on stage at various campus events playing the bass guitar. And he’s still playing. Like all of us, he has many facets. Software developer is just one of them.
Next week, our guest is Marc Harter of Applied Data Consultants.
Here’s your TODO list for next time:
Please read the following articles:
There are many unrepresented groups in our field—not just women—and these readings address only a fraction of diversity issues.
Please make at least two separate posts sharing your own coherent thoughts. Additionally, check out and respond to the posts of at least three of your channelmates. Complete these before next Tuesday at noon.
See you next class!
If you have checkpoints from the last lab to show your instructor or TA, do so immediately. No credit will be given if you have not already completed the work, nor will credit be given after the first 10 minutes of this lab.
In this lab you will create a robot or robots who will compete with others in a game of SplatBot. Each robot is assigned a color—either red or blue. On each action, the tile underneath a robot is painted the robot’s current color. If a robot is hit by an enemy’s splat, that robot begins painting tiles the opponent’s color and does so for 10 turns. The game is won by whichever robot has more tiles painted after 500 turns.
The code for the game is available in the template repository, in speccheckers/splatbot.jar. Pull this JAR file down using Team / Pull…, as explained in homework 0, part 2.
You will need to submit your robot via your Bitbucket repository. Create a lab12 package. Create class SplatBot. (You can create others with different names after you get SplatBot working.)
In your class, add a constructor that accepts a SplatBotColor as a parameter. This is the color that has been assigned to your bot. It will be one of these two values:
SplatBotColor.RED
SplatBotColor.BLUE
You may ignore the parameter or use it in your strategy.
On each turn of the game, the game calls your robot’s getAction method to decide what Action it will take. This method accepts as parameters three Cells, describing the three tiles to the robot’s left, in front of the robot, and to the robot’s right, respectively. Each Cell parameter will have one of these values:
Cell.RED // cell has been painted red
Cell.BLUE // cell has been painted blue
Cell.NEUTRAL // cell has not been painted
Cell.ROCK // cell is covered by impenetrable rock
Cell.RED_ROBOT // cell is occupied by red robot
Cell.BLUE_ROBOT // cell is occupied by blue robot
Cell.WALL // cell is off the game board
Have your method return one of these choices:
Action.TURN_LEFT
Action.TURN_RIGHT
Action.MOVE_FORWARD
Action.MOVE_BACKWARD
Action.PASS // skips a turn
Action.SPLAT // fires a splat in the robot's line of sight
Action.SURVEY // request a view of the game board
Pick one these actions using a strategy of your choice. Add any instance variables you want. Just don’t cheat by taking screenshots, prompting for user interaction, or deferring all calls to one of the provided robots.
You may fire a splat or request a survey one out of every 5 turns. More frequent requests will be ignored, effectively forfeiting your turn.
Have getAction return Action.SURVEY to get a 10×10 2D array describing the current state of the game board. The board will be delivered to the robot via a method named survey, which accepts a 2D array of Cells as its only parameter.
Run a game of SplatBot with a snippet like this in a main method:
int delayMillis = 100;
int nTurns = 500;
new Splatter(splatbot.RobotRandom.class, lab12.SplatBot.class, delayMillis, nTurns);
Write a robot that beats splatbot.RobotRandom. Once you are confident that your robot can do so, commit and push it, and let your instructor know.
The victory must happen on your instructor’s computer. That means there must be enough time left in lab for the competition to take place. Other pairs will also be submitting their robots. No battles will take place once lab has ended. To ensure successful completion of this lab, you are encouraged to complete the work before the scheduled lab period.
Write a robot that beats splatbot.RobotLefty. The same time restrictions apply.
When we last met, we made a slideshow application. This was our first graphical application that we wrote from scratch. We organized the code into two camps: model code and view code. This separation made the model code reusable under many different circumstances. Let’s do all that again today, but in a different context and in more detail. We will create a volume slicer, which will depict a single 2D slice of a 3D dataset.
You probably haven’t gotten your hands on a lot of 3D data. But you might have gotten your hands in one. If you’ve ever had an MRI or CT scan, those machines essentially produced a stack of 2D images at increasing depths—a 3D array. And if you recorded many of these over time, you’d get a 4D array.
Visualizing 3D data is possible, but if you’ve ever had an ultrasound, you know that a lot of measurement and analysis is done in 2D. We’ll make a rudimentary tool that loads in the full 3D volume of data, but only projects a single plane of it. We’ll add a slider so we can change which plane is projected.
Let’s follow this checklist as we implement our slicer:
Volume class that encapsulates a 3D array holding data from a CT scan or MRI.Slicer class that is a window.Slicer to change which plane is displayed.interface, local classes, and lambdas.JLabel as a grayscale image.TransferFunction class for abstracting a colormap.Here’s your TODO to complete before we meet again:
See you next class!
P.S. It’s time for a haiku!
Numbers to pictures
Pictures to interactions
To better humans
P.P.S. Here’s the code we wrote together…
package lecture1204;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Volume {
private int[][][] densities;
public Volume(String path) throws IOException {
DataInputStream in = new DataInputStream(new FileInputStream(path));
int width = in.readInt();
int height = in.readInt();
int depth = in.readInt();
densities = new int[depth][height][width];
for (int z = 0; z < depth; ++z) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
densities[z][y][x] = Byte.toUnsignedInt(in.readByte());
}
}
}
in.close();
}
public int getDepth() {
return densities.length;
}
public int getHeight() {
return densities[0].length;
}
public int getWidth() {
return densities[0][0].length;
}
public int get(int x, int y, int z) {
return densities[z][y][x];
}
}
package lecture1204;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SliderListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
System.out.println(e);
}
}
package lecture1204;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
public class Slicer extends JFrame {
private JLabel label;
private Volume volume;
public Slicer(Volume volume) {
this.volume = volume;
JSlider slider = new JSlider(0, 100);
label = new JLabel("foobag");
add(slider, BorderLayout.NORTH);
add(label, BorderLayout.CENTER);
slider.addChangeListener(e -> {
load(slider.getValue());
});
load(slider.getValue());
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private void load(int z) {
BufferedImage image = new BufferedImage(volume.getWidth(), volume.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < image.getHeight(); ++y) {
for (int x = 0; x < image.getWidth(); ++x) {
int density = volume.get(x, y, z);
Color color = new Color(density, density, density);
image.setRGB(x, y, color.getRGB());
}
}
label.setIcon(new ImageIcon(image));
}
}
package lecture1204;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
Volume vismale = new Volume("/Users/johnch/Desktop/vismale.f0");
Slicer slicer = new Slicer(vismale);
}
}
If you have checkpoints from the last lab to show your instructor or TA, do so immediately. No credit will be given if you have not already completed the work, nor will credit be given after the first 10 minutes of this lab.
In this lab you will create a bare-bones text-based adventure game, in which a player moves through a network of rooms, achieving some objective—like collecting items or solving puzzles.
Person A types. In Eclipse, create a lab11 package.
Create a class named Room that knows at least five things about itself: its textual description and which Rooms are to its north, east, south, and west. Give it the following:
Give it the following behaviors:
setNorth, setEast, setSouth, and setWest. Each accepts another Room as its sole parameter.getNorth, getEast, getSouth, and getWest. Each returns the Room in the given direction. If there is no room in the given direction, return null.Create a class named TextAdventure with a main method. Declare and construct a network of at least four rooms. Connect them using your set* methods.
Person B types. Extend TextAdventure.main by first adding a variable to track the player’s current room. Start the player in one of the rooms that person A has already constructed—do not construct a new room.
Then continuously prompt the user for text command and respond accordingly. Respond to commands n, e, s, and w by attempting to move the player to the room in the given direction. For example, if n is typed, move to the room north of the current room.
When a room is entered, display its description.
For example, consider this interaction with just two rooms:
You look around. The room is completely black. Suddenly, a flame lights up. It ignites the end of cigarette, which is perched in the mouth of a clown. He is not smiling. > n Three clowns sit around a table playing cards. They nod as you enter and return to their game. > e There is no room to the east. > s You look around. The room is completely black. Suddenly, a flame lights up. It ignites the end of cigarette, which is perched in the mouth of a clown. He is not smiling.
Support at least one other meaningful command of your choosing that allows the player to interact with a room. For example, maybe a room contains items that can be taken and added to the player’s inventory. Maybe the doors are locked and need to be unlocked in some way. You decide. Add methods to Room as needed.
Consider adding a win condition appropriate for your interaction.
Invite another team over to playtest your text adventure.
]]>