 
//------------neue_Teilaufgabe--------- file = lsg201a.java
interface Directions {
  static final int north = 0, east  = 1, south = 2, west  = 3;
}

// ------------------------------------------------------------

class MapSite {
  void Enter() {/* ... */};
}

// ------------------------------------------------------------

class Room extends MapSite {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  
  Room(int roomNo) {
    this.roomNo = roomNo;
  }
  
  MapSite GetSide(int direction) {return null; /* for now */};
  
  void SetSide(int direction, MapSite ms) {
    sides[direction] = ms;
  };
}

// ------------------------------------------------------------

class EnchantedRoom extends Room {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  String spell;
  
  EnchantedRoom(int roomNo, String spell) {
    super(roomNo);
    this.spell  = spell;
  }
}

// ------------------------------------------------------------

class DoorWall extends MapSite {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  
  DoorWall(Room r1, Room r2) {
    this.r1 = r1;
    this.r2 = r2;
    this.isOpen = false;
  };
  
  Room OtherSideFrom(Room r) {return null; /* for now */};
}

// ------------------------------------------------------------

class DoorWallNeedingSpell extends DoorWall {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  String spell;
  
  DoorWallNeedingSpell(Room r1, Room r2, String spell) {
    super(r1, r2);
    this.spell = spell;
  };
}

// ------------------------------------------------------------

class Maze {
  void AddRoom(Room r) {};
  Room RoomNo(int r) {return null;};
}

// ------------------------------------------------------------

class Wall extends MapSite {
}

// ------------------------------------------------------------

interface MazeFactory {
  Maze MakeMaze();
  Wall MakeWall();
  Room MakeRoom(int n);
  DoorWall MakeDoorWall(Room r1, Room r2);
}

// ------------------------------------------------------------

class PureMazeFactory implements MazeFactory {
  //Singleton
  private static PureMazeFactory TheFactory;
  protected PureMazeFactory() {}
  static MazeFactory Instance() {
    if (TheFactory == null)
      TheFactory = new PureMazeFactory();
    return TheFactory;
  }
  
  public Maze MakeMaze() {
    return new Maze();
  }
  public Wall MakeWall() {
    return new Wall();
  }
  public Room MakeRoom(int n) {
    return new Room(n);
  }
  public DoorWall MakeDoorWall(Room r1, Room r2) {
    return new DoorWall(r1, r2);
  }
}

// ------------------------------------------------------------

class EnchantedMazeFactory extends PureMazeFactory {
  //Singleton
  private static EnchantedMazeFactory TheFactory;
  protected EnchantedMazeFactory() {}
  static MazeFactory Instance() {
    if (TheFactory == null)
      TheFactory = new EnchantedMazeFactory();
    return TheFactory;
  }
  
  public Room MakeRoom(int n) {
    return new EnchantedRoom(n, SomeSpell());
  }
  public DoorWall MakeDoorWall(Room r1, Room r2) {
    return new DoorWallNeedingSpell(r1, r2, SomeSpell());
  }
  private String SomeSpell() {
    return "Abrakadabra";  // for now
  }
}

// ------------------------------------------------------------

class MazeGame implements /* uses */ Directions {
  public static void main(String[] argv) {
    // MazeFactory factory = PureMazeFactory.Instance();
    MazeFactory factory = EnchantedMazeFactory.Instance();
    CreateMaze(factory);
  }
 
  static Maze CreateMaze(MazeFactory factory) {
    Maze aMaze = factory.MakeMaze();
    Room r1 = factory.MakeRoom(1);
    Room r2 = factory.MakeRoom(2);
    DoorWall d  = factory.MakeDoorWall(r1, r2);
 
    aMaze.AddRoom(r1);
    aMaze.AddRoom(r2);
 
    r1.SetSide(north, factory.MakeWall());
    r1.SetSide(east,  d);
    r1.SetSide(south, factory.MakeWall());
    r1.SetSide(west,  factory.MakeWall());
 
    r2.SetSide(north, factory.MakeWall());
    r2.SetSide(east,  factory.MakeWall());
    r2.SetSide(south, factory.MakeWall());
    r2.SetSide(west,  d);
 
    return aMaze;
  }
  
}

 
//------------neue_Teilaufgabe--------- file = lsg201b.java
interface Directions {
 static final int north = 0, east = 1, south = 2, west  = 3;
}

