MasterMindModel.java
Created with JBuilder
package mastermind;

/**
 * MasterMindModel -
 * Enthält das ganze Spielbrett mit den Regeln, dem Code und einer Test Routine.
 *
 * Mind Blowing Master Mind ein klein Projekt des Informatik Unterrichts Programmieren II
 * Authors Pascal Naef; Fabian Heusser
 * Teacher: H. J. Diethlem
 * School: hta.fhz.ch, Horw;
 * Project Homepage: http://www.w3p.ch/mastermind/
 *
 * supported features:
 * OYOAHA Look and feel;
 * Transparen Pictures;
 * Drag & Drop;
 * Copy & Paste;
 *
 *
 * LEGAL NOTICE
 * THIS PROJECT AND ITS FILES ARE COPYRIGHTED BY THE AUTHORS
 * THIS PROJECT CAN BE COPIED, MODIFIED AND DISTRIBUTED
 * UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENCE
 * WITH THE RESTRICTION OF SENDING US A MAIL WITH THE MODIFIED
 * SOURCODE IF THE PROJECT IS MODIEFIED.
 *
 * if you like this progi feel free to send us something (beer, chips, playmates, houses....).
 *
 *
 * @author Fabian Heusser
 * @author Pascal Naef
 * @version 1.0 $Date: 2001/12/05 14:46:53 $ $Revision: 1.1.1.1 $
 * @(#) MasterMindView.java
 */

// 2001-11-16 hef getScore() improved

public class MasterMindModel {

  private int[][] playGround;
  private String code;
  private int width, height, colors, currentRow;
  private static final int maxColor = 10; //Maximale anzahl Farben
  private static final boolean blockInactiveRows = false; //soll man auch auf reihen setzten können die nicht aktiv sind?
  private static final boolean allowCheating = false;

  /**
   * Der Konstruktor generiert den CODE und definiert die Grösse.
   * @param width int, Anzahl der Code Stellen. 1 - ...
   * @param height int, Anzahl der Maximalen Versuchen 1 - ...
   * @param colors int, number of different colors 1 - 10 are valid arguments
   */
  public MasterMindModel(int width, int height, int colors) throws IllegalArgumentException {
     //check params an assign them
     if (colors > maxColor || colors < 0) throw new IllegalArgumentException("color is not in a valid range");
     if (width < 1) throw new IllegalArgumentException("width is not in a valid range");
     if (height < 1) throw new IllegalArgumentException("height is not in a valid range");

     this.width = width;
     this.height = height;
     this.colors = colors;

     //creating random Code
     code = "";
     for(int i=1; i<=width; i++){
        code += (int) (Math.random() * (double) this.colors) + 1;
     }

     //code = "1244";
     //System.out.println(code);

     //setting up the PlayGround itself
     playGround = new int[this.width][this.height];
     currentRow = 0;
     runSelfTest();
  }

  /**
   * Setzt an einer Position eine Farbe
   * @param x int, Position auf der Akutellen Linie dessen Farbe gesetzt werden Soll. 0 - ...
   * @param color int Farbe die der Stift erhalten soll
   */
  public void setTack(int x, int color) throws IllegalArgumentException{
     if (color > this.colors || color < 0) throw new IllegalArgumentException("color is not in a valid range");
     if (x < 0 || x > this.width-1) throw new IllegalArgumentException("x is not in a valid range");

     playGround[x][currentRow] = color;
  }

  /**
   * Setzt an einer Position eine Farbe
   * @param x int, Position auf der Linie dessen Farbe gesetzt werden Soll. 0 - ...
   * @param y int, Position in der Höhe dessen Farbe gesetzt werden Soll. 0 - ...
   * @param color int Farbe die der Stift erhalten soll
   */
  public void setTack(int x, int y, int color) throws IllegalArgumentException{
     if (blockInactiveRows && y != currentRow) return;
     if (!allowCheating && y < currentRow) return;
     if (color > this.colors || color < 0) throw new IllegalArgumentException("color is not in a valid range");
     if (x < 0 || x > this.width-1) throw new IllegalArgumentException("x is not in a valid range");

     playGround[x][y] = color;
  }

  /**
   * Lifert die Farbe eines Stiftes zurück
   * @param x int, Lage des Stiftes in der Horizontalen
   * @param y int, Lage des Stiftes in der Vertikalen
   * @return int, farbe in Form einer Nummer
   */

  public int getTack(int x, int y) throws IllegalArgumentException{
     if (x < 0 || x > this.width-1) throw new IllegalArgumentException("x is not in a valid range");
     if (y < 0 || y > this.height-1) throw new IllegalArgumentException("y is not in a valid range");

     return playGround[x][y];
  }

  /**
   * Gibt die breite, also die Code Länge zurück
   * @return int, Schlüssel Länge 1 - ..
   */
  public int getWidth(){return width;}

  /**
   * Gibt die Maximal mögliche Anzahl Versuche zurück um den Code zu Knacken.
   * @return int, Maximale Anzahl Versuche 1 - ..
   */
  public int getHeight(){return height;}

  /**
   * Gibt die Anzahl verschieder farben zurück die benötigt werden
   * @return int, Maximale Anzahl Versuche 1 - ..
   */
  public int getColors(){return colors;}

