import java.util.*;

class GiocoPersona {
  Gioco gioco;
  Persona persona;

  public boolean equals(Object o) {
    if (o != null && getClass().equals(o.getClass())) {
      GiocoPersona gp = (GiocoPersona)o;
      return gioco.equals(gp.gioco) && persona.equals(gp.persona);
    }
    return false;
  }

  //Quanto segue va capito solo dopo avere studiato hashCode()
  public int hashCode() {
    return gioco.hashCode() + 31*persona.hashCode();  //cf. equals()!
  }


}

public class Ludoteca {

  // Rappresentazione degli oggetti Ludoteca
  
  private String nome;
  private Set ins; //uso l'intefaccia set
  
  // Costruttore
  public Ludoteca(String n) {
    nome = n;
    ins = new HashSet();  //uso una classe concreta che implementa
                              //Set
  }

  // funzioni pubbliche della classe
  public String nome() {
    return nome;
  }

  public boolean presente(Gioco g) {
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.gioco.equals(g)) return true;
    }
    return false;
  }

  public Persona chiHaIlGioco(Gioco g) {
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.gioco.equals(g)) return gp.persona;
    }
    return null;
  }

  public int numeroGiochi() {
    return ins.size();
  }

  public int numeroGiochiPrestati() {
    int cont = 0;
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.persona != null) cont++;
    }
    return cont;
  }

  public void aggiungiGioco(Gioco g) {
    if (presente(g)) return;
    GiocoPersona gp = new GiocoPersona();
    gp.gioco = g;
    gp.persona = null;
    ins.add(gp);
  }

  public void eliminaGioco(Gioco g) {
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.gioco.equals(g)) {
        it.remove();
        return;
      }
    }
  }

  public void prestaGioco(Gioco g, Persona p) {
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.gioco.equals(g)) {
        if (gp.persona != null) 
          throw new RuntimeException(
            "Errore, prestaGioco: il gioco e' gia' in prestito");
        else {
          gp.persona = p;
          return;
        }
      }
    }
    throw new RuntimeException(
      "Errore, prestaGioco: il gioco non e' presente");
  }

  public void restituisciGioco(Gioco g) {
    Iterator it = ins.iterator();
    while(it.hasNext()) {
      GiocoPersona gp = (GiocoPersona)it.next();
      if (gp.gioco.equals(g)) {
        if (gp.persona != null) {
          gp.persona = null;
          return;
        }
        else 
          throw new RuntimeException(
            "Errore, restituisciGioco: il gioco non e' in prestito");
      }
    }
    throw new RuntimeException(
      "Errore, retituisciGioco: il gioco non e' presente");
  }

  public Gioco[] tuttiIGiochi() {
    Gioco[] ris = new Gioco[numeroGiochi()];
    Object[] ao = ins.toArray();
    for(int i = 0; i < ao.length; i++)
      ris[i] = ((GiocoPersona)ao[i]).gioco;
    return ris;
  }

}