// ------------------------------------------------------------

class MapSite {
  void Enter() {/* ... */};
}

// ------------------------------------------------------------

class Room extends MapSite {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  
  Room(int roomNo) {
    this.roomNo = roomNo;
  }
  
  MapSite GetSide(int direction) {return null; /* for now */};
  
  void SetSide(int direction, MapSite ms) {
    sides[direction] = ms;
  };
}

// ------------------------------------------------------------

class EnchantedRoom extends Room {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  String spell;
  
  EnchantedRoom(int roomNo, String spell) {
    super(roomNo);
    this.spell  = spell;
  }
}

// ------------------------------------------------------------

class DoorWall extends MapSite {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  
  DoorWall(Room r1, Room r2) {
    this.r1 = r1;
    this.r2 = r2;
    this.isOpen = false;
  };
  
  Room OtherSideFrom(Room r) {return null; /* for now */};
}

// ------------------------------------------------------------

class DoorWallNeedingSpell extends DoorWall {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  String spell;
  
  DoorWallNeedingSpell(Room r1, Room r2, String spell) {
    super(r1, r2);
    this.spell = spell;
  };
}

// ------------------------------------------------------------

class Maze {
  void AddRoom(Room r) {};
  Room RoomNo(int r) {return null;};
}

// ------------------------------------------------------------

class Wall extends MapSite {
}

// ------------------------------------------------------------

class MazeGame implements /* uses */ Directions {
  public static void main(String[] argv) {
    CreateMaze();
  }

  static Maze MakeMaze() {
    return new Maze();
  }
  static Room MakeRoom(int r) {
    return new Room(r);
  }
  static DoorWall MakeDoorWall(Room r1, Room r2) {
    return new DoorWall(r1,r2);
  }
  static Wall MakeWall() {
    return new Wall();
  }
  
  static Maze CreateMaze() {
    Maze aMaze = MakeMaze();
    Room r1 = MakeRoom(1);
    Room r2 = MakeRoom(2);
    DoorWall d  = MakeDoorWall(r1, r2);
 
    aMaze.AddRoom(r1);
    aMaze.AddRoom(r2);
 
    r1.SetSide(north, MakeWall());
    r1.SetSide(east,  d);
    r1.SetSide(south, MakeWall());
    r1.SetSide(west,  MakeWall());
 
    r2.SetSide(north, MakeWall());
    r2.SetSide(east,  MakeWall());
    r2.SetSide(south, MakeWall());
    r2.SetSide(west,  d);
 
    return aMaze;
  }
}

// ------------------------------------------------------------

class EnchantedMazeGame extends MazeGame {
  public static void main(String[] argv) {
    CreateMaze();
  }
  static Room MakeRoom(int r) {
    return new EnchantedRoom(r, SomeSpell());
  }
  static DoorWall MakeDoorWall(Room r1, Room r2) {
    return new DoorWallNeedingSpell(r1,r2, SomeSpell());
  }

  private static String SomeSpell() {
    return "Abrakadabra";  // for now
  }
}
 
//------------neue_Teilaufgabe--------- file = lsg201c.java
interface Directions {
  static final int north = 0, east = 1, south = 2, west = 3;
}

// ------------------------------------------------------------

class MapSite {
  void Enter() {/* ... */};
}

// ------------------------------------------------------------

class Room extends MapSite {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  
  Room(int roomNo) {
    this.roomNo = roomNo;
  }
  
  MapSite GetSide(int direction) {return null; /* for now */};
  
  void SetSide(int direction, MapSite ms) {
    sides[direction] = ms;
  };
}

// ------------------------------------------------------------

class EnchantedRoom extends Room {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  String spell;
  
  EnchantedRoom(int roomNo, String spell) {
    super(roomNo);
    this.spell  = spell;
  }
}

// ------------------------------------------------------------

class DoorWall extends MapSite {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  
  DoorWall(Room r1, Room r2) {
    this.r1 = r1;
    this.r2 = r2;
    this.isOpen = false;
  };
  
  Room OtherSideFrom(Room r) {return null; /* for now */};
}

// ------------------------------------------------------------

