Advertisement
Guest User

Untitled

a guest
Mar 22nd, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.86 KB | None | 0 0
  1. package assignment4;
  2. /* CRITTERS Critter.java
  3. * EE422C Project 4 submission by
  4. * Hasan Saleemi
  5. * has2375
  6. * Fall 2018
  7. */
  8.  
  9. import java.lang.reflect.InvocationTargetException;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12.  
  13. /**
  14. * Critter class that contains all the critters and the critter world, along with critter interactions
  15. */
  16. public abstract class Critter {
  17. private static String myPackage;
  18. private static List<Critter> population = new java.util.ArrayList<Critter>();
  19. private static List<Critter> babies = new java.util.ArrayList<Critter>();
  20.  
  21. private static ArrayList<ArrayList<ArrayList<Critter>>> grid;
  22. private boolean hasMoved = false;
  23.  
  24. // Gets the package name. This assumes that Critter and its subclasses are all in the same package.
  25. static {
  26. myPackage = Critter.class.getPackage().toString().split(" ")[1];
  27. }
  28.  
  29. private static java.util.Random rand = new java.util.Random();
  30. public static int getRandomInt(int max) {
  31. return rand.nextInt(max);
  32. }
  33.  
  34. /**
  35. *sets the seed for the randomizing
  36. */
  37. public static void setSeed(long new_seed) {
  38. rand = new java.util.Random(new_seed);
  39. }
  40.  
  41. /* a one-character long string that visually depicts your critter in the ASCII interface */
  42. public String toString() { return ""; }
  43.  
  44. private int energy = 0;
  45. protected int getEnergy() { return energy; }
  46.  
  47. private int x_coord;
  48. private int y_coord;
  49.  
  50. /**
  51. * makes it easier to move in the grid, given a random direction N, NE, E, SE, S, SW, W, NW
  52. * @param direction is an integer from 0-7 that determines direction
  53. */
  54. private void moveCrit(int direction){
  55. switch (direction) {
  56. case 0:
  57. x_coord++;
  58. break;
  59. case 1:
  60. x_coord++;
  61. y_coord--;
  62. break;
  63. case 2:
  64. y_coord--;
  65. break;
  66. case 3:
  67. x_coord--;
  68. y_coord--;
  69. break;
  70. case 4:
  71. x_coord--;
  72. break;
  73. case 5:
  74. x_coord--;
  75. y_coord++;
  76. break;
  77. case 6:
  78. y_coord++;
  79. break;
  80. case 7:
  81. x_coord++;
  82. y_coord++;
  83. break;
  84. default:
  85. break;
  86. }
  87. x_coord = x_coord - Math.floorDiv(x_coord, Params.world_width)*Params.world_width;
  88. y_coord = y_coord - Math.floorDiv(y_coord, Params.world_height)*Params.world_height;
  89. }
  90.  
  91. /**
  92. * method that moves critter in a direction and calculating the relevant energy costs, by removing and adding to the grid
  93. * @param direction refers to what you pass into the moveCrit routine like above
  94. */
  95. protected final void walk(int direction) {
  96. if(hasMoved){
  97. energy-=Params.walk_energy_cost;
  98. return;
  99. }
  100. hasMoved = true;
  101. grid.get(x_coord).get(y_coord).remove(this);
  102.  
  103. energy-=Params.walk_energy_cost;
  104. moveCrit(direction);
  105.  
  106. grid.get(x_coord).get(y_coord).add(this);
  107. }
  108.  
  109. /**
  110. * same method as above but with different energy costs, and different placements, moves 2 tiles instead of 1
  111. * @param direction
  112. */
  113. protected final void run(int direction) {
  114. if(hasMoved){
  115. energy-=Params.run_energy_cost;
  116. return;
  117. }
  118. hasMoved = true;
  119. grid.get(x_coord).get(y_coord).remove(this);
  120.  
  121. energy-=Params.run_energy_cost;
  122. moveCrit(direction);
  123. moveCrit(direction);
  124.  
  125. grid.get(x_coord).get(y_coord).add(this);
  126. }
  127.  
  128. private final int[][] dirTrans = {
  129. {3, 4, 5},
  130. {2, 8, 6},
  131. {1, 0, 7}
  132. };
  133.  
  134. /**
  135. * causes the critter to flee if it does not want to fight, checks whether the square is occupied, and moves to a random unoccupied square and subtracting relevent costs
  136. */
  137. private void flee(){
  138. if(this instanceof TestCritter)
  139. return;
  140. if(hasMoved){
  141. energy-=Params.walk_energy_cost;
  142. return;
  143. }
  144. ArrayList<Integer> spots = new ArrayList<>();
  145.  
  146. for(int dx = -1; dx < 2; dx++){
  147. for(int dy = -1; dy < 2; dy++){
  148. if(grid.get( (x_coord + dx) - Math.floorDiv(x_coord + dx, Params.world_width)*Params.world_width ).get( (y_coord + dy) - Math.floorDiv(y_coord + dy, Params.world_height)*Params.world_height ).size() == 0)
  149. spots.add(dirTrans[dx + 1][dy + 1]);
  150. }
  151. }
  152.  
  153. if(spots.size() > 0)
  154. walk( spots.get(getRandomInt(spots.size())) );
  155. else
  156. energy-=Params.walk_energy_cost;
  157. }
  158.  
  159. /**
  160. *method that causes critters to reproduce another critter in the next time step, using a certain amount of energy and placing the child in a random adjacent tile
  161. * @param offspring the critter to be created and placed in the world the next timestep with all the properties of a critter
  162. * @param direction random direction the child is placed from the parent
  163. */
  164. protected final void reproduce(Critter offspring, int direction) {
  165. if(energy < Params.min_reproduce_energy)
  166. return;
  167.  
  168. offspring.energy = energy/2;
  169. offspring.x_coord = x_coord;
  170. offspring.y_coord = y_coord;
  171. offspring.moveCrit(direction);
  172.  
  173. energy-=offspring.energy;
  174.  
  175. babies.add(offspring);
  176. }
  177.  
  178. public abstract void doTimeStep();
  179. public abstract boolean fight(String opponent);
  180.  
  181. /**
  182. * create and initialize a Critter subclass.
  183. * critter_class_name must be the unqualified name of a concrete subclass of Critter, if not,
  184. * an InvalidCritterException must be thrown.
  185. * (Java weirdness: Exception throwing does not work properly if the parameter has lower-case instead of
  186. * upper. For example, if craig is supplied instead of Craig, an error is thrown instead of
  187. * an Exception.)
  188. * @param critter_class_name is the critter subclass that needs to be created and initialized, creates that kind of critter and places it in the world
  189. * @throws InvalidCritterException if the critter you want to make is undefined then this is thrown
  190. */
  191. public static void makeCritter(String critter_class_name) throws InvalidCritterException {
  192. try {
  193. Critter newCritter = (Critter)Class.forName(myPackage + "." + critter_class_name).getDeclaredConstructor().newInstance();
  194. newCritter.x_coord = Critter.getRandomInt(Params.world_width);
  195. newCritter.y_coord = Critter.getRandomInt(Params.world_height);
  196. newCritter.energy = Params.start_energy;
  197.  
  198. population.add(newCritter);
  199. grid.get(newCritter.x_coord).get(newCritter.y_coord).add(newCritter);
  200. }catch (ClassCastException | NoSuchMethodException | InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException e){
  201. throw new InvalidCritterException(critter_class_name);
  202. }
  203. }
  204.  
  205. /**
  206. * Gets a list of all of the critters of a specific type.
  207. * @param critter_class_name What kind of Critter is to be listed. Unqualified class name.
  208. * @return List of Critters.
  209. * @throws InvalidCritterException if the type of critter you want to return does not exist under Critter
  210. */
  211. public static List<Critter> getInstances(String critter_class_name) throws InvalidCritterException {
  212. List<Critter> result = new java.util.ArrayList<Critter>();
  213.  
  214. try{
  215. Class.forName(myPackage + "." + critter_class_name);
  216. }catch (ClassNotFoundException e){
  217. throw new InvalidCritterException(critter_class_name);
  218. }
  219.  
  220. for(Critter c: population){
  221. if(c.getClass().getName().equals(myPackage + "." + critter_class_name))
  222. result.add(c);
  223. }
  224.  
  225. return result;
  226. }
  227.  
  228. /**
  229. * Prints out how many Critters of each type there are on the board. Also prints out some properties of whatever Critter class it is. Takes
  230. * all the different critters and prints out stats for each unique kind
  231. * @param critters List of all the critters in the word
  232. */
  233. public static void runStats(List<Critter> critters) {
  234. System.out.print("" + critters.size() + " critters as follows -- ");
  235. java.util.Map<String, Integer> critter_count = new java.util.HashMap<String, Integer>();
  236. for (Critter crit : critters) {
  237. String crit_string = crit.toString();
  238. Integer old_count = critter_count.get(crit_string);
  239. if (old_count == null) {
  240. critter_count.put(crit_string, 1);
  241. } else {
  242. critter_count.put(crit_string, old_count.intValue() + 1);
  243. }
  244. }
  245. String prefix = "";
  246. for (String s : critter_count.keySet()) {
  247. System.out.print(prefix + s + ":" + critter_count.get(s));
  248. prefix = ", ";
  249. }
  250. System.out.println();
  251. }
  252.  
  253. /* the TestCritter class allows some critters to "cheat". If you want to
  254. * create tests of your Critter model, you can create subclasses of this class
  255. * and then use the setter functions contained here.
  256. *
  257. * NOTE: you must make sure that the setter functions work with your implementation
  258. * of Critter. That means, if you're recording the positions of your critters
  259. * using some sort of external grid or some other data structure in addition
  260. * to the x_coord and y_coord functions, then you MUST update these setter functions
  261. * so that they correctly update your grid/data structure.
  262. */
  263.  
  264. static abstract class TestCritter extends Critter {
  265. protected void setEnergy(int new_energy_value) {
  266. super.energy = new_energy_value;
  267. }
  268.  
  269. protected void setX_coord(int new_x_coord) {
  270. grid.get(super.x_coord).get(super.y_coord).remove(this);
  271. super.x_coord = new_x_coord;
  272. grid.get(super.x_coord).get(super.y_coord).add(this);
  273. }
  274.  
  275. protected void setY_coord(int new_y_coord) {
  276. grid.get(super.x_coord).get(super.y_coord).remove(this);
  277. super.y_coord = new_y_coord;
  278. grid.get(super.x_coord).get(super.y_coord).add(this);
  279. }
  280.  
  281. protected int getX_coord() {
  282. return super.x_coord;
  283. }
  284.  
  285. protected int getY_coord() {
  286. return super.y_coord;
  287. }
  288.  
  289.  
  290. /*
  291. * This method getPopulation has to be modified by you if you are not using the population
  292. * ArrayList that has been provided in the starter code. In any case, it has to be
  293. * implemented for grading tests to work.
  294. */
  295. protected static List<Critter> getPopulation() {
  296. return population;
  297. }
  298.  
  299. /*
  300. * This method getBabies has to be modified by you if you are not using the babies
  301. * ArrayList that has been provided in the starter code. In any case, it has to be
  302. * implemented for grading tests to work. Babies should be added to the general population
  303. * at either the beginning OR the end of every timestep.
  304. */
  305. protected static List<Critter> getBabies() {
  306. return babies;
  307. }
  308. }
  309.  
  310. /**
  311. * Clear the world of all critters, dead and alive
  312. * empties out the list and populations for the critters and babies
  313. */
  314. public static void clearWorld() {
  315. grid = new ArrayList<ArrayList<ArrayList<Critter>>>();
  316. for(int x = 0; x < Params.world_width; x++){
  317. grid.add(x, new ArrayList<>());
  318. for(int y = 0; y < Params.world_height; y++){
  319. grid.get(x).add(y, new ArrayList<>());
  320. }
  321. }
  322.  
  323. population.clear();
  324. babies.clear();
  325. }
  326.  
  327. /**
  328. * removes all the critters in the population with energy less than 0
  329. */
  330. private static void removeDeadCritters(){
  331. List<Critter> newPop = new ArrayList<>();
  332. for(Critter c: population) {
  333. if(c.energy > 0){
  334. newPop.add(c);
  335. } else {
  336. grid.get(c.x_coord).get(c.y_coord).remove(c);
  337. }
  338. }
  339. population = newPop;
  340. }
  341.  
  342. /**
  343. *Progresses the world one time step, first adding the babies to the population and placing them
  344. * then attemping to resolve each individual critter's situation whether its fight walk run flee or reproduce
  345. * has implementation of fight and fleeing
  346. * then subtracts rest energy after that and finally removes dead critters
  347. * at the end of the time step, algae is always added
  348. */
  349. public static void worldTimeStep() {
  350. // add babies
  351. for(Critter c: babies){
  352. population.add(c);
  353. grid.get(c.x_coord).get(c.y_coord).add(c);
  354. }
  355. babies.clear();
  356.  
  357. // do time step
  358. ArrayList<ArrayList<Integer>> coords = new ArrayList<>();
  359.  
  360. for(Critter c: population) {
  361. c.hasMoved = false;
  362. c.doTimeStep();
  363.  
  364. ArrayList<Integer> saveCoords = new ArrayList<>();
  365. saveCoords.add(c.x_coord);
  366. saveCoords.add(c.y_coord);
  367. coords.add(saveCoords);
  368. }
  369.  
  370. // handle encounters
  371. for(ArrayList<Integer> gridSpot: coords){
  372. ArrayList<Critter> spot = grid.get(gridSpot.get(0)).get(gridSpot.get(1));
  373. while(spot.size() > 1){
  374. Critter A = spot.get(0);
  375. Critter B = spot.get(1);
  376.  
  377. boolean AFight = A.fight(B.toString());
  378. boolean BFight = B.fight(A.toString());
  379.  
  380. if(!AFight)
  381. A.flee();
  382. if(!BFight)
  383. B.flee();
  384.  
  385. if(A.x_coord == B.x_coord && A.y_coord == B.y_coord && (A.energy > 0 && B.energy > 0)){
  386. int ARand = AFight ? Critter.getRandomInt(A.energy) : 0;
  387. int BRand = BFight ? Critter.getRandomInt(B.energy) : 0;
  388.  
  389. if(ARand > BRand){
  390. A.energy+=B.energy/2;
  391. B.energy = 0;
  392. } else {
  393. B.energy+=A.energy/2;
  394. A.energy = 0;
  395. }
  396. }
  397.  
  398. removeDeadCritters();
  399. }
  400. }
  401.  
  402. for(Critter c: population) {
  403. c.energy-=Params.rest_energy_cost;
  404. }
  405.  
  406. // remove ded
  407. removeDeadCritters();
  408.  
  409. // create new algae
  410. for(int i = 0; i < Params.refresh_algae_count; i++) {
  411. try {
  412. makeCritter("Algae");
  413. } catch (InvalidCritterException ignored) { }
  414. }
  415. }
  416.  
  417. /**
  418. * prints special characters for top/bottom
  419. */
  420. private static void printTopBottom(){
  421. System.out.print("+");
  422. for(int i = 0; i < Params.world_width; i++)
  423. System.out.print("-");
  424. System.out.print("+");
  425. }
  426.  
  427. /**
  428. *the MVC world for the user to interact with, can see all the critters and the grid, creates
  429. * world based on dimensions and makes borders
  430. */
  431. public static void displayWorld() {
  432. for(int y = 0; y < Params.world_height; y++){
  433. if(y == 0){
  434. printTopBottom();
  435. System.out.println();
  436. }
  437.  
  438. for(int x = 0; x < Params.world_width; x++){
  439. if(x == 0)
  440. System.out.print("|");
  441.  
  442. if(grid.get(x).get(y).size() == 0){
  443. System.out.print(" ");
  444. } else if(grid.get(x).get(y).size() > 0){
  445. System.out.print(grid.get(x).get(y).get(0));
  446. } /*else {
  447. System.out.print("*");
  448. }*/
  449.  
  450. if(x == Params.world_width - 1)
  451. System.out.print("|");
  452. }
  453.  
  454. if(y == Params.world_height - 1){
  455. System.out.println();
  456. printTopBottom();
  457. }
  458. System.out.println();
  459. }
  460. }
  461. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement