https://www.cs.indiana.edu/classes/c212-dgerman/spr2015/tylerdell.jpg

http://silo.cs.indiana.edu:8346/c212/spr2015/sketch-of-stage-three/

https://www.cs.indiana.edu/classes/c212-dgerman/spr2015/sampleFinal.pdf

http://silo.cs.indiana.edu:8346/c212/spr2015/exercise.phps

------

import java.awt.*; 

public interface World {
  public boolean hasEnded(); 
  public void draw(Graphics g); 
  public void update(); 
  public void keh(String key); 
}

----------------------------------------------------------( no change here )-----------

import java.awt.*; 
import javax.swing.*;

public class Tetris implements World {
  public Tetris() {
    super(); 
    this.current = new L( 20, 50, 1 ); // just because now I can 
    this.ground = new Ground(); // this will be side-effected
  }
  Tetromino current; 
  Ground ground; 
  public boolean hasEnded() { 

    return false; 
  } 
  public void draw(Graphics g) { 
    this.current.draw(g); 
    this.ground.draw(g); 
  }
  private int count;
  public void update() { 
    this.count += 1; 
    Tetromino future = this.current.moveDown(); 
    if (this.ground.overlaps( future )) {
      for (Block b : this.current)
        this.ground.add(b); 
      this.current = Tetromino.random();   
    } else {
      this.current = future; 
    }
    System.out.println( count ); 
  }
  public void keh(String key) { 
    if (key.equals("left")) {
      Tetromino future = this.current.moveLeft(); 
      if (this.ground.overlaps( future )) {
        
      } else {
        this.current = future; 
      }
    } else if (key.equals("right")) {
      Tetromino future = this.current.moveRight(); 
      if (this.ground.overlaps( future )) {
        
      } else {
        this.current = future; 
      }
    } else if (key.equals("up")) {
      Tetromino future = this.current.moveUp(); 
      if (this.ground.overlaps( future )) {
        
      } else {
        this.current = future; 
      }
    } else if (key.equals("down")) {
      Tetromino future = this.current.moveDown(); 
      if (this.ground.overlaps( future )) {
        
      } else {
        this.current = future; 
      }
    } else if (key.equals("rotate")) {
      Tetromino future = this.current.rotate(); 
      if (this.ground.overlaps( future )) {
        
      } else {
        this.current = future; 
      }
    } else {
      int code = Integer.parseInt(key); 
      switch (code) {
        case 'L': this.current = new L(this.current.x, 
                                       this.current.y, 
                                       this.current.direction);  
                  break; 
        case 'Z': this.current = new Z(this.current.x, 
                                       this.current.y, 
                                       this.current.direction);  
                  break; 
        case 'T': this.current = new T(this.current.x, 
                                       this.current.y, 
                                       this.current.direction);  
                  break; 
        case 'X': for (Block b : this.current)
                    this.ground.add(b); 
                  this.current = Tetromino.random(); 
                  break; 
        default:  break; 
      }
    }

  }
  public static void main(String[] args) {
    JFrame a = new JFrame(); 
    a.setSize(200, 500); 
    a.setVisible(true); 
    BigBang b = new BigBang( new Tetris() );
    a.addKeyListener( b ); 
    a.getContentPane().add( b ); 
    b.start(); 
  }
}

----------------------------------------------------------( some changes here )-----------

import javax.swing.*; 
import java.awt.event.*;
import java.awt.*; 

public class BigBang extends JComponent
                     implements ActionListener, 
                                KeyListener {
  World world; 
  Timer timer; 
  public BigBang(World w) {
    this.world = w;     
    this.timer = new Timer(1000, this);

  }
  public BigBang(int delay, World w) {
    this.world = w;     
    this.timer = new Timer(delay, this);
     
  }
  public void start() {
    this.timer.start();  
  }
  public void keyPressed(KeyEvent e) { 
    int code = e.getKeyCode(); 
    switch (code) {
      case 37: // left 
               this.world.keh( "left" ); 
               break;
      case 38: // up 
               this.world.keh( "up" ); 
               break;
      case 39: // right
               this.world.keh( "right" ); 
               break;
      case 40: // down 
               this.world.keh( "down" ); 
               break;
      case 32: this.world.keh( "rotate" );                    
               break;
      default: // what?!
               this.world.keh( code + "" );                    
               break; 
    }
    this.repaint(); 
  }
  public void keyReleased(KeyEvent e) { }
  public void keyTyped(KeyEvent e) { }
  public void actionPerformed(ActionEvent e) { 
    this.world.update(); 
    this.repaint(); 
  }
  public void paintComponent(Graphics g) {
    this.world.draw(g);  
  }
}

