# Week 6
Main Lecturer: Ayaan Siddiqui
## Java Review
Today, we're going to incorporate all the things we've learned throughout the past five weeks in a small project.
We're going to make a GUI app to play the game "Battleship."

### Class Design
Battleship is made of a bunch of tiles. What data might they need?
* Does the Tile have a ship?
* Was the Tile hit?
* How should we actually draw our Tile? (I'll give you the answer for this one — it's a `JButton`)
* What should we do when that button is pressed? We don't actually answer this question in the `Tile` class; we answer it whenever we instantiate a new `Tile.`
```java
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Tile {
private boolean hasShip, hit;
private JButton button;
public Tile(JPanel panel, boolean hasShip, ActionListener listener) {
button = new JButton();
button.setBackground(Color.WHITE);
button.addActionListener(listener);
panel.add(button);
this.hasShip = hasShip;
}
public Tile(JPanel panel, ActionListener listener) {
this(panel, false, listener);
}
public boolean hit() {
if (hit)
return false;
hit = true;
if (hasShip) {
button.setBackground(Color.RED);
} else {
button.setBackground(Color.BLACK);
}
return true;
}
public void reset() {
hit = false;
hasShip = false;
button.setBackground(Color.WHITE);
}
public void showShip() {
if (!hit && hasShip)
button.setBackground(Color.BLUE);
}
public void putShip() {
hasShip = true;
}
public boolean hasShip() {
return hasShip;
}
public boolean isHit() {
return hit;
}
public String toString() {
if (hit)
return "X";
if (hasShip)
return "O";
return " ";
}
}
```
### Creating the Panel
Before we do anything, we will need to actually instantiate and do everything we need to show our `JFrame`. Detailed notes on this can be found in the Week 5 notes.
```java
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Battleship");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
BattleshipPanel panel = new BattleshipPanel();
frame.setContentPane(panel);
frame.setVisible(true);
}
}
```
In our `JPanel` subclass, which we will call `BattleshipPanel`, we want to create a bunch of these `Tiles` and store them properly. Remember that Battleship works with a matrix of `Tiles`.
`BattleshipPanel` will need to store all of our data to play the game. What might we need to store?
* Number of torpedos fired
* `Tile` matrix
* All of our other interactive elements
* Reset button
* Label showing the number of torpedos left
```java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BattleshipPanel extends JPanel {
private Tile[][] tiles;
private JPanel shipPanel;
private JLabel torpedoLabel;
private JButton resetButton;
private static final int NUM_SHIPS = 4;
private static final int NUM_TORPEDOS = 50;
private int torpedos = NUM_TORPEDOS;
public BattleshipPanel() {
setBackground(Color.WHITE);
setLayout(new BorderLayout());
tiles = new Tile[10][10];
JPanel bottomPanel = new JPanel();
torpedoLabel = new JLabel("Torpedos: " + torpedos);
bottomPanel.add(torpedoLabel);
resetButton = new JButton("Reset");
resetButton.setEnabled(false);
resetButton.addActionListener(new ResetListener());
bottomPanel.add(resetButton);
add(bottomPanel, BorderLayout.SOUTH);
shipPanel = new JPanel();
shipPanel.setLayout(new GridLayout(tiles.length, tiles[0].length));
add(shipPanel, BorderLayout.CENTER);
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
tiles[i][j] = new Tile(shipPanel, new TileListener(i, j));
}
}
}
private class ResetListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// We will implement this later
}
}
private class TileListener implements ActionListener {
private int row, col;
public TileListener(int row, int col) {
this.row = row;
this.col = col;
}
public void actionPerformed(ActionEvent e) {
// We will implement this later
}
}
}
```
At this point, our game looks pretty good but we can't actually do anything:

