import tester.*;
import java.util.LinkedList;

interface INode {
  int getData();
  INode getLeft();
  INode getRight();
  LinkedList<INode> lookAhead (int depth);
  int size();
}

abstract class AbsNode implements INode {
  // if this is private instead of protected, then Node/NodePromise 
  // can't access via this.data.  
  protected int data;
  
  AbsNode(int data) {
    this.data = data;
  }
  
  public int getData() { return this.data; }

  public LinkedList<INode> lookAhead(int depth) {
    if (depth == 0) {
      LinkedList<INode> newlist = new LinkedList<INode>();
      newlist.add(this);
      return newlist;
    }
    else {
      LinkedList<INode> leftresult = this.getLeft().lookAhead(depth - 1);
      LinkedList<INode> rightresult = this.getRight().lookAhead(depth - 1);
      leftresult.addAll(rightresult);
      return leftresult;
    }
  }
  
  public int size() {
    return 1 + getLeft().size() + getRight().size();
  }
}

class Node extends AbsNode {
  private INode left;
  private INode right;
  
  Node (int data, INode left, INode right) {
    super(data);
    this.left = left;
    this.right = right;
  }
  
  public INode getLeft() { return this.left; }
  public INode getRight() { return this.right; }
}

class NodePromise extends AbsNode { 
  NodePromise(int data) {
    super(data);
  }
  
  private INode force() {
    return new Node(this.data,
                    new NodePromise(this.data - 1),
                    new NodePromise(this.data + 1));
  }
  
  public INode getLeft() { return this.force().getLeft(); }
  public INode getRight() { return this.force().getRight(); }
  public int size() { return 0; }
}

class GameTree {
  // if make this private, need a getter to write examples class
  INode root;
  
  // notice constructor doesn't take data for its fields,
  //   but data to initialize the root node via its
  //   constructor
  GameTree(int rootdata) {
    this.root = new NodePromise(rootdata);
  }

  // this constructor takes no arguments but initializes
  // initial node to 0
  GameTree() {
    this.root = new NodePromise(0);
  }
}

class Examples {
  GameTree gt = new GameTree();
  
  boolean testLookAhead0 (Tester t) {
    return t.checkExpect(gt.root.lookAhead(0).size(),1);
  }
  
  boolean testLookAhead1 (Tester t) {
    return t.checkExpect(gt.root.lookAhead(1).size(),2);
  }
    
  boolean testLookAhead3 (Tester t) {
    return t.checkExpect(gt.root.lookAhead(3).size(),8);
  }
  
}