Blocking Game
<< Card Shark | LabTrailIndex | Base Converter >>
This game described by UC Berkeley professor Dr Dan Garcia at gamescrafters.berkeley.edu was crafted by Greg Bonin and Tanya Gordeeva. Players move one of their two pieces until someone loses by being blocked and has no way to move their piece. The board has 5 nodes: 4 of them are arranged as the corners of the square and 1 node is in the middle. The node in the middle is connected diagonally to each corner. Each corner is connected to the two adjacent corners and also to the center node. However, the two nodes in the top left and top right corners are not connected to each other. The starting position: The first player has his or her pieces in the top left and top right corners. The other player has his or her pieces in the bottom left and bottom right corners.
See a Video Demo of the Game Being Playerd
Exercises
- Declare the instance fields of the
Node
class (see the comments and accessor methods in the starter code for hints} - Make a constructer for the
Node
class (see the comments in the starter code} - Implement the method
addLink
(see the comments in the starter code} - Implement the method
linkedTo
(see the comments in the starter code}
Things to try
- Make a new Version with different colors
- Make a variation with a different number of nodes and/or links
Starting Code
Node.java
import java.awt.Color; import java.awt.Graphics; import java.util.ArrayList; /** * A Node in the Blocking Game is a circular disc * that can be linked to other Nodes * * The Instance fields are: * 1. Its color (of type Color) * 2. The x,y coords of the Top Left corner * 3. The radius * 4. If it is selected (of type boolean) * 5. An ArrayList of type Node that has the nodes it can be linked to * * The constructor should have three fields: the x,y Coords of the the * top left corner, and the radius, sets the Color to Color.WHITE and * selected to false. * * * * @author Chris Thiel * @version 19 Mar 2016 */ public class Node { // DECLARE INSTANCE FIELDS public Node(int x, int y, int radius) { //YOUR CODE HERE } /** * Draws itself in the correct color as well as * indicating it is selected. * @param g the Graphics object to draw itself upon */ public void draw(Graphics g){ g.setColor(Color.BLACK); if (selected) g.setColor(Color.YELLOW); g.fillOval(x-3, y-3, 2*radius+6, 2*radius+6); g.setColor(color); g.fillOval(x, y, 2*radius, 2*radius); } /** * Using the pythagorean theorem, detects if a coordinate * is within the node's circular area * @param h the horizontal location of the point to test * @param k the vertical location of the point to test * @return true if (h,k) is inside the node */ public boolean contains(int h, int k) { return (h-centerX())*(h-centerX())+(centerY()-k)*(centerY()-k) < radius*radius; } /** * adds a node to the linked nodes (if it is not already linked), * checks to see if the other node is linked to this node * and if not, adds this link to the other's links * @param n */ public void addLink(Node other) { //YOUR CODE HERE } /** * returns whether or not the specified node is * in its links * @param n * @return */ public boolean linkedTo(Node n) { //YOUR CODE HERE } /** * Other Accessor methods: */ public void toggle() { selected=!selected;} public void deselect(){selected=false; } public void select() {selected=true;} public void setColor(Color color){this.color=color;} public int centerX(){return x+radius;} public int centerY(){return y+radius;} public boolean isSelected(){return selected;} public ArrayList<Node> getLinks() {return links;} public Color color(){return color;} }
BlockingGame.java
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import javax.swing.JFrame; import javax.swing.JPanel; /** * * @author Chris Thiel * @version 19 March 2016 * */ public class BlockingGame extends JPanel implements MouseListener { public static int WIDTH=800,HEIGHT=600, TOP=100, LEFT=75, GAP=80, SIZE=60; private Font titleFont, regularFont, giantFont; private Node[] nodes; private String message, message2, message3; private Color bgColor; private Color currentPlayer; private Node selectedNode; /** * The class constructor will initialize the ArrayList<Balloon> * and other object fields (variables), including a Timer * object from the javax.swing.* library. The timer will * generate an Action Event, so that something happens * in regular intervals without the user typing anything. */ public BlockingGame() { //initialize variables here... this.currentPlayer=null; this.selectedNode=null; titleFont = new Font("SansSerif", Font.BOLD, 24); giantFont = new Font("SansSerif", Font.BOLD, 72); regularFont = new Font("Serif", Font.PLAIN, 18); message="Which player starts, Blue or Red?"; message2="Click Blue or Red to start"; message3=""; bgColor = Color.GREEN; nodes=new Node[5]; nodes[0]=new Node(LEFT+GAP+SIZE, TOP+SIZE+GAP, SIZE); nodes[1]=new Node(LEFT, TOP, SIZE); nodes[2]=new Node(LEFT+2*GAP+2*SIZE, TOP, SIZE); nodes[3]=new Node(LEFT, TOP+2*GAP+2*SIZE, SIZE); nodes[4]=new Node(LEFT+2*GAP+2*SIZE, TOP+2*GAP+2*SIZE, SIZE); nodes[0].addLink(nodes[1]); nodes[0].addLink(nodes[2]); nodes[0].addLink(nodes[3]); nodes[0].addLink(nodes[4]); nodes[1].addLink(nodes[3]); nodes[2].addLink(nodes[4]); nodes[3].addLink(nodes[4]); nodes[1].setColor(Color.CYAN); nodes[2].setColor(Color.CYAN); nodes[3].setColor(Color.RED); nodes[4].setColor(Color.RED); repaint(); } /** * the main method makes an instance of our application and puts it in a JFrame * that will end the application when it is closed. * */ public static void main(String[] args) { BlockingGame app= new BlockingGame(); JFrame window = new JFrame("Blocking Game"); window.setSize(WIDTH, HEIGHT); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.getContentPane().add(app); window.addMouseListener(app); window.setVisible(true); } /** * This is the method to change what is drawn to the screen: */ public void paintComponent(Graphics g){ //super.paintComponent(g); if (this.currentPlayer!=null) bgColor=new Color(200, 255, 200); g.setColor(bgColor); g.fillRect(0, 0, getWidth(),getHeight()); g.setColor(Color.BLUE); g.setFont(titleFont); g.drawString("Blocking Game ver. 1.0", 20, 30); if (currentPlayer!=null && getLegalMoves().size()>0){ if (currentPlayer==Color.CYAN){ g.setColor(Color.BLUE); g.drawString("Blues's turn", WIDTH-300, TOP-20); }else{ g.setColor(Color.RED); g.drawString("Red's turn", WIDTH-300, TOP-20); } } g.setColor(Color.RED); g.setFont(giantFont); //g.drawString("LEVEL ", WIDTH-300, TOP+100); g.setColor(Color.BLACK); g.setFont(regularFont); g.drawString(message, 20, 60); g.drawString(message2, WIDTH-300, TOP+50); g.drawString(message3, WIDTH-300, TOP+80); paintLinks(g,nodes[0]); paintLinks(g,nodes[3]); paintLinks(g,nodes[4]); this.paintLegalMoves(g); for (Node n: nodes) n.draw(g); } public void paintLinks(Graphics g, Node n) { int x1=n.centerX(); int y1=n.centerY(); for (Node m: n.getLinks()) { int x2=m.centerX(); int y2=m.centerY(); g.drawLine(x1, y1, x2, y2); } } public void paintLegalMoves(Graphics g) { if (this.selectedNode==null || this.currentPlayer==null) return; g.setColor(currentPlayer); int x1=this.selectedNode.centerX(); int y1=this.selectedNode.centerY(); for (Node m: this.selectedNode.getLinks()) { int x2=m.centerX(); int y2=m.centerY(); if (m.color().equals(Color.WHITE)) { g.drawLine(x1, y1, x2, y2); } } } /** * getLegalMoves will return the Nodes that are white * that are connected to the current player's nodes. * If there is no current player it returns the * non-white nodes. If the size of the result is * zero, there are no legal moves left. * @return */ public ArrayList<Node> getLegalMoves(){ ArrayList<Node> result = new ArrayList<Node>(); if (currentPlayer==null){ for (Node n:nodes) if (!n.color().equals(Color.WHITE)) result.add(n); return result; } for (Node n: nodes){ if (n.color().equals(currentPlayer)){ for (Node m:n.getLinks()) if(m.color().equals(Color.WHITE)) result.add(m); } } return result; } /** * New Turn will switch the current player * then check to see if the game is over * that is, the new current player has no move to make */ public void newTurn() { String winner=""; if (currentPlayer.equals(Color.CYAN)){ currentPlayer=Color.RED; winner="Blue"; }else{ currentPlayer=Color.CYAN; winner="Red"; } int moves=getLegalMoves().size(); message3=moves+" move(s) can be made"; if(moves==0){ message2="No moves can be made!"; message3=winner+" wins!"; } } /** * These 5 methods need to be declared to implement the MouseListener Interface */ @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) { int x=e.getX(); int y=e.getY(); Node touched=null; for(int i=0; i< nodes.length; i++) { Node n=nodes[i]; if(n.contains(x, y)){ touched=n; //message3="node "+i; //diag } repaint(); } if (touched==null)// a random click not on a node return; if (currentPlayer==null && !touched.color().equals(Color.WHITE)) { // start of game a color of first move is chosen currentPlayer=touched.color(); } // if (this.selectedNode==null && touched.color().equals(Color.WHITE)){ message2="Select one of your own"; repaint(); return; } if (this.selectedNode==null && !touched.color().equals(currentPlayer)){ message2="Select one of your own"; repaint(); return; } if (this.selectedNode==null ) { // node to move was just selected message2="Select destination"; message=""; this.selectedNode=touched; touched.select(); touched=null; repaint(); }else{ if(selectedNode.linkedTo(touched) && touched.color().equals(Color.WHITE)) { //destination was just selected touched.setColor(selectedNode.color()); touched.deselect(); selectedNode.setColor(Color.WHITE); selectedNode.deselect(); message2="Select a peice to move"; this.newTurn(); selectedNode=null; touched=null; repaint(); } } repaint(); } @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} }