From f2d9d5271174cf07988f73ec15c30b424bd656af Mon Sep 17 00:00:00 2001 From: davpapp Date: Mon, 19 Feb 2018 16:12:25 -0500 Subject: [PATCH] Tested Dropping, improved randomization and SMART drop --- src/Cursor.java | 112 +++++++++++++----------- src/CursorPath.java | 4 +- src/CursorTask.java | 23 ++--- src/CursorTest.java | 5 +- src/Inventory.java | 4 +- src/InventoryItemsTest.java | 4 +- src/InventoryTest.java | 2 +- src/Randomizer.java | 4 +- src/WillowChopper.java | 7 +- src/main.java | 5 +- target/classes/Cursor.class | Bin 7799 -> 8326 bytes target/classes/CursorPath.class | Bin 5684 -> 5684 bytes target/classes/CursorTask.class | Bin 2279 -> 2789 bytes target/classes/CursorTest.class | Bin 3701 -> 3415 bytes target/classes/Inventory.class | Bin 3124 -> 3109 bytes target/classes/InventoryItemsTest.class | Bin 2547 -> 2539 bytes target/classes/InventoryTest.class | Bin 3889 -> 3885 bytes target/classes/Randomizer.class | Bin 1669 -> 2154 bytes target/classes/WillowChopper.class | Bin 872 -> 1113 bytes target/classes/main.class | Bin 463 -> 500 bytes 20 files changed, 95 insertions(+), 75 deletions(-) diff --git a/src/Cursor.java b/src/Cursor.java index 7f735f7..45d0f33 100644 --- a/src/Cursor.java +++ b/src/Cursor.java @@ -73,18 +73,23 @@ public class Cursor { return randomizer.nextGaussianWithinRange(MINIMUM_CLICK_LENGTH, MAXIMUM_CLICK_LENGTH); } + private int getRandomClickReleaseLength() { + return randomizer.nextGaussianWithinRange(MINIMUM_CLICK_LENGTH + 5, MAXIMUM_CLICK_LENGTH + 10); + } + + public void leftClickCursor() throws InterruptedException { robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); Thread.sleep(getRandomClickLength()); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - Thread.sleep(getRandomClickLength()); + Thread.sleep(getRandomClickReleaseLength()); } public void rightClickCursor() throws InterruptedException { robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); - Thread.sleep(20 + getRandomClickLength()); + Thread.sleep(getRandomClickLength() + 20); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); - Thread.sleep(getRandomClickLength()); + Thread.sleep(getRandomClickReleaseLength()); } public void moveAndLeftClickAtCoordinates(Point goalPoint) throws Exception { @@ -99,15 +104,25 @@ public class Cursor { public Point moveAndLeftClickAtCoordinatesWithRandomness(Point goalPoint, int xTolerance, int yTolerance) throws Exception { Point randomizedGoalPoint = randomizePoint(goalPoint, xTolerance, yTolerance); - moveCursorToCoordinates(randomizedGoalPoint); - leftClickCursor(); + moveAndLeftClickAtCoordinates(randomizedGoalPoint); + return randomizedGoalPoint; // Return the point we moved to in case we need precise movement afterwards + } + + public Point moveAndLeftClickAtCoordinatesWithRandomness(Point goalPoint, int xToleranceLeft, int xToleranceRight, int yTolerance) throws Exception { + Point randomizedGoalPoint = randomizePoint(goalPoint, xToleranceLeft, xToleranceRight, yTolerance); + moveAndLeftClickAtCoordinates(randomizedGoalPoint); return randomizedGoalPoint; // Return the point we moved to in case we need precise movement afterwards } public Point moveAndRightlickAtCoordinatesWithRandomness(Point goalPoint, int xTolerance, int yTolerance) throws Exception { Point randomizedGoalPoint = randomizePoint(goalPoint, xTolerance, yTolerance); - moveCursorToCoordinates(randomizedGoalPoint); - rightClickCursor(); + moveAndRightClickAtCoordinates(randomizedGoalPoint); + return randomizedGoalPoint; // Return the point we moved to in case we need precise movement afterwards + } + + public Point moveAndRightlickAtCoordinatesWithRandomness(Point goalPoint, int xToleranceLeft, int xToleranceRight, int yTolerance) throws Exception { + Point randomizedGoalPoint = randomizePoint(goalPoint, xToleranceLeft, xToleranceRight, yTolerance); + moveAndRightClickAtCoordinates(randomizedGoalPoint); return randomizedGoalPoint; // Return the point we moved to in case we need precise movement afterwards } @@ -115,15 +130,14 @@ public class Cursor { Point startingPoint = getCurrentCursorPoint(); int distanceToMoveCursor = getDistanceBetweenPoints(startingPoint, goalPoint); double angleToRotateCursorPathTo = getThetaBetweenPoints(startingPoint, goalPoint); - System.out.println("R:" + distanceToMoveCursor + ", theta:" + angleToRotateCursorPathTo); + if (distanceToMoveCursor == 0) { return; } CursorPath cursorPathWithDistanceSet = chooseCursorPathToFollowBasedOnDistance(distanceToMoveCursor); CursorPath cursorPathWithDistanceAndAngleSet = cursorPathWithDistanceSet.getRotatedCopyOfCursorPath(angleToRotateCursorPathTo); - System.out.println("Rotated the points: "); - //cursorPathWithDistanceAndAngleSet.displayCursorPoints(); + followCursorPath(cursorPathWithDistanceAndAngleSet, startingPoint); } @@ -149,50 +163,45 @@ public class Cursor { private CursorPath chooseCursorPathToFollowBasedOnDistance(int distanceToMoveCursor) throws Exception { int newDistanceToMoveCursor = findNearestPathLengthThatExists(distanceToMoveCursor); - double scaleToFactorBy = getScaleToFactorBy(newDistanceToMoveCursor, distanceToMoveCursor); - System.out.println("new distance to follow cursor is: " + newDistanceToMoveCursor + " from scaling by " + scaleToFactorBy); ArrayList cursorPathsWithSameDistance = cursorPathsByDistance.get(newDistanceToMoveCursor); + + CursorPath randomlyChosenCursorPath = cursorPathsWithSameDistance.get(random.nextInt(cursorPathsWithSameDistance.size())); + if (newDistanceToMoveCursor == distanceToMoveCursor) { + return randomlyChosenCursorPath; + } - CursorPath scaledCursorPath = cursorPathsWithSameDistance.get(random.nextInt(cursorPathsWithSameDistance.size())).getScaledCopyOfCursorPath(scaleToFactorBy); - - return scaledCursorPath; - //return cursorPathsByDistance.get(newDistanceToMoveCursor).get(indexOfRandomPathToFollow);//scaledCursorPath; + double scaleToFactorBy = getScaleToFactorBy(newDistanceToMoveCursor, distanceToMoveCursor); + return randomlyChosenCursorPath.getScaledCopyOfCursorPath(scaleToFactorBy); } public int findNearestPathLengthThatExists(int distanceToMoveCursor) throws Exception { - int offset = 0; - boolean reachedMinimumLimit = false; - boolean reachedMaximumLimit = false; - while (cursorPathsByDistance.get(distanceToMoveCursor + offset).size() == 0) { - // Go up - if (distanceToMoveCursor + Math.abs(offset) + 1 >= NUMBER_OF_DISTANCES) { - reachedMaximumLimit = true; - } - if (distanceToMoveCursor - Math.abs(offset) - 1 < 0) { - reachedMinimumLimit = true; - } - if (reachedMaximumLimit && reachedMinimumLimit) { - throw new Exception("No paths exist."); - } - - if (offset < 0) { - if (!reachedMaximumLimit) { - offset = -offset + 1; - } - else { - offset--; - } - } - else { - if (!reachedMinimumLimit) { - offset = -offset - 1; - } - else { - offset++; - } + int closestShorterPathLength = Integer.MIN_VALUE; + int closestLongerPathLength = Integer.MAX_VALUE; + for (int i = distanceToMoveCursor; i >= 0; i--) { + if (cursorPathsByDistance.get(i).size() > 0) { + closestShorterPathLength = i; + break; } } - return distanceToMoveCursor + offset; + for (int i = distanceToMoveCursor; i < 2203; i++) { + if (cursorPathsByDistance.get(i).size() > 0) { + closestLongerPathLength = i; + break; + } + } + + if (closestShorterPathLength == Integer.MIN_VALUE && closestLongerPathLength == Integer.MAX_VALUE) { + throw new Exception("No paths of any size exist."); + } + else if (closestShorterPathLength == Integer.MIN_VALUE) { + return closestLongerPathLength; + } + else if (closestLongerPathLength == Integer.MAX_VALUE) { + return closestShorterPathLength; + } + else { + return (Math.abs(distanceToMoveCursor - closestShorterPathLength) <= Math.abs(distanceToMoveCursor - closestLongerPathLength)) ? closestShorterPathLength : closestLongerPathLength; + } } private double getScaleToFactorBy(int newDistanceToMoveCursor, int distanceToMoveCursor) { @@ -209,14 +218,15 @@ public class Cursor { return new Point(goalPoint.x + randomizer.nextGaussianWithinRange(-xTolerance, xTolerance), goalPoint.y + randomizer.nextGaussianWithinRange(-yTolerance, yTolerance)); } + private Point randomizePoint(Point goalPoint, int xToleranceLeft, int xToleranceRight, int yTolerance) { + Randomizer randomizer = new Randomizer(); + return new Point(goalPoint.x + randomizer.nextGaussianWithinRange(-xToleranceLeft, xToleranceRight), goalPoint.y + randomizer.nextGaussianWithinRange(-yTolerance, yTolerance)); + } + public void displayCursorPaths() { for (int i = 0; i < NUMBER_OF_DISTANCES; i++) { System.out.println("There are " + cursorPathsByDistance.get(i).size() + " paths of size " + i); } System.out.println("--------------"); - /*for (int i = 0; i < cursorPathsByDistance.get(1).size(); i++) { - cursorPathsByDistance.get(1).get(i).displayCursorPoints(); - }*/ - //cursorPathsByDistance.get(0).get(0).displayCursorPoints(); } } \ No newline at end of file diff --git a/src/CursorPath.java b/src/CursorPath.java index 30bb08f..9242347 100644 --- a/src/CursorPath.java +++ b/src/CursorPath.java @@ -101,7 +101,7 @@ public class CursorPath { } private boolean isCursorPathTimespanReasonable() { - return (this.timespan > 50 && this.timespan < 400); + return (this.timespan > 50 && this.timespan < 300); } private boolean isCursorPathDistanceReasonable() { @@ -109,7 +109,7 @@ public class CursorPath { } private boolean isCursorPathNumPointsReasonable() { - return (this.cursorPoints.size() > 0 && this.cursorPoints.size() < 80); + return (this.cursorPoints.size() > 0 && this.cursorPoints.size() < 40); } public ArrayList getCursorPathPoints() { diff --git a/src/CursorTask.java b/src/CursorTask.java index efb586a..01dca78 100644 --- a/src/CursorTask.java +++ b/src/CursorTask.java @@ -8,13 +8,13 @@ public class CursorTask { // Human drop time: 29 seconds - // Measured: 30 seconds, 29 seconds - public void optimizedDropAllItemsInInventory(Cursor cursor, Inventory inventory) throws InterruptedException { + // Measured: 30 seconds, 29 seconds, 28 + public void optimizedDropAllItemsInInventory(Cursor cursor, Inventory inventory) throws Exception { for (int row = 0; row < 4; row++) { Point coordinatesToClick = dropItem(cursor, inventory, row, 0); for (int column = 1; column < 7; column++) { - if (distanceBetweenPoints(coordinatesToClick, inventory.getClickCoordinatesCoordinatesForInventorySlot(row, column)) > 12) { - coordinatesToClick = inventory.getClickCoordinatesCoordinatesForInventorySlot(row, column); + if (distanceBetweenPoints(coordinatesToClick, inventory.getClickCoordinatesForInventorySlot(row, column)) > 12) { + coordinatesToClick = inventory.getClickCoordinatesForInventorySlot(row, column); } rightClickItemSlot(cursor, coordinatesToClick); coordinatesToClick = leftClickDropOption(cursor, coordinatesToClick, column); @@ -26,7 +26,7 @@ public class CursorTask { return (int) (Math.hypot(a.x - b.x, a.y - b.y)); } - public void dropAllItemsInInventory(Cursor cursor, Inventory inventory) throws InterruptedException { + public void dropAllItemsInInventory(Cursor cursor, Inventory inventory) throws Exception { for (int row = 0; row < 4; row++) { for (int column = 0; column < 7; column++) { dropItem(cursor, inventory, row, column); @@ -35,22 +35,22 @@ public class CursorTask { } - public Point dropItem(Cursor cursor, Inventory inventory, int row, int column) throws InterruptedException { - Point coordinatesToRightClick = inventory.getClickCoordinatesCoordinatesForInventorySlot(row, column); + public Point dropItem(Cursor cursor, Inventory inventory, int row, int column) throws Exception { + Point coordinatesToRightClick = inventory.getClickCoordinatesForInventorySlot(row, column); Point clickedCoordinates = rightClickItemSlotWithRandomness(cursor, coordinatesToRightClick); return leftClickDropOption(cursor, clickedCoordinates, column); } - public void rightClickItemSlot(Cursor cursor, Point coordinatesToRightClick) throws InterruptedException { + public void rightClickItemSlot(Cursor cursor, Point coordinatesToRightClick) throws Exception { cursor.moveAndRightClickAtCoordinates(coordinatesToRightClick); } - public Point rightClickItemSlotWithRandomness(Cursor cursor, Point coordinatesToRightClick) throws InterruptedException { + public Point rightClickItemSlotWithRandomness(Cursor cursor, Point coordinatesToRightClick) throws Exception { Point clickedCoordinates = cursor.moveAndRightlickAtCoordinatesWithRandomness(coordinatesToRightClick, 6, 6); return clickedCoordinates; } - private Point leftClickDropOption(Cursor cursor, Point coordinatesToLeftClick, int column) throws InterruptedException { + private Point leftClickDropOption(Cursor cursor, Point coordinatesToLeftClick, int column) throws Exception { Point offsetCoordinatesToLeftClick = coordinatesToLeftClick; if (column < 6) { offsetCoordinatesToLeftClick.y += DROP_OFFSET; @@ -58,6 +58,7 @@ public class CursorTask { else { offsetCoordinatesToLeftClick.y = DROP_BOTTOM_ROW; } - return cursor.moveAndLeftClickAtCoordinatesWithRandomness(offsetCoordinatesToLeftClick, 10, 6); + System.out.println("foudn where to click..."); + return cursor.moveAndLeftClickAtCoordinatesWithRandomness(offsetCoordinatesToLeftClick, 13, 10, 6); } } diff --git a/src/CursorTest.java b/src/CursorTest.java index 36f293d..b40ac59 100644 --- a/src/CursorTest.java +++ b/src/CursorTest.java @@ -27,9 +27,12 @@ class CursorTest { } void testFindNearestPathLengthThatExists() throws Exception { + int closestLengthForPreviousValue = 0; for (int i = 0; i < 2203; i++) { int closestLength = cursor.findNearestPathLengthThatExists(i); - System.out.println("Closest path to length " + i + " is " + closestLength); + assertTrue(closestLength >= closestLengthForPreviousValue); + closestLengthForPreviousValue = closestLength; + //System.out.println("Closest path to length " + i + " is " + closestLength); } } diff --git a/src/Inventory.java b/src/Inventory.java index 1c79505..31a1256 100644 --- a/src/Inventory.java +++ b/src/Inventory.java @@ -47,7 +47,7 @@ public class Inventory { } private void initializeItems() throws IOException { - items = new InventoryItems("/home/dpapp/Desktop/RunescapeAIPics/Items/"); + items = new InventoryItems("/home/dpapp/Desktop/RunescapeAI/Items/"); } public void update() throws IOException { @@ -89,7 +89,7 @@ public class Inventory { return true; } - public Point getClickCoordinatesCoordinatesForInventorySlot(int row, int column) { + public Point getClickCoordinatesForInventorySlot(int row, int column) { Point centerOfInventorySlot = inventorySlots[row][column].getClickablePointWithinItemSlot(); int x = INVENTORY_OFFSET_WIDTH + row * INVENTORY_SLOT_WIDTH + centerOfInventorySlot.x; int y = INVENTORY_OFFSET_HEIGHT + column * INVENTORY_SLOT_HEIGHT + centerOfInventorySlot.y; diff --git a/src/InventoryItemsTest.java b/src/InventoryItemsTest.java index d562816..b4ff817 100644 --- a/src/InventoryItemsTest.java +++ b/src/InventoryItemsTest.java @@ -18,8 +18,8 @@ class InventoryItemsTest { public void initialize() throws IOException { System.out.println("running initialize..."); - items = new InventoryItems("/home/dpapp/Desktop/RunescapeAIPics/Items/"); - this.testingItemDirectoryPath = "/home/dpapp/Desktop/RunescapeAIPics/Tests/ItemNameRecognition/"; + items = new InventoryItems("/home/dpapp/Desktop/RunescapeAI/Items/"); + this.testingItemDirectoryPath = "/home/dpapp/Desktop/RunescapeAI/Tests/ItemNameRecognition/"; } @Test diff --git a/src/InventoryTest.java b/src/InventoryTest.java index c979efa..a0a4068 100644 --- a/src/InventoryTest.java +++ b/src/InventoryTest.java @@ -16,7 +16,7 @@ class InventoryTest { public void initialize() throws AWTException, IOException { inventory = new Inventory(); - this.testingInventoryDirectoryPath = "/home/dpapp/Desktop/RunescapeAIPics/Tests/Inventory/"; + this.testingInventoryDirectoryPath = "/home/dpapp/Desktop/RunescapeAI/Tests/Inventory/"; } @Test diff --git a/src/Randomizer.java b/src/Randomizer.java index 4d71aa7..1b5c768 100644 --- a/src/Randomizer.java +++ b/src/Randomizer.java @@ -11,10 +11,12 @@ public class Randomizer { } public int nextGaussianWithinRange(double rangeBegin, double rangeEnd) { - double rangeMean = (rangeEnd - rangeBegin) / 2.0; + double rangeMean = (rangeEnd + rangeBegin) / 2.0; double rangeSTD = (rangeEnd - rangeMean) / 3.0; double result = random.nextGaussian() * rangeSTD + rangeMean; while (result > rangeEnd || result < rangeBegin) { + System.out.println("Gaussian result out of range..."); + System.out.println(rangeMean + ", std: " + rangeSTD); result = random.nextGaussian() * rangeSTD + rangeMean; } return (int) result; diff --git a/src/WillowChopper.java b/src/WillowChopper.java index d1c2902..e887ea7 100644 --- a/src/WillowChopper.java +++ b/src/WillowChopper.java @@ -14,9 +14,10 @@ public class WillowChopper { inventory = new Inventory(); } - public void run() throws IOException, InterruptedException { + public void run() throws Exception { while (true) { + Thread.sleep(250); /* if (character.isCharacterEngaged()) { // DO NOTHING @@ -29,7 +30,9 @@ public class WillowChopper { */ inventory.update(); if (inventory.isInventoryFull()) { - cursorTask.dropAllItemsInInventory(cursor, inventory); + System.out.println("Inventory is full! Dropping..."); + cursorTask.optimizedDropAllItemsInInventory(cursor, inventory); + //cursorTask.dropAllItemsInInventory(cursor, inventory); } } } diff --git a/src/main.java b/src/main.java index 4978077..a1d43fc 100644 --- a/src/main.java +++ b/src/main.java @@ -6,8 +6,9 @@ import java.net.URL; public class main { - public static void main(String[] args) throws AWTException, InterruptedException, IOException { - + public static void main(String[] args) throws Exception { + WillowChopper willowChopper = new WillowChopper(); + willowChopper.run(); /*Cursor cursor = new Cursor(); CursorTask cursorTask = new CursorTask(); Inventory inventory = new Inventory(); diff --git a/target/classes/Cursor.class b/target/classes/Cursor.class index 6b557421c117c3f7d7da67fb3b9493f20ccca104..8f2edb554d85562747c8e79a43929ad0c2b59772 100644 GIT binary patch delta 3910 zcmb7Hc~n&A7609tHw(iP2bdAYnL*TuFn|bdNR+SzMS&VbjoEaRC!iCC&I|^6+D=Yl zLr+?h<9R2wHO6Yvge=C0(!nJfn`*T&i(Qh|w9Qh}rkhEcv`L$$()+zP3`Df2{e$s) z-*>;?z4v#w&rcTIQ)zqQ(vjl;=FqBsTc@Sk-Ks>I{2eX9+p7cZ>o+wi0mUCy>XnYx zNSnE0O$Cbr=8B-cAdC+v8zP!$byp}H3|X*K-D;T@-6i9@*iEqA9_$J$%R)*xOptQx z@>beFcv!|a(QCu^@R$XU66_oOoBc%re@AOkb6ZI9x5((j;{;PUpeUW<;u3MO1W(F% zO2En*Y}`75__T}%(91}n_SUvYwL0BeMF-T4)`{i;8Q;f#^<-y4PAOJu73M z`my!q$tPs|0LKX_ArJ^eHF-5c z`ZF2-)=vBpe@BT8T^N!HXeFd`=2WZg<5C+9gk(J%G_sP2@PYXG$cBq#mXSdg0m&4K zWS}IOY}hYi5L_3GG>Cj@2yRyR2FWswQ_qaM$($~egDh%pN{%^0rc83F%_;eXE66RA zM}%DpbLebXKv^#*;v`ErqnWoTGwKv7fY<1BznR1xCwDG0tE#tGInR@60 zJ=JZ&u+kAXoH^j2h1dH7N^`K*zdjNSRrMI}Nu7J$-0ag-@EN=^jB1&kPKT_SM7Z)KTepVms zXw{D5CpMZ(r52h;NJ~UkW2vrVLr|vqRHoYPGo~z{atkdaI1)k{`$|X`yN>f~t$peO z3stcyO-76M@<^z?qqVB5J#+0#bYfD0ARj4tzU?ZF_mgfJ*)~Yo`sU;#s1}oL~9nR>! zE9hAl*ORNE+K2Vn9cvS+#O75st!7O(!HJtO3AbQ6ZXM-eZo)(ELNH8DxY)0`Sj(yn zY^=?fAHzXk3^CO(VdkPkILw}t=qr3Y%*s`+93AmI1x5x_*#8YkLaTbrnGqevI)>w8 zuma4s;400R@9_@exiZP;l45w?CGF>3olPBcBjattcmy=xX6v`&zVUtNTEyxk$62_P zhEu#UM)_hAe#8!mz#hZtF-CMVn3*p)gb_|@5NFCvK9@asL&N0k*JZ_i#P-a)#fF zYvRWN|}^ZBo(mscP1>cf`aL-_lBm-nx2 z>O+|s4Z;EuSeIs%=ub1O(gfnXg$)wj5S$Qv6v^8-j%6)g} zlpdZ{m2A~S<_-7`GPoa?a2GDcPE_#s66_k4;Y$-SSxPC)wcufCJSG{)qw!>CN=uMJ zsW_~@$G%Ntvb?T_akMq-AfG2KOj)^cZ)y$B~04kdG%Z15aZv_KhmO@`Q=yB11(F zFr$>F^RI!g7EmsyzL5bkDUS)1__~#RoWLd?S^99)rJ7kvWG|1)OPE0xtg!G~jl|RG za)0SomKDu>dphMWOs9f!_gqenEcP^dqmwIAIL;pLLXuNj*oWjT(vVZyIdmZ*Hb$zv z4=GzDa!RSz2louU6KA-aoE^pd_5}0WwcfyQN~rZTOJm-O`)M|>jNC7$;x=AM++cFz zE5Wk|<1TUD5@i@Zh4dLr+QO1)wWd`N4B7*<&oiCQsjql4nngTC@>?}kq6zTxpMOPP zDdvC0ndK18iP5zqgG|5js%EqP3bMp)Hi-YksAXPv>BZHe9$bGf)#T+btbdX=2#*7~}-)jK@!fuh7HF49LaOXP4Z+1YEM>U7-FZM-kazW6BStscbu zGLvW`ngJ#@K-Z`lU~)>4UZ-?56W(B;H?gRSvGmD2ws{L)h9`4zVlWrS2Xhi~HT!rl zQ-ylg>%NUDImfC8>3UJT?nDm9s5YIJ#HgMNyEaB&h++B`BDa>NXAfXfIxXj|k-4M4 e2rqDXyu(fC0v2*-t;M@)O;&+r1)FQ2mHz<-Lk#5r delta 3425 zcmb7Gd301~7609tH%lgu%w!>x=}cf`OEO6bgryKjSQ26b1SkoRKy5Q*UXqa{FV4I` zV%71SqVb$+)$^<+6sxrhWl;*GlTcbfYps@AsY*CEoA7$s|XrNB@{N z-*&g({oVV0A76E4x$C)WPn-d;h?58`Ps_Bcx)tCeK>Q6alCx&F~ z$9)7>x7rt1HpP^9oFEm~muz)`@C6y4#Gngb!~+g|iQsvEcz3wGE8Npj-qaaW!Vwu? z#)AY~yh~Afh2UBtSb>LSJR;P}hT6?amlBREEFX(@bWV0d-{o9VbA*sPp?FPyo6@UA z)gIx%S7dw@hX~$ob+=-A-lW#3YAh1%32RDRoOw*fJ^E|TI_Ys42laUwJG`f4Jb@8H zRxI2TQM;obR5q#69!)=*QK2tz&9k4A@ily1kGtmEzairpd{aN{T4Vo~jBn#P{Vi9u z)q&^rH{Jexyg;yQu5{r%BI5I+jPK$5ddO4a#YKX%EU0xVTG%-7L$UX={sGVY3O;#B z%zjJ=6xWulp9ro|i$!}nR`*4_B1&wTQ2C0CpWl2<8_ueu-b{RhcX8zn1YD zUf1u;ET84XZwYyuRgGhg2%EuP5m3A`C}e&w;}3X4e=_q-;w=u^uom8KC)OW&FdK4Y=?Q#vHgdE@ULOA*^-Ee3m$^oddn9#{b2&wI#KDnyfNO#!grZ z_f)vhM|PPU=->=?C|ZqvRnFd!LC7>yWja7kT*=_i+b&$DDKfm2B~;d%93ziR*&@YR zF?FY^H3%9uaI#r~a%IZXo2P8I-yoBpvh>j@bL`V(nodFe)hVS;q8T#Hq*?m%tipto z<`8D|D0_mDXq=sEQ-YcrY*)Lw)IGsAgY&^C1LmY+LUyn{rgjJ8ZQ(9XM{wr=SGSsZ7^xUigVlxZ#n36376U#suYM7;B4nvd5BK90AM<&{W{+B>jO*RqN{ZlO?V zQtQHPni^X@pbupQ6CPtRl0t;R6*%4`(-NWC8r~UqQYFE?K@IluW<03$v;T8lIE)Cv zuC}+w6;44eS6f@B5^0F`M7#UC*GIdfyh__A?S%W&J1$y9H4a)$$k8M2JZmkj(eH52 zwZE6@9dxsP%}aq2Cn|5P9>%U!~Ap7M)oG-hla5zTS5~1LL)fvu~FQgUU_JI*^IPZ{UcMoiG7|tp|v$_$it@pqoF1? zv;|YK71OZ|MQEO6s5outQ5>2S-(e%ZI$p7`8?I1k5=TQx95aGwF`~$VmA7_qEVm*9 z?=zI+bw{iE)u6My~TnWAp`h`JvK4;Rr@6rI1fb`R0=z z;~f*?96kpq>{vV8=s+$y4F?yR(rE|tQx1xxoQ7SvpWxw>JhZa#6g zSCr&7mJz)4l?~%>rTmKw^5`m$u0{q&@z1-D@}|iVJBxr7uI6vh6cXMgc*^pIQ{sTn za8wjJ-<2sVTT@mF-qi|Oj?2NZTk#*|6}nmUv@QZp}XP0wZl_mFr5A zWJ_XKrF0NC`J_`&3FpYU;WRF{+&D}w;Y}+KGDXO(BP3VaLOxrP+`N_}nuU;Ie(fK7 zW+It47^?4rmmfYA_!Kgi;BJQfF0938bn<)arZPqXh;^wvc~L_77dY4_PhM=?2X!gMc#wU67v5a#kLav2VAXT9HWyxM@V zIqi6};4u3S9+RB23w2)bDV{t1jGWgxdrbPEQ_nLT*#J&ITF|(YN z_kaOwm9^Tsn5nSC9~h;@tx{{Y^S%dQmljLLLPUxjfK95NDh(m0a0pqa6FA(GOG`&+ z+1bDW?6r&?mg7W%d3BOYdziWPI9K}!Uwo&~$eni^ zx7=H~+1`$`*vU%z@U(%d*{=uEs1Br1wO|h|H&B)Mg;GV;?2rR7TEQd9V51w(YjE+) z%_HY}Y?*wK(M$`!oV?SD=vjTmG;fp0ir}@=&?yR>pUC_bZDc-qntja~AOe*AGwgFS*lBtF|JSnrbxwZTGT%7r@~ delta 24 gcmdm@vqfjadSS*1lM_Y6CLa@?#Tc+TQRFfs0C{i;H2?qr diff --git a/target/classes/CursorTask.class b/target/classes/CursorTask.class index b6df67f053a6c89b38197ba98cc32222f5691586..c601f0e4c8208b81bbaaa969c82bbb11c2401004 100644 GIT binary patch delta 921 zcmZuw-EI;=7(KJQWeeTL1wtuN8xl34LO~m;6@p2_jg43-)c*L}6&BbQb_^_SyyC(q zFnt3r^uokgt6X^D1Na`smoUa}cM+^5o9vu#_M3CgoSFUU{}J+i|NZqFfHe5A?;M*7 z?r8^Fs;Qav)KQ96yqD^_m2VoA{gb!smC*B{h?0zT22Z}*?(nvPGBz0ITKqs?F{>q` z-f;U@tUTxKs$puD-eCyF3J$Y&Xr+qWFs=MJc&gYYXJxCcYpv`g zb{WDo-mRL^!-n40qZaQ)E4H^}GU>x}RAp3XXAbx2#R_!P7~~f=U(+OsfnO(B5-`mA zAb^Gf1AC(Y3VLl!fP(<))xQB;856+S1Q=#2qf^-6Lvn@-yjJVb*^d2u@?O%#-W>=K z>27%9i9YTh6B3}(+eag?fC(hwClqzN5I~SB>PHIKz#MdsZk9m!E($cx(40h77}JEd z2}?98@r3G8J$*b_Tlh%zKqceITqn6jN9L;AJd{y}G74N7+t?Zjibt;}!@Un=aDwR4 ziHvkn^}InKBJF%ePL1t;LGB%gOcprR#g^iHG_NSNI6tQ> zHANvgKer$=C$S_mKTn~cC_gDDHP=dki!(GYBQY-}2dE&mB004HEL~DrkgDJc<8pB^ z_%np?FmN-3GBSv2_#i9_E-A{)OJ}y$4BPyjHI=#Egn=0d85p>BGx$de1#V{u-Vfw4 zF$e%jHU>r@smmY;BzeGWE(Re6VIYr@!JEMcs7egTW&!fV8F+y#!e$wwn-u}n#ssuN Y536A;Kv~=lvqd)ysG5->3~XXJ0C3(_Z~y=R diff --git a/target/classes/CursorTest.class b/target/classes/CursorTest.class index 3943342427629c51bde76e2e538ba18e256897fd..d2d7f56bb71fbe8e3453f81c0af547351d8f0fd3 100644 GIT binary patch delta 1922 zcmYjST}%{L6#mZ4?CdfO%ML8nK@m`~unSTn{%sXjU7#Q$Dy|A@yUJD(WRc}ZrDbT< zYOA$rr)koVHZ@IZVjmi-6)K5o8lU>uKJ?kX_QgK*#k95O-dU6o=6v6|=iYnHx#yhy zd-?CB#xMUpcnDwvKD}eam4JZ;Z1iJ;JEc`MZNg@Pk;-P%Bct6TV`+j`-BXh!l${vN zWYgKvj`YyU(Nis%k*<;SczQfV=^ZI|#n&wzit29#2lQ4}bwei-}geMhNw#PmZM1+3w7~R9}B;C@XGH)FceNgmx3V z(BW>@;(-Qqn%ILb_ZzKC?=`U&N8B#0%B}Qm(+5qQ!I0bMiyFfw&SHqLGx#5l%t zB46(b2d)tG>O>+@lN1K;oA>~+yBGA&$@vNjG!8DJZdJG4!ivZ}*vs#uzOiiCP58B2 z(9}7sFWY)aq2*R!=H|1<9zcjJ6#WvEUc0nh? zS7i8WxJtkQ860d02U>|JKX5I!qYmAS`cTi0_litIgXeWF4F)nefF!43SqYmRWT^1= zL;RQIG_2+NIgF(HW!`FMag-K5v+#5wP>UukJX{D>Fy#=lm?k2()HzG(71SrGMiwp$ zs!OVrTS|+deo6I#91RGn=13kBhfjJCniQsnG*us1>Q92^OG?w0azjv4&`@_MDoDX% z5|qTW)ON8{D7WcxOHl+3d9=w=NKotfs(8;>(YzyK(RbvQizDLodLp&_UOkaI@gzMF zTeE#q`fOcF-S$iA&spWP-p;64iY{2#0cjbq^Q6qP4Ji#fU&?&jF(okV0x1jZpp-$o zP|89(BxT69q_pfJDU0l4DT~E*FDmAHt`1;5S4;zz@>E-cjr`q&1U6$oH^y=9g0tKf zQ``^Nxf^ESG~zazz{$WPF05a%1COy2Pk75SG*b{Q6h01UjEXtoV(OL@R5}Bqxw#B7Lf*$nXQYnVco^sBF!|z@O4)B< zj6EIa!zcKq&hx0dfYq2>G}5Yay$l{?UUmfXva^(Zeupnt`5YeK+~;C;IsJUFP_2sI z!@E~%#fLp9o5N*RTosC|3yK%s1m%_~4$k4xIxRh@@Q!)z!75zi+ejSEbt8s}B7UZF s_crp|h-;S_FNg8rKo}oozGLbQFvvSu75|-iCX<_FCNH>vFc^Vkk`Pf)NDu;fU?9Xu#sFpYaWivCE}6_7W^Q)vxXyYwxN6*S5>I)N6{RzqQxfhc0Jz9vS2f3mgKKpa&H>piME=$^9uBU!iKb<26D zXmS5hyHK*rajaKpT#nI_Dh2b!*1{$IEfM$I5hJ+$-DGY;PPr3M-Z)$!(`NwRg@b z_tD*ZCTDcutMEZC+LDnU;;-a zSYJ|zwha%rPsI8r&g;sTQu>O4ui|UWVBVf8+jb@E9*s0h4kG!VNa!Emvy%oaBza%Z|R-ElXF&q)DV;IpX5;cMZHIKCd}tm!0Eh{UgJb;bOl_898sP zVCC$nE(PH81YXAv;`sh8-JG3fujUQ>5Ira@N>;@R-wkqc}!_wdaZq?L{sd%rel58>;IJ<=vo=;JMQP1 zO%PNjXa2Z5SI*f(j$9n|!HDL3*en%~G(8T}nGhG}yLO91ov>OjiAW8xZbC&E%`Cw9 zJ&_RV_#4xkRj4O!_zXxQMG7*R$<;_K!Y@r)%pjGCn8wUCv>aW)$}2E4O;~*e_bdyo z(-zh7Ks|*dZxY_PBzzr(hnIw>aW936F|CAR?*ZbXD3zJVeOw#4+PONH)wIxI(5?tp z(BYM|-=z4}H>pc4spG|QlP_tl;u23v=(dM5MLmN zFizL%$eSe=!V{FkN6EhtRT-kZ2KiZH@F@j~i)XK4;%GR$fFmPT+=RB;du(>s}xYgxvHDOkBn2|eJIv4krW4%$A(*~Nh5zW|y^)z!c z+OY>2deMPAI&p@6OC4?XjSf6cz~z65E;WQ|m@*EaLM*~_ysU4}QTQ;w z@WrD3a%%`ucs+&B7o(6;r&GAT7zd$3M@aQV?Uy zkdSdr#%2PtO2}|PRO@fy50mGFGZ9d!@SlXN(WE+`3SAV^5Hgufb_h{>Gf}4rBNg5+ zpX&9oSYIj>5;EzNyHg=0WNPWFmwd8PhOk z#x;xwT*0n?vO_*~EOMAtnzPER*09=4XqYf-G^{ZV4Gpta!&Ul1-PH--omzhfF<=H+hQvQ_&bh=Fv;dQiS2lXFN+K4!DaN~ zUF-xK5+7j~{)XN71bz4?%kKvEsyaS+nlPYN@ins^L#iG7)D}Kuc3@cbVZYjk18S7d zlPnIZV;EIAK0szLrYd+`ox>sZJcslv$f`?tLS4p$dYcc5_i#l00Y}v}z99aLW4f?E z_DgZGu+<-f!d^*kzpyu|H-f_6rY;7BJ)oY&X_k1DT1sq^66f5cvT&AI94FNwJV~qy z&!|C;h7ud?f_fO|h$V1Ywc#mZHF#HUf5+E}rO5RWo+sA8NL|4T#AK-RVQ_o9@nl%H;s!k$=JBFH7R8T~oIho1X&iVO8DVceRC8@=mr?5_B F0|16{5QG2# diff --git a/target/classes/InventoryItemsTest.class b/target/classes/InventoryItemsTest.class index f28c40d292c98e9419c3a2571bcd5890ea02da14..59dad8f3928601cf49c16f3af5204b7be6c6cdcf 100644 GIT binary patch delta 28 icmew?{91U!B}PWI$>L1%lfN-4Fj|3Fo2{63vI78;0tndv delta 140 zcmaDY{8@OzCB}L!{fzwFRQ;5K#DW5Sm(=3ylKcYwpwhh5;^f4FR7cN%%;aKy&yv*K zVtpZ5{?z1~v``T}B2wV$29hEiQqWM68kCxxpPrXlve}bq G5jy}mfh=hN diff --git a/target/classes/InventoryTest.class b/target/classes/InventoryTest.class index 9702b2b775995dcd62c8afd8cb5f64f43752e5aa..63e34c7302ff001b75c506ea23bfef15c4b94d46 100644 GIT binary patch delta 45 zcmdlew^nXLFr$Kjenx(7s(wmAVnKnvOKNd;Nq&KTP-$LjadKios-x%Ta>iY}0CJ%a AWdHyG delta 49 zcmZ20w^43GFr$izenx(7s(wmAVnKnvOKNd;Nq&KTP-$LjadKios-tH>W^(c7V#Zy( E0J$I$_y7O^ diff --git a/target/classes/Randomizer.class b/target/classes/Randomizer.class index 6485227ab5b303f056d90331bf8fce26b7cd6e52..a4fbe739d0fa3b394b16c4e1d883568881569e59 100644 GIT binary patch delta 1248 zcmZuwT~iZh7(H)xH*Yqs(IU}AXblLGAR&IClC-q7_<`bxpkTzW6;_Dk1CtFxTP8D| zQSN$^3p>;Cy3-jhs^bJl)ZTgFFX&Zgy!99Krs~;^BAt4(d-nM_&pFS#@12dWH~U|{ zdGZ`U4;CNz!=j=if>wzZfz3C~IWv(p^HYhDg_3RM4D3XkfKn*i0>MEyohc-SikZAU zVizqlm-1nkz>ec)xm3!S`AE?!m9ut)4Uxi)NRd=lcXziRQFKbg1h)K-qhfN*ZgdIA zS%){9=cs6XR$YqC@Kh=`D$y;lZJkCpaipBdPFh7j_F$jH-v7FAD-7(%0n*Qz*|K%! zhC|;UTN_ZJ+4=-O;y7qPqRWTFtnZ4H?8#)r2`3Gt@TGv)oSn7ulLGNiDO}_HK>1!< z%Ax3UD83eGUO$|Lz3W}LmERgTg6{-;cA>6JpfUPU@CWi#b*H%3He?`(trEim0e3a# zZ96ek;3EAvi*t^h^VPq_!q61~&v?Ji;57p##stK?^EF{$(*0VH;BGdYG;?O+v`JO- zepr}x7&3Go9Ut$HjXI$j16ky%zj)Ss=`p?TGRqz>~yP#M1sKH7cTQG=5j5C_SRx~iz2d^`nnMS@H)Q_VOE;>e}K&R8= zL>g-@;slXID^6j6NXJQ5>hQclyP_yPY&^vgf+6517CPi@jW|8f8EC33)o|vZO0*Q6 zaiF$}v+1B3)K)O^2Max}+6Jh^+xcw5Ml>UY&t0VlsDNZ^O4~4sF^*Ds6E9GUht=DV zW=v&|L9Ju#5OjN~E+`=S;B%ENd!ONQbwFzlTdLobrn`RzJjSFbzAAM>OgN;3wvw0nUro%SSm^ld3J`ST1Q$~YA#Cp!oH6# zzuazEoGcW_kI&Wnh^NC0ZWDHP|Tgn5KDfb3`gL iN!-Rf%`YN>1tKr*lKOihNp6KlcZHh}_`zNJkM961K?6+y delta 724 zcmX|;O=}ZT6o%i)eB4et9cxT%#)?feF-c7uO=@kUjj_gPYpOA|A0Y_N%2ZLI1Z@|k zAZT~pj8MT}AY`E+Em(E0E4S`kxe)vbM&Fr$44nJi^EK}|_gDY(KL6LwhtB}cV)>ol zlAQ0po!BV@AsiMMkzn4ppV%4uX)9BGyz;2!M;aLe0;ipq@_Kbrg0E51={#@X0h#;JFF*Oz5e?%tZ%m&m2r^v7`p-{bR57T^y4_a zaRe~Na~eSsP=H2TW<1E#r6EKhc@!ndte#?J1S)fKI6)G;$M{7Ui!)QlrmuszEXyV< zPa;99)BlW_ZueLa$(dnuaBCOCJPgq;~gb8O<95wUl z_sBQ5YIVg0XIVs-ChD^GQPgF#>zraxHEZ*EWgo@*$R4Ki)LpDwii?`1TG}qI@>XP$KgsdS{D74A_t#XqaoaP1h^#%#2BL)__^8jtk;ReU4;4W^W o$~S1Dgj*zqb$Qe<&%rj3!EKV}^;jSYc9Pk1l4D9(^ftQm4|S_-y8r+H diff --git a/target/classes/WillowChopper.class b/target/classes/WillowChopper.class index d06345f257784a6dc081796dade65176129255de..a118a2ee11dc9ae383b9292b9230e79a1aa53428 100644 GIT binary patch delta 469 zcmY+A%TB^T6o&s10d1-=h>@5mg?IstMZ7C2UO)x$l3?67QnjYEO)1_sJcKKsz_phU zW1(w%EJE_?zP;wfDiCOK!$%$fPWod3)7(Zap`KEDE(!tNb+&Xmqm=}d~Ll6D+R zUmVJYrRbWQ`u6(aAY#mm7(>VZv;7lOmI^%L7-w*oR9Q9{nj_ih0f!(ad6MQCJY}OG zS+adK!($e6*DowkX+;8yUMw^S<}XW@T;#EYB!f#YTMS*fI#1DKd#0jUd5e(6LO)o{j>1^KC-szJI{giv)q3ov|L>mNjBScl0jPJw%b$ADWK@8C;N6}tq KGHg@bgq=T0{%WuQ delta 245 zcmcb~@q&%()W2Q(7#J8#87wz)l`|&EWhIs+>gOcprR#gc^C{B3>g{tGmAa*%2M-6@{20nN^^1;8JIOR zqqrEP7>s!sOc+cV8N^dIA7J8PtYl+gVh~`^WDo+{oy5S*zzC$3wYD%QZDY`ePTn*LST*PAw?O%+F(I5N2fH4bRNU z$uD=#$S){JE#hJjV&DW3Vmu7u3~Y=H%tfUW|0&4xmLscTWZ?Hf(KcC{u^^6xfssLg zfgNb4Cj%1@GBEJ&W)Ot0>!0)1~M|p0QpP|vH;HnDKP*5 delta 177 zcmeyue4d%>)W2Q(7#J8#8Kfq1EeaCNN-Rs%Pb@FdcMK14tw>HSD9OyvV`mU%WRL?( zwD&vq!tyG7L=r>AgK{$WDo|c$;{XH^oL1Ie6BEAlQGwYgMpbrfI)~sgn=Ds noi-3Ng78Kl!NkA?B-y|Mk__BHHV;ISL5x8hq=-QRtV$996@Vte