----------------------------------------------------------( change here as well )-----------

import java.awt.*; 

public class Block {
  public boolean overlaps(Block t) {
    return 
      Math.max(this.x, t.x) < Math.min(this.x + Block.SIZE, t.x + Block.SIZE) 
      && Math.max(this.y, t.y) < Math.min(this.y + Block.SIZE, t.y + Block.SIZE); 
  }
  final static int SIZE = 20; 
  private int x, y, w, h;
  private Color c; 
  public Block(int x, int y, Color c) {
    this.x = x;    
    this.y = y;    
    this.w = Block.SIZE;    
    this.h = Block.SIZE;    
    this.c = c;    
  }
  public String toString() { return "(" + this.x + ", " + this.x + ")" ; }
  public void draw(Graphics g) {
    g.setColor(this.c); 
    g.fillRect(this.x, this.y, this.w, this.h); 
    g.setColor(Color.BLACK); 
    g.drawRect(this.x, this.y, this.w, this.h); 
  }
  public Block moveLeft( ) { // this.x -= Block.SIZE; } 
    return new Block(this.x - Block.SIZE, this.y, this.c); }
  public Block moveRight() { // this.x += Block.SIZE; } 
      return new Block(this.x + Block.SIZE, this.y, this.c); }
  public Block moveUp(   ) { // this.y -= Block.SIZE; } 
    return new Block(this.x, this.y - Block.SIZE, this.c); }
  public Block moveDown( ) { // this.y += Block.SIZE; } 
    return new Block(this.x, this.y + Block.SIZE, this.c); }
}

----------------------------------------------------------( some change here too )-----------

import java.util.*; 
import java.awt.*; 

public class Ground extends ArrayList<Block> {
  public boolean overlaps(Tetromino t) {
    if (t.y > 400)
        return true; 
    for (Block b : this)
      for (Block c : t) 
        if (b.overlaps(c))
          return true; 
    return false; 
  }
  public void draw(Graphics g) {
    for (Block b : this)
      b.draw(g); 
  }
}

----------------------------------------------------------( changed )-----------

import java.awt.*; 
import java.util.*; 

public abstract class Tetromino extends ArrayList<Block> {
  
  public static Tetromino random() {
    int i = (int)(Math.random() * 7);    
    switch (i) {
      case 0: return new T(20, 50, 1); 
      case 1: return new Z(20, 50, 1); 
      default: 
              return new L(20, 50, 1); 
    }
  }
  
  protected int x, y; 
  protected int direction; // will take values 0, 1, 2, 3
  public Tetromino(int x, int y, int direction) {
    super(); // since I am in fact an ArrayList of Blocks
    this.x = x; 
    this.y = y; 
    this.direction = direction; 
  }
  public void draw(Graphics g) {
    for (Block b : this)
      b.draw(g); 
  }
  public abstract Tetromino moveLeft(); //  {
    // return new Tetromino
    // this.x -= Block.SIZE;  
    // for (Block b : this) b.moveLeft(); 
  // }
  public abstract Tetromino moveRight(); // {
    // this.x += Block.SIZE; 
    // for (Block b : this) b.moveRight(); 
  // }
  public abstract Tetromino moveUp(); // {
    // this.y -= Block.SIZE;  
    // for (Block b : this) b.moveUp(); 
  // } 
  public abstract Tetromino moveDown(); // {
    // this.y += Block.SIZE;  
    // for (Block b : this) b.moveDown(); 
  // }
  public abstract Tetromino rotate(); 
}

----------------------------------------------------------( changed some )-----------

import java.awt.*; 

public class L extends Tetromino {
  
  final static int[][][] shape = 
  {
    { { 0, 1, 0 },
      { 0, 1, 0 },
      { 0, 1, 1 }
    }, // index 0 in the shape array 
    { { 0, 0, 0 },
      { 1, 1, 1 },
      { 1, 0, 0 }
    }, // index 0 in the shape array 
    { { 1, 1, 0 },
      { 0, 1, 0 },
      { 0, 1, 0 }
    }, // index 0 in the shape array 
    { { 0, 0, 1 },
      { 1, 1, 1 },
      { 0, 0, 0 }
    }, // index 0 in the shape array 
        
  }; 
  
