For the problem statement shown below:Part II(b):Your run-length encodings will only be useful if other classes  have the ability to read them after you create them.  Therefore, implement the  nextRun() and restartRuns() methods.  These two methods work together to return  all the runs in a run-length encoding to an outside application, one by one.  Each time nextRun() is invoked, it returns a different run--represented as a  TypeAndSize object--until every run has been returned.  The first time  nextRun() is invoked, it returns the first run in the encoding, which contains  cell (0, 0).  After every run has been returned, nextRun() returns null, which  lets the calling program know that there are no more runs in the encoding.The restartRuns() method resets the enumeration, so that nextRun() will once  again return the first run as if it were being called for the first time.  Warning:  the test code will not necessarily call restartRuns() before the  first time nextRun() is called.IMPORTANT NOTE on nextRun() and restartRuns():  your methods in the  RunLengthEncoding class should never call these methods.  The nextRun() and  restartRuns() methods are provided so that other classes (specifically, the  Test program that autogrades your project) can read the contents of a  run-length encoding.  If your RunLengthEncoding methods call them, they will  mess up the position of the internal pointer for the other classes.IMPORTANT NOTE on TypeAndSize:  The Java return keyword only allows you to  return one value from a method call.  But the nextRun() method needs to return  two values--the length of a run, and the type of object it contains.  How can  it do this?  Answer:  by returning a TypeAndSize object.  A TypeAndSize  object is nothing more than a way to return two integers at once.  That's it.  Each time nextRun() is called, it creates a TypeAndSize object (or it will once  you've coded it to do so), fills in the values, and returns it to the calling  routine, which then throws it away.  The TypeAndSize object is part of the  predefined interface of your RunLengthEncoding class, so you CANNOT change it,  because the calling programs (including the autograder) are relying on you to  return TypeAndSize objects according to spec.  TypeAndSize objects are NOT  suitable as a way to represent a run in your run-length encoding, because they  do not encode a shark's hunger.Part II(c):Implement a toOcean() method in the RunLengthEncoding class, which  converts a run-length encoding to an Ocean object.  To accomplish this, you  will need to implement a new addShark() method in the Ocean class, so that you  can specify the hunger of each shark you add to the ocean.  This way, you can  convert an Ocean to a run-length encoding and back again without forgetting how  hungry each shark was.Read RunLengthEncoding.java carefully for an explanation of what methods you  must write.  The fields of the Ocean class MUST be private, and the  RunLengthEncoding class cannot manipulate these fields directly.  Hence, the  toOcean() method will rely upon the Ocean constructor and the addFish() and  addShark() methods.You cannot change any of the prototypes in RunLengthEncoding.java, and you  cannot change the file TypeAndSize.java.  Again, we will test your code by  calling your methods directly.Part III:  Converting an Ocean to a Run-Length Encodingwrite a RunLengthEncoding constructor that takes an Ocean object as its  sole parameter and converts it into a run-length encoding of the Ocean.  To  accomplish this, you will need to implement a sharkFeeding() method in the  Ocean class, which tells you how hungry a given shark is.  Read Ocean.java and  RunLengthEncoding.java carefully for an explanation of what methods you must  write.The fields of the Ocean class MUST be private, so the RunLengthEncoding  constructor will rely upon the width(), height(), starveTime(), cellContents(),  and sharkFeeding() methods.Here is my solution:RunLengthEncoding:/* RunLengthEncoding.java */package Project1;/** *  The RunLengthEncoding class defines an object that run-length encodes an *  Ocean object.  Descriptions of the methods you must implement appear below. *  They include constructors of the form * *      public RunLengthEncoding(int i, int j, int starveTime); *      public RunLengthEncoding(int i, int j, int starveTime, *                               int[] runTypes, int[] runLengths) { *      public RunLengthEncoding(Ocean ocean) { * *  that create a run-length encoding of an Ocean having width i and height j, *  in which sharks starve after starveTime timesteps. * *  The first constructor creates a run-length encoding of an Ocean in which *  every cell is empty.  The second constructor creates a run-length encoding *  for which the runs are provided as parameters.  The third constructor *  converts an Ocean object into a run-length encoding of that object. * *  See the README file accompanying this project for additional details. */class RunLengthEncoding {  /**   *  Define any variables associated with a RunLengthEncoding object here.   *  These variables MUST be private.   */  private DList2 list;  private long sizeOfRun;  private int width;  private int height;  private static int starveTime;  /**   *  restartRuns() and nextRun() are two methods that work together to return   *  all the runs in the run-length encoding, one by one.  Each time   *  nextRun() is invoked, it returns a different run (represented as a   *  TypeAndSize object), until every run has been returned.  The first time   *  nextRun() is invoked, it returns the first run in the encoding, which   *  contains cell (0, 0).  After every run has been returned, nextRun()   *  returns null, which lets the calling program know that there are no more   *  runs in the encoding.   *   *  The restartRuns() method resets the enumeration, so that nextRun() will   *  once again enumerate all the runs as if nextRun() were being invoked for   *  the first time.   *   *  (Note:  Don't worry about what might happen if nextRun() is interleaved   *  with addFish() or addShark(); it won't happen.)   */  /**   *  restartRuns() resets the enumeration as described above, so that   *  nextRun() will enumerate all the runs from the beginning.   */  private void restartRuns() {    this.sizeOfRun = this.list.size;  }  /**   *  nextRun() returns the next run in the enumeration, as described above.   *  If the runs have been exhausted, it returns null.  The return value is   *  a TypeAndSize object, which is nothing more than a way to return two   *  integers at once.   *  @return the next run in the enumeration, represented by a TypeAndSize   *          object.   */  private String nextRun() {      String obj = null;      if(this.sizeOfRun > 0){          obj = this.list.nTh(this.sizeOfRun);          this.sizeOfRun--;      }      return obj;  }  /**   *  toOcean() converts a run-length encoding of an ocean into an Ocean   *  object.  You will need to implement the three-parameter addShark method   *  in the Ocean class for this method's use.   *  @return the Ocean represented by a run-length encoding.   */  public Ocean toOcean() {      Ocean sea = new Ocean(this.width, this.height, this.starveTime);      String stringObject = null;      String singleArray[] = new String[this.width*this.height];      int savedIndex = 0;      int runLength = 0;      int tokenNumber = 0;      /*Convert Doubly linked List of Strings to 1d array */      //Critter critterObject = critterFactory.convertString(obj);      while((stringObject = nextRun()) != null){        tokenNumber = 1;          runLength = Utility.regexChecker(\\d{1,}, stringObject, tokenNumber);          for(int index = savedIndex; index < (savedIndex + runLength); index++){            singleArray[index] = stringObject;        }        savedIndex += runLength;      }      AbstractFactory factoryObject =  FactoryProducer.getFactory();      /* Convert 1d array to 2d array Ocean using abstract factory pattern*/      for(int index =0; index < singleArray.length; index++){          factoryObject.toCritterObject(sea, index, singleArray[index], this.width);      }      this.restartRuns();      return sea;  }  /**   *  The following method is required for Part III.   */  /**   *  RunLengthEncoding() (with one parameter) is a constructor that creates   *  a run-length encoding of an input Ocean.  You will need to implement   *  the sharkFeeding method in the Ocean class for this constructor's use.   *  @param sea is the ocean to encode.   */  public RunLengthEncoding(Ocean sea) {      this.list = new DList2();      this.width = sea.getWidth();      this.height = sea.getHeight();      RunLengthEncoding.starveTime = sea.getStarvationTime();      int indexOf2DOcean =0;      int sizeOfTheOcean = sea.getWidth() * sea.getHeight();      int sameNeighborCount =1;      String runLengthEncodeObject = null;      while(indexOf2DOcean < sizeOfTheOcean){          if(isSameNeighbor(sea,indexOf2DOcean)){              sameNeighborCount++;          }else{              runLengthEncodeObject = sea.cellContents((indexOf2DOcean/sea.getWidth()), Utility.mod(indexOf2DOcean, sea.getWidth())).toRunLengthEncodeSegment(sameNeighborCount);              this.list.insertFront(runLengthEncodeObject);              this.sizeOfRun++;              sameNeighborCount = 1;          }          indexOf2DOcean++;      }      check();  }  /**   * This method checks the type of any two adjacent cells   * Critter class equals() method is overridden in Shark   * class to compare additional property hungerLevel of     * two adjacent sharks.   * @param sea is a 2d array of Ocean   * @param index of 2d Ocean   * @return boolean   */  private boolean isSameNeighbor(Ocean sea, int index){      Critter creature1 = sea.cellContents((index/sea.getWidth()), Utility.mod(index, sea.getWidth()));      Critter creature2 = sea.cellContents(((index+1)/sea.getWidth()), Utility.mod(index+1, sea.getWidth()));       if( creature1.equals(creature2) ){          return true;      }      return false;  }  /**   *  check() walks through the run-length encoding and prints an error message   *  if two consecutive runs have the same contents, or if the sum of all run   *  lengths does not equal the number of cells in the ocean.   */  public void check() {      DListNode2 node = this.list.sentinel.next;      int sumOfAllRunLengths = 0;      while(node != this.list.sentinel){          int nodetype = Utility.regexChecker(\\D{1,}, node.runObject, 1);          int nodeNextType = Utility.regexChecker(\\D{1,}, node.next.runObject, 1);          if(nodetype == nodeNextType){              System.out.println(Error message - Two consecutive runs have the same contents\n);              return;          }else{              node = node.next;          }      }      node = this.list.sentinel.next;      while(node != this.list.sentinel){          sumOfAllRunLengths += Utility.regexChecker(\\d{1,}, node.runObject, 1);           node = node.next;      }      if(sumOfAllRunLengths != this.width*this.height){          System.out.println(Error Message);      }  }}Utility:/* Utility.java */package Project1;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * The Utility class provides some utility functions which are used * by multiple classes like Fish, Shark etc... * @author mohet01 * */final class Utility {/**     * This method checks for the match of particular pattern frmo the      * given string     * @param theRegex     * @param str2Check     */    public static int regexChecker(String theRegex, String str2Check, int tokenNumber){        Pattern checkRegex = Pattern.compile(theRegex);        Matcher regexMatcher = checkRegex.matcher(str2Check);        int count = 1;        int result = 0;        while(regexMatcher.find()){            if(regexMatcher.group().length() != 0){                result = Integer.parseInt(regexMatcher.group().trim());                if(count == tokenNumber){                    break;                }            }            count++;        }        return result;    }}AbstractFactory:/* AbstractFactory.java */package Project1;abstract class AbstractFactory {   abstract void toCritterObject(Ocean sea, int index, String str, int width);}class CritterFactory extends AbstractFactory{    void toCritterObject(Ocean sea, int index, String str, int width){        if(str.startsWith(S)){            int hungerLevel = 0;            int tokenNumber = 2;            hungerLevel = Utility.regexChecker(\\d{1,}, str, tokenNumber);            sea.addShark(index/width, Utility.mod(index, width), hungerLevel);        }else if(str.startsWith(F)){            sea.addFish(index/width, Utility.mod(index, width));        }    }}class FactoryProducer{    static AbstractFactory getFactory(){          return new CritterFactory();       }}Critter:/* Critter.java */package Project1;/** * The abstract class Critter defines a base class for any creature  * that can exist at a specific location in the ocean. * @author mohet01 * */abstract class Critter  {    /**     * Below data member defines a location of a Critter in an Ocean     */    Point location;    public Critter(int x, int y){        location = new Point(x,y);    }    public Point getLocation(){        return location;    }    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (this.getClass() != obj.getClass())            return false;        return true;    }    public abstract String toRunLengthEncodeSegment(int sameNeighborCount);    /**     * This method computes the behavior of the Critter in the Ocean.      * Computes new value of location property of Critter.     * No operation is performed as this is a base class.     */    public abstract Critter update(Ocean currentTimeStepSea);}Ocean/* Ocean.java */package Project1;/** * The Ocean class defines an object that models an ocean full of sharks and * fish. * @author mohet01 * */class Ocean {    /**     * Define any variables associated with an Ocean object here. These     * variables MUST be private.     *      */    //width of an Ocean    private final int width;    //height of an Ocean    private final int height;    /**     * Below data member is the number of simulation time steps that a Shark     *  can live through without eating.     */    private int starveTime;    /**     *  Do not rename these constants.  WARNING:  if you change the numbers, you     *  will need to recompile Test4.java.  Failure to do so will give you a very     *  hard-to-find bug.     */    /*public final static int EMPTY = 0;    public final static int SHARK = 1;    public final static int FISH = 2;*/    /*     * This method provides the starvation time in the Ocean for sharks     */    public int getStarvationTime(){        return starveTime;    }    /*     * This method provides the starvation time in the Ocean for sharks     */    public void setStarvationTime(int starveTime){        this.starveTime = starveTime;     }    /*     * I preferred, 2d array of references to Critter objects     * rather than List. Reasons(correct me),     * 1) To display an array of ocean, it adds more logic in paint() method.     * 2) Checking 8 nearest neighbors of each Critter looks inefficient,     * For example: for an ocean of SEEFE       *                              FEEFE a 2x2 ocean, If i maintain     * a list of Critter for this 2x2 ocean, i need to traverse      * S->E->E->F->E->F to get my first nearest neighbor of Shark,     * In contrast, With 2d array, I would just use modulo operation as     * mentioned in update() method.  Let us see what happens!!!     *       */    private Critter[][] oceanMatrix;    /**     * Constructor that creates an empty ocean with below dimension     *       * @param width     *            is the width of the ocean.     * @param height     *            is the height of the ocean.     *      */    public Ocean(int width, int height, int starveTime){        this.oceanMatrix = new Critter[height][width];        this.width = width;        this.height = height;        this.starveTime = starveTime;        for (int row = 0; row < height; row++) {            for (int col = 0; col < width; col++) {                oceanMatrix[row][col] = new Empty(row,col);            }        }    }    /**     * This method adds Critter in an ocean.     * @param object     *              is the Critter object to be added in Ocean.     */    public void addCritter(Critter object){        Point p = object.getLocation();        int x = p.getX();        int y = p.getY();        /*         * I understand that, location property make sense to be be moved          * to corresponding Critter<type> class as it's property, which i did, But          * also captured location property of a Critter Object in Ocean class(with         * above 3 lines of code) which is redundant and not relevant, But 2d array         * is more efficient than list, for checking neighbor in update() method.         * Are we Breaking SRS????         * So, Instead of List am using 2d array. Let us see what happens!!!         */        oceanMatrix[x][y] = object;    }    /**     * This method returns either Critter Object reference     *      * @param x     *            is the x-coordinate of the cell whose contents are queried.     * @param y     *            is the y-coordinate of the cell whose contents are queried.     */    public Critter cellContents(int x, int y) {        return oceanMatrix[x][y];    }    /**     * getWidth() returns the width of an ocean Object.     *      * @return      *          the width of the ocean.     *      */    public int getWidth() {        return this.width;    }    /**     * getHeight() returns the height of an Ocean object.     *      * @return     *          the height of the Ocean.     */    public int getHeight() {        return this.height;    }    /**     * timeStep() performs a simulation time step as described in README.     *      * @return     *          an ocean representing the elapse of one time Step.     */    public Ocean timeStep() {        Ocean nextTimeStepSea = new Ocean(width, height, starveTime);        for (int row = 0; row < this.height; row++) {            for (int col = 0; col < this.width; col++) {                Critter creature = this.cellContents(row, col);                nextTimeStepSea.addCritter(creature.update(this));            }        }        return nextTimeStepSea;    }    /**     *  The following method is required for Part II.     */    /**     *  addShark() (with three parameters) places a shark in cell (x, y) if the     *  cell is empty.  The shark's hunger is represented by the third parameter.     *  If the cell is already occupied, leave the cell as it is.  You will need     *  this method to help convert run-length encodings to Oceans.     *  @param x is the x-coordinate of the cell to place a shark in.     *  @param y is the y-coordinate of the cell to place a shark in.     *  @param feeding is an integer that indicates the shark's hunger.  You may     *         encode it any way you want; for instance, feeding may be the     *         last timestep the shark was fed, or the amount of time that has     *         passed since the shark was last fed, or the amount of time left     *         before the shark will starve.  It's up to you, but be consistent.     */    public void addShark(int x, int y, int feeding) {      if (this.cellContents(x, y).getClass().getName().equals(Empty)){          this.addCritter(new Shark(x, y, feeding));      }    }    /**     *  addFish() places a fish in cell (x, y) if the cell is empty.  If the     *  cell is already occupied, leave the cell as it is.     *  @param x is the x-coordinate of the cell to place a fish in.     *  @param y is the y-coordinate of the cell to place a fish in.     */    public void addFish(int x, int y) {        if (this.cellContents(x, y).getClass().getName().equals(Empty)){          this.addCritter(new Fish(x, y));        }    }}The complete code is available on this link.TypeAndSize class is completely ignored as a whole.My questions:Does OOP paradigm introducing Utility class?Please provide Comments on Abstract factory approach for issues (if any)Is this design accommodating more types of creatures in smoother way?
Converting Ocean to RunLengthEncoding object
java;object oriented;compression