  /**
   * Berechnet die Auswertung der gesetzen Tacks.
   * @param y int, Zeile welche berechnet werden soll
   * @return Score im Format: [Anzahl Richtig Plazierte (also die Schwarzen)] * 100 +
   *         [Anzahl Richtige Farbe am Falschen Platz (also die weissen)]
   *         you have won if you reach a score of (width * 100)
   */
  //2001-11-16 hef banned mechanisme added, whitout that the algorithm fail under certain circumstances
  public int getScore(int y){
     if (!allowCheating && y >= currentRow) return 0;
     int score = 0;
     boolean[] banned_i = new boolean[width];
     boolean[] banned_k = new boolean[width];
     for(int i=banned_i.length; --i>0;){banned_i[i] = false; banned_k[i] = false;};

     for(int i=0; i < width; i++){
       if (playGround[i][y] == code.charAt(i)-0x30) {
         score += 100;   			//exact match
         banned_i[i] = true;
         banned_k[i] = true;
       }
     }

     //checking color matching ...
     for(int i=0; i < width; i++){
       if (banned_i[i]) {continue;}
       for(int k=0; k < width; k++){
         if (banned_k[k]) {continue;}

         if (playGround[k][y] == code.charAt(i)-0x30) {
           score++; 				//color match
           banned_k[k] = true;
           break;
         }

       }
     }

     return score;
  }

  /**
   * Incrementiert der Aktuelle Zug
   * Einflussreich beim ganzen RegelWerk. So können reihen nicht mehr gesetzt
   * werden die kleinder sind asl currentRow
   */
  public void incrementTurn(){
    currentRow++;
  }

  /**
   * Liefert den Aktuellen Spielzug zurück
   * @return int aktueller Höhe an der Gebastelt wird
   */
  public int getTurn(){return currentRow; }

  /**
   * Liefert true wenn das Spiel gewonnen wurde
   * @return boolean, True falls Alle Tacks der letzten reihe richtig sind.
   */
  public boolean getWon(){return getScore(currentRow-1) == (width * 100);}

  /**
   * Liefert true fals das Spiel verloren wurde.
   * @return boolean, true falls der aktuelle Spielzug grösser als die höhe des mastermind ist
   */
   public boolean getLoose(){return currentRow >= height;}

   /**
    * Liefert das Code Wort zurück
    * @return String Code Wort in width chars welche die farben representieren
    *
    */
   public String getCode(){return code;}

   /**
    * Liefert zurück ob der aktuelle spielzug komplett ist.
    * @return boolean, true wenn alle tacks gesetzt sind des aktuellen zug.
    *
    */
   public boolean isTurnComplete(){
     boolean b = true;
     for (int i = 0; i < width; i++){
       if (playGround[i][currentRow] < 1) {
         b = false;
       }
     }
     return b;
   }


   // SELF TEST PROCEDURES
   /**
    * Let The Procedures Make a self Test.
    * @return bollean, false if test failed.
    */
   public boolean runSelfTest(){
   // we gonna save the object status;
     int[][] tmp = playGround;
     int tmpHeight = height;
     int tmpWidth = width;
     int tmpCurrentRow = currentRow;
     String tmpCode = code;

     boolean test = true;

   // Test Values Last schould be one that fit the won contition!
     String[] testCases =  {"2323","1333","2111","3123","4321","1111","1112","2131","1423",
                                 "1222","1242","1243","1214","1234","1234"};
     String[] TestOnCode = {"4141","4441","1234","1234","1234","1234","1234","1234","1234",
                                 "1234","1234","1234","1234","1244","1234"};
     int[] testScores = {0,1,2,3,4,100,101,102,103,200,201,202,300,300,400};

     playGround = new int[testCases[0].length()][testCases.length];
     for (int i=testCases.length; --i>0;){
       for (int k=testCases[0].length(); --k>0;){  playGround[k][i] = 0; }
     }

     height = testCases.length;
     width = testCases[0].length();

    for (int i=0; i<testCases.length; i++){
       for (int k=width; --k>=0;){
         setTack(k,testCases[i].charAt(k)-0x30);
       }
       code = TestOnCode[i];
       if (getScore(i) != testScores[i]) {
         test = false;
       }
       incrementTurn();
    }
    //a littel hack
    currentRow--;
    if (!getWon()) {test = false;}
    incrementTurn();
    if (!getLoose()) {test = false;}


    playGround = tmp;
    height = tmpHeight;
    width = tmpWidth;
    currentRow = tmpCurrentRow;
    code = tmpCode;

    return test;

   }
}

/*
 * History:
 * $Log: MasterMindModel.java,v $
 * Revision 1.1.1.1  2001/12/05 14:46:53  hef
 * no message
 *
 * Revision 1.3  2001/11/29 13:21:33  pascal
 * no message
 *
 * Revision 1.1.1.1  2001/11/25 22:15:46  hef
 * R3 clean check in
 *
 * Revision 1.1.1.1  2001/11/25 22:02:23  hef
 * The Graphical Mastermind
 *
 * Revision 1.11  2001/11/23 15:59:01  hef
 * last bug fixed i hope
 *
 * Revision 1.10  2001/11/22 21:48:20  hef
 * Main Doku Erweitert
 * Sync from NoteBook
 *
 * Revision 1.9  2001/11/21 22:20:55  hef
 * Maka a clean version for sync
 *
 * Revision 1.8  2001/11/20 21:52:13  hef
 * now with wonderful keywords inserted
 *
 * Revision 1.5  2001/11/20 21:44:44  hef
 * Last version of the Model. (i Hope)
 *
 */

MasterMindModel.java
Created with JBuilder