class DoorWallNeedingSpell extends DoorWall {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  String spell;
  
  DoorWallNeedingSpell(Room r1, Room r2, String spell) {
    super(r1, r2);
    this.spell = spell;
  };
}

// ------------------------------------------------------------

class Maze {
  void AddRoom(Room r) {};
  Room RoomNo(int r) {return null;};
}

// ------------------------------------------------------------

class Wall extends MapSite {
}

// ------------------------------------------------------------

class MazeGame implements /* uses */ Directions {
  public static void main(String[] argv) {
    // MazeBuilder builder = new PureMazeBuilder();
    MazeBuilder builder = new EnchantedMazeBuilder();
    CreateMaze(builder);
  }
 
  static Maze CreateMaze(MazeBuilder builder) {
    builder.buildMaze();
    builder.buildRoom(1);
    builder.buildRoom(2);
    builder.buildDoorWall(1, east, 2, west);
    return builder.getMaze();
  }
}

// ------------------------------------------------------------

interface MazeBuilder extends /* uses */ Directions {
  void buildMaze();
  void buildRoom(int r);
  void buildDoorWall(int r1, int side1, int r2, int side2);
  Maze getMaze();
}

// ------------------------------------------------------------

class PureMazeBuilder implements MazeBuilder {
  protected Maze currentMaze;
  public void buildMaze() {
    currentMaze = new Maze();
  }
  public Maze getMaze() {
    return currentMaze;
  }
  public void buildRoom(int r) {
    if (currentMaze.RoomNo(r) == null) {
      Room room = new Room(r);
      currentMaze.AddRoom(room);
      room.SetSide(north, new Wall());
      room.SetSide(east,  new Wall());
      room.SetSide(south, new Wall());
      room.SetSide(west,  new Wall());
    }
  }
  public void buildDoorWall(int r1, int side1, int r2, int side2) {
    Room room1 = currentMaze.RoomNo(r1);
    Room room2 = currentMaze.RoomNo(r2);
    if ((room1 != null) && (room2 != null)) {
      DoorWall d = new DoorWall(room1, room2);
      room1.SetSide(side1,d);
      room2.SetSide(side2,d);
    }
  }
}

// ------------------------------------------------------------

class EnchantedMazeBuilder extends PureMazeBuilder {
  public void buildRoom(int r) {
    if (currentMaze.RoomNo(r) == null) {
      Room room = new EnchantedRoom(r, SomeSpell());
      currentMaze.AddRoom(room);
      room.SetSide(north, new Wall());
      room.SetSide(east,  new Wall());
      room.SetSide(south, new Wall());
      room.SetSide(west,  new Wall());
    }
  }
  public void buildDoorWall(int r1, int side1, int r2, int side2) {
    Room room1 = currentMaze.RoomNo(r1);
    Room room2 = currentMaze.RoomNo(r2);
    if ((room1 != null) && (room2 != null)) {
      DoorWall d = new DoorWallNeedingSpell(room1, room2, SomeSpell());
      room1.SetSide(side1,d);
      room2.SetSide(side2,d);
    }
  }
  private static String SomeSpell() {
    return "Abrakadabra";  // for now
  }
}
 
//------------neue_Teilaufgabe--------- file = lsg201d.java
interface Directions {
  static final int north = 0, east = 1, south = 2, west = 3;
}

// ------------------------------------------------------------

class MapSite {
  void Enter() {/* ... */};
}

// ------------------------------------------------------------

class Room extends MapSite implements Cloneable {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  
  Room(int roomNo) {
    this.roomNo = roomNo;
  }

  Room() {}
  
  MapSite GetSide(int direction) {return null; /* for now */};
  
  void SetSide(int direction, MapSite ms) {
    sides[direction] = ms;
  };

  Room cloneIt() {
    try {
      return (Room)clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }
  }
  void initialize(int roomNo) {
    this.roomNo = roomNo;
  }
}

// ------------------------------------------------------------

class EnchantedRoom extends Room {
 
  private MapSite[] sides = new MapSite[4];
  private int roomNo;
  String spell;
  
  EnchantedRoom(int roomNo, String spell) {
    super.initialize(roomNo);
    this.spell  = spell;
  }