  public Tetromino moveLeft( ) { return new L(this.x - Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveRight() { return new L(this.x + Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveUp(   ) { return new L(this.x, 
                                              this.y - Block.SIZE, 
                                              this.direction ); }
  public Tetromino moveDown( ) { return new L(this.x, 
                                              this.y + Block.SIZE, 
                                              this.direction ); }
  
  public Tetromino rotate() {
    // this.direction += 1; // reminder a op= b; is the same as a = a op b;  
    // this.direction %= 4; 
    int newDirection = (this.direction + 1) % 4; 
    // // what else 
    // this.reset(); 
    return new L(this.x, this.y, newDirection); 
  }
  
  private void reset() {
    // this.clear(); 
    for (int i = 0; i < shape[direction].length; i++) 
      for (int j = 0; j < shape[direction][i].length; j++) 
        if (shape[direction][i][j] == 1)
          this.add( new Block( this.x + Block.SIZE * j, 
                               this.y + Block.SIZE * i, 
                               Color.MAGENTA
                             ) 
                  );      
  }
  
  public L(int x, int y, int d) {
    super(x, y, d); 
    this.reset();             
  }
}

----------------------------------------------------------( this is new )-----------

import java.awt.*; 

public class T extends Tetromino {
  
  final static int[][][] shape = 
  {
    { { 0, 1, 0 },
      { 1, 1, 1 },
      { 0, 0, 0 }
    }, // index 0 in the shape array 
    { { 0, 1, 0 },
      { 0, 1, 1 },
      { 0, 1, 0 }
    }, // index 0 in the shape array 
    { { 0, 0, 0 },
      { 1, 1, 1 },
      { 0, 1, 0 }
    }, // index 0 in the shape array 
    { { 0, 1, 0 },
      { 1, 1, 0 },
      { 0, 1, 0 }
    }, // index 0 in the shape array 
        
  }; 
  
  public Tetromino moveLeft( ) { return new T(this.x - Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveRight() { return new T(this.x + Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveUp(   ) { return new T(this.x, 
                                              this.y - Block.SIZE, 
                                              this.direction ); }
  public Tetromino moveDown( ) { return new T(this.x, 
                                              this.y + Block.SIZE, 
                                              this.direction ); }
  
  public Tetromino rotate() {
    // this.direction += 1; // reminder a op= b; is the same as a = a op b;  
    // this.direction %= 4; 
    int newDirection = (this.direction + 1) % 4; 
    // // what else 
    // this.reset(); 
    return new T(this.x, this.y, newDirection); 
  }
  
  private void reset() {
    // this.clear(); 
    for (int i = 0; i < shape[direction].length; i++) 
      for (int j = 0; j < shape[direction][i].length; j++) 
        if (shape[direction][i][j] == 1)
          this.add( new Block( this.x + Block.SIZE * j, 
                               this.y + Block.SIZE * i, 
                               Color.YELLOW
                             ) 
                  );      
  }
  
  public T(int x, int y, int d) {
    super(x, y, d); 
    this.reset();             
  }
}

----------------------------------------------------------( not changed )-----------

import java.awt.*; 

public class Z extends Tetromino {
  
  final static int[][][] shape = 
  {
    { { 1, 1, 0 },
      { 0, 1, 1 },
      { 0, 0, 0 }
    }, // index 0 in the shape array 
    { { 0, 0, 1 },
      { 0, 1, 1 },
      { 0, 1, 0 }
    }, // index 0 in the shape array 
    { { 0, 0, 0 },
      { 1, 1, 0 },
      { 0, 1, 1 }
    }, // index 0 in the shape array 
    { { 0, 1, 0 },
      { 1, 1, 0 },
      { 1, 0, 0 }
    }, // index 0 in the shape array 
        
  }; 
  
  public Tetromino moveLeft( ) { return new Z(this.x - Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveRight() { return new Z(this.x + Block.SIZE, 
                                              this.y, 
                                              this.direction ); }
  public Tetromino moveUp(   ) { return new Z(this.x, 
                                              this.y - Block.SIZE, 
                                              this.direction ); }
  public Tetromino moveDown( ) { return new Z(this.x, 
                                              this.y + Block.SIZE, 
                                              this.direction ); }
  
  public Tetromino rotate() {
    // this.direction += 1; // reminder a op= b; is the same as a = a op b;  
    // this.direction %= 4; 
    int newDirection = (this.direction + 1) % 4; 
    // // what else 
    // this.reset(); 
    return new Z(this.x, this.y, newDirection); 
  }
  
  private void reset() {
    // this.clear(); 
    for (int i = 0; i < shape[direction].length; i++) 
      for (int j = 0; j < shape[direction][i].length; j++) 
        if (shape[direction][i][j] == 1)
          this.add( new Block( this.x + Block.SIZE * j, 
                               this.y + Block.SIZE * i, 
                               Color.GREEN
                             ) 
                  );      
  }
  
  public Z(int x, int y, int d) {
    super(x, y, d); 
    this.reset();             
  }
}

----------------------------------------------------------( either new or not changed )-----------