Plinko
Modules - Data Structures, Dynamic Data Structures, Object Oriented Programming, (potentially Recursion).
Teacher’s Notes:
=======================================
- This is a pretty involved assignment that will challenge students to develop something of their own design with little input from the teacher.
- My plan is to have the students do this in pairs. However, I would encourage you to pair students with a peer of similar ability or else the stronger student will likely just take over the project.
- Make sure students know their rights and lefts!
- Creating a program that starts with an array of Nodes and then becomes a linked structure is going to be quite complex for many students.
- When you create an array of Nodes, you are actually only making a list of Node references - not the actual instances of Nodes. You need to use a FOR loop to actually instantiate Nodes at each element of the array.
- This is a variation of a depth first exploration algorithm.
- Debugging this program will be hard since it will be tough to display the board. Encourage students to very careful when designing their algorithms. Following their work with a diagram is recommended for both the teacher and students.
- I have left my test/debugging code and comments in the solution code in case you want to use it.
- Students will need to devise their own way of exploring the case study and should write an explanation of their methods and outcomes.
- There are many ways to model this. My solution is just one.
Assignment:
=======================================
Case Study: Plinko
On the TV game show The Price is Right, there is a game called Plinko. In this game there is a board with a number of slots across the top where a disc can be placed. The player can choose any slot to place their disc in. From this slot, the disc falls directly below where it hits a peg and can then go to another slot that is either to the left or to the right of the peg. There are 9 slots across the top row and 10 slots in the next row down. In subsequent rows, each row alternates 9 and 10 slots per row until the disc reaches the bottom. Once it reaches the bottom, the disc falls into a final slot where a prize amount is assigned. The player wins the prize associated with that slot.
A video of the game can be seen here:
https://youtu.be/EmuJbou5j4g?si=zaWZ9jkqdwCaNGSI
In this study, you will create a Plinko simulator where there are n slots across the top and L levels on the board. The second level will always have n+1 slots and there will always be at least 3 levels (L >= 3).
The top level of the board will be modeled using an array of Node objects that can link directly to two Node objects below them to the left and right. Every Node object can then link to the Nodes below them until the bottom has been reached (see diagram for an illustration of a Plinko board with 5 slots and 6 rows). Once the bottom has been reached, the program will note which slot the disc was dropped in at the top and which slot it ended up in at the bottom.
Once this has been modeled, answer the following questions experimentally by running a large number of simulations:
1. In The Price is Right, there are 9 slots across the top and 14 rows of slots until the disc reaches the bottom. If the top prize is in the center slot of the bottom row, which slot is the best place to start to give you the best chance to win it?
2. Does the number of rows impact the chance of winning the prize in the center slot of the bottom row? Do the proportions of the slots vs. rows make a difference to the outcome?
3. The concept of "Diminishing Returns" describes the situation where an increase in an input will result in a proportional increase in output. However as the input increases further, the increase in output does not keep pace with the input. For example: working out for 30 minutes is probably better than working out for 3 minutes since you are working out 10x longer. However, working out for 10 hours straight vs 1 hour, probably does not have a similar benefit increase.
Experimentally, does the number of rows in the Plinko game have diminishing returns?
Solution (Node Class):
=======================================
public class Node {
//The left and right Nodes are the directions that a chip could follow down
private Node left;
private Node right;
//The next Node is a reference to the node to this node's right on the same row
private Node next;
//end refers to the Node knowing if it is at the bottom row of the board.
private static int count = 1;
public int nodeNumber = count++;
private int number;
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public int getNumber() {
return number;
}
public void setNumber(int prize) {
this.number = prize;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
Solution (Board Class):
=======================================
public class Board {
public int width;
public int rows;
public Node[] entryPoint;
public Board(int width, int rows) {
this.width = width;
//Making the top row
entryPoint = new Node[width];
for(int x = 0; x < width; x++)
entryPoint[x] = new Node();
//Making the next row
entryPoint[0].setLeft(new Node());
for(int x = 0; x < width-1; x++) {
entryPoint[x].setRight(new Node());
entryPoint[x+1].setLeft(entryPoint[x].getRight());
}
entryPoint[width-1].setRight(new Node());
Node rowMarker = entryPoint[0].getLeft();
for(int x = 0; x < width; x++)
entryPoint[x].getLeft().setNext(entryPoint[x].getRight());
this.rows = 2;
//At this point, the nodes are not directly connected to the array in the top row
while(this.rows < rows) {
Node temp = rowMarker;
//creating a size "width+1" row
for(int x = 0; x < width; x++) {
temp.setRight(new Node());
temp.getNext().setLeft(temp.getRight());
//temp.getRight().setNext(temp.getNext().getRight());
temp = temp.getNext();
}
temp = rowMarker.getNext();
for(int x = 0; x < width-1; x++) {
temp.getLeft().setNext(temp.getRight());
temp = temp.getNext();
}
this.rows++;
//System.out.println("Currently have: " + this.rows + " rows.");
/*
System.out.println("ROW");
temp = rowMarker;
while(temp!=null)
{
System.out.print(temp.nodeNumber + " ");
if(temp.getLeft()!=null)
System.out.print("(" + temp.getLeft().nodeNumber + ",");
else
System.out.print("(null,");
if(temp.getRight() != null)
System.out.print(temp.getRight().nodeNumber + ")");
else
System.out.print("null)");
temp = temp.getNext();
}
System.out.println();*/
rowMarker = rowMarker.getRight();
if(this.rows < rows) {
//creating a size "width" row
temp = rowMarker;
temp.setLeft(new Node());
for(int x = 0; x < width-1; x++) {
temp.setRight(new Node());
temp.getNext().setLeft(temp.getRight());
temp = temp.getNext();
}
temp.setRight(new Node());
temp = rowMarker;
for(int x = 0; x < width; x++) {
temp.getLeft().setNext(temp.getRight());
temp = temp.getNext();
}
/*
System.out.println("ROW");
temp = rowMarker;
while(temp!=null)
{
System.out.print(temp.nodeNumber + " ");
if(temp.getLeft()!=null)
System.out.print("(" + temp.getLeft().nodeNumber + ",");
else
System.out.print("(null,");
if(temp.getRight() != null)
System.out.print(temp.getRight().nodeNumber + ")");
else
System.out.print("null)");
temp = temp.getNext();
}
System.out.println();
*/
rowMarker = rowMarker.getLeft();
this.rows++;
//System.out.println("Currently have: " + this.rows + " rows.");
}
int count = 1;
if(this.rows == rows) {
if(rowMarker.getLeft()!=null)
rowMarker = rowMarker.getLeft();
if(rowMarker.getRight()!=null)
rowMarker = rowMarker.getRight();
while(rowMarker != null) {
rowMarker.setNumber(count++);
rowMarker = rowMarker.getNext();
}
}
}
//System.out.println("Board Ready");
}
public int plink(int startingColumn) {
//System.out.println("Start");
Node disc = entryPoint[startingColumn];
int level = 1;
while(disc.getNumber() == 0) {
//System.out.println("disc at: " + disc.nodeNumber);
if(disc.getLeft() == null) {
//System.out.println("going right");
disc = disc.getRight();
}
else if(disc.getRight() == null){
// System.out.println("going left");
disc = disc.getLeft();
}
else if(Math.random() <= 0.5){
// System.out.println("going left");
disc = disc.getLeft();
}
else{
// System.out.println("going right");
disc = disc.getRight();
}
}
return disc.getNumber();
}
}
Solution (Plinko Class):
=======================================
public class Plinko {
public static void main(String[] args) {
Board plinko = new Board(9,14);
for(int x = 0; x < 100; x++)
System.out.println("Ended on: " + plinko.plink(4));
}
}