  EnchantedRoom() {};
  void initialize(int roomNo) {
    super.initialize(roomNo);
    spell  = SomeSpell();
  }
  private String SomeSpell() {
    return "Abrakadabra";  // for now
  }
}

// ------------------------------------------------------------

class DoorWall extends MapSite implements Cloneable {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  
  DoorWall(Room r1, Room r2) {
    this.r1 = r1;
    this.r2 = r2;
    this.isOpen = false;
  }

  DoorWall() {}
  
  Room OtherSideFrom(Room r) {return null; /* for now */};

  DoorWall cloneIt() {
    try {
      return (DoorWall)clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }
  }
  void initialize(Room r1, Room r2) {
    this.r1 = r1;
    this.r2 = r2;
  }
}

// ------------------------------------------------------------

class DoorWallNeedingSpell extends DoorWall {
 
  private Room r1;
  private Room r2;
  private boolean isOpen;
  String spell;
  
  DoorWallNeedingSpell(Room r1, Room r2, String spell) {
    super.initialize(r1, r2);
    this.spell = spell;
  };

  DoorWallNeedingSpell() {};
  void initialize(Room r1, Room r2) {
    super.initialize(r1, r2);
    this.spell = SomeSpell();
  }
  private String SomeSpell() {
    return "Abrakadabra";  // for now
  }
}

// ------------------------------------------------------------

class Wall extends MapSite implements Cloneable {
  Wall cloneIt() {
    try {
      return (Wall)clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }
  }
}

// ------------------------------------------------------------

class Maze implements Cloneable {
  void AddRoom(Room r) {};
  Room RoomNo(int r) {return null;};
  Maze cloneIt() {
    try {
      return (Maze)clone();
    } catch (CloneNotSupportedException e) {
      return null;
    }
  }
}


// ------------------------------------------------------------

class PrototypeFactory {
  //Singleton
  private static PrototypeFactory TheFactory;
  private PrototypeFactory(Maze m, Room r, Wall w, DoorWall d) {
    protoMaze = m;
    protoRoom = r;
    protoWall = w;
    protoDoorWall = d;
  }
  static PrototypeFactory Instance(Maze m, Room r, Wall w, DoorWall d) {
    if (TheFactory == null)
      TheFactory = new PrototypeFactory(m,r,w,d);
    return TheFactory;
  }

  //Prototypes
  private Maze protoMaze;
  private Room protoRoom;
  private Wall protoWall;
  private DoorWall protoDoorWall;
  
  public Maze MakeMaze() {
    return protoMaze.cloneIt();
  }
  public Wall MakeWall() {
    return protoWall.cloneIt();
  }
  public Room MakeRoom(int n) {
    Room newRoom = protoRoom.cloneIt();
    newRoom.initialize(n);
    return newRoom;
  }
  public DoorWall MakeDoorWall(Room r1, Room r2) {
    DoorWall newDoorWall = protoDoorWall.cloneIt();
    newDoorWall.initialize(r1, r2);
    return newDoorWall;
  }
}

// ------------------------------------------------------------

class MazeGame implements /* uses */ Directions {
  public static void main(String[] argv) {
/*    
    PrototypeFactory factory = PrototypeFactory.Instance(
        new Maze(),new Room(), new Wall(), new DoorWall());
*/
    PrototypeFactory factory = PrototypeFactory.Instance(
	new Maze(), new EnchantedRoom(), new Wall(), new DoorWallNeedingSpell());
    CreateMaze(factory);
  }
 
  static Maze CreateMaze(PrototypeFactory factory) {
    Maze aMaze = factory.MakeMaze();
    Room r1 = factory.MakeRoom(1);
    Room r2 = factory.MakeRoom(2);
    DoorWall d  = factory.MakeDoorWall(r1, r2);
 
    aMaze.AddRoom(r1);
    aMaze.AddRoom(r2);
 
    r1.SetSide(north, factory.MakeWall());
    r1.SetSide(east,  d);
    r1.SetSide(south, factory.MakeWall());
    r1.SetSide(west,  factory.MakeWall());
 
    r2.SetSide(north, factory.MakeWall());
    r2.SetSide(east,  factory.MakeWall());
    r2.SetSide(south, factory.MakeWall());
    r2.SetSide(west,  d);
 
    return aMaze;
  }
}