### Implementing Game Logic
We have the looks and foundations of our game done. Yay! Now we just have to make it playable. We will implement most of our game logic inside of `BattleshipPanel.java`.
* We want to dynamically generate where our ships are placed.
```java
public void placeBattleships(int num) {
int successfullyPlaced = 0;
while (successfullyPlaced < num) {
int row = (int) (Math.random() * 10);
int col = (int) (Math.random() * 10);
boolean orientation = Math.random() >= 0.5;
int length = (num - successfullyPlaced) + 2;
if (placeBattleship(row, col, length, orientation)) {
successfullyPlaced++;
}
}
}
// Returns true if the ship is placed successfully, false otherwise.
public boolean placeBattleship(int r, int c, int length, boolean horizontal) {
if (horizontal) {
if (r < 0 || r + length > tiles.length || c < 0 || c + 1 > tiles[0].length)
return false;
for (int i = 0; i < length; i++)
if (tiles[r + i][c].hasShip())
return false;
for (int i = 0; i < length; i++)
tiles[r + i][c].putShip();
} else {
if (r < 0 || r + 1 > tiles.length || c < 0 || c + length > tiles[0].length)
return false;
for (int i = 0; i < length; i++)
if (tiles[r][c + i].hasShip())
return false;
for (int i = 0; i < length; i++)
tiles[r][c + i].putShip();
}
return true;
}
```
* We want to be able to fire torpedos. We put the `TileListener` class inside of `BattleshipPanel` instead of `Tile` because it needs access to so much from `BattleshipPanel` (`resetButton`, `torpedos`, `showAllShips()`). Theoretically, with a couple of code changes, you would be able to put `TileListener` inside of `Tile`, but it would be a lot less neat.
```java
private class TileListener implements ActionListener {
private int row, col;
public TileListener(int row, int col) {
this.row = row;
this.col = col;
}
public void actionPerformed(ActionEvent e) {
if (torpedos == 0)
return;
if (tiles[row][col].hit()) {
torpedos--;
torpedoLabel.setText("Torpedos: " + torpedos);
if (hasHitAllShips()) { // We will implement this in a bit
torpedos = 0;
resetButton.setEnabled(true);
torpedoLabel.setText("You win!");
} else if (torpedos == 0) {
resetButton.setEnabled(true);
torpedoLabel.setText("You lose!");
showAllShips(); // We will implement this in a bit
}
}
}
}
```
* We want to figure out if we have won (when there are no other ships to hit) or lost and act accordingly. We want to stop the player from firing more torpedos and, if they have lost, show the remaining ship parts to be hit.
```java
public boolean hasHitAllShips() {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
if (tiles[i][j].hasShip() && !tiles[i][j].isHit())
return false;
}
}
return true;
}
public void showAllShips() {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
tiles[i][j].showShip();
}
}
}
```
* We want to be able to reset the board.
```java
public void reset() {
resetButton.setEnabled(false);
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
tiles[i][j].reset();
}
}
placeBattleships(NUM_SHIPS);
torpedos = NUM_TORPEDOS;
}
private class ResetListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
reset();
}
}
```
**The full code (minus extension) can be found on Google Classroom after the class.** The extension will be posted later, after next week's class.
### Extension
Store all scores, from lowest to highest (the score being the number of torpedoes fired) in a file, in the following format:
```java
name + "\t" + score
```
For example:
```
Diana 29
Ayaan 31
KJ 31
Caroline 45
```
Hint: sorting may come in handy.
This is trickier than it looks; if you get stuck, feel free to ask one of us!
## Python Basics
Today, we'll also start introducing Python. Python is another extremely versatile programming language, and we will be focusing on it for the rest of the summer. It often looks simpler than Java, though they each have their pros and cons.
Java tends to be faster than Python. However, Java also has more strongly-enforced rules than Python; this can be a good or bad thing, depending on the case. While it's simpler to not have those rules, debugging in Python is a bit trickier than in Java.
| **Language** | **Java** | **Python** |
|---------------------- |------------------------------------------------------ |----------------------------------------- |
| Declaring a Variable | ``` int i = 0; ``` | ``` i = 0 ``` |
| Print to Console | ``` System.out.println("ok"); ``` | ``` print("ok") ``` |
| If-Statements | ``` if (3 < 4) { } ``` | ``` if 3 < 4: ``` |
| For-Loops | ``` for (int i = 0; i < 10; i++) { } ``` | ``` for i in range(10): ``` |
| While-Loops | ``` while (i < 10) { } ``` | ``` while i < 10: ``` |
### Indentation
Note that indentation in Python is extremely important. In Java, you can freely indent anywhere (though not recommend). This is not the case in Python.
```java
public class Main {
public static void main(String[] args) {
if (5 == 5) {
System.out.println("This works!");
}
}
}
```
Running the above Java code would output:
```
This works!
```
However, Python doesn't have curly braces. Take the example below.
```python
if 5 == 5:
print("This doesn't work, sad. :(")
```
Running the above Python code would output something like:
```
File "<stdin>", line 2
print("This doesn't work, sad. :(")
^
IndentationError: expected an indented block
```
If you use `:` anywhere, be prepared to indent the next few lines. Anything that is indented in Python can be thought of as equivalent to being surrounded by curly braces in Java.
```python
if 5 == 5:
print("Wow, this works!")
```
Other differences:
* Semicolons aren't needed.
* `main` method isn't needed.
* A class that contains all our methods and functions isn't needed.
### Functions
```java
public static int add(int a, int b) {
return a + b;
}
```
vs.
```python
def add(a, b):
return a + b
```
Functions look simpler in Python. Note that you don't need the return type in the method header. You also don't need to specify the types of `a` and `b`. These aspects have their pros and cons. They make functions less rigid, but also more prone to bugs so be cautious.
Here are some demonstrations of some built-in Python functions!
```python
# Ask the user for a string:
s = input("Please type a string: ")
# Ask the user for a number and convert it to an integer:
temp = input("Please type an integer: ")
num = int(temp)
# Print the requested character from the given string
print("The character at index", num, "in string", s, "is", s[num])
# Print three characters starting from a certain index
print("The three characters starting at index", num, "are", s[num:num + 3])
# Change the case of the string
u = s.upper()
l = s.lower()
print("Uppercase:", u)
print("Lowercase:", l)
# Print the length of the string
print(s, "is", len(s), "characters long")
print() # This adds an empty line to make the output look nicer
for num in range(4, 10):
print(num)
```