From 9549465e970b1502e0cca2f524225114676cdece Mon Sep 17 00:00:00 2001 From: UditDewan Date: Fri, 24 Apr 2026 22:33:52 -0400 Subject: [PATCH 01/12] Add files via upload --- CHANGELOG.md | 2 + CraftingStation.java | 156 ++++++++++++++++ GameInventory1LTest.java | 319 ++++++++++++++++++++++++++++++++ GameInventoryContractTest.java | 300 +++++++++++++++++++++++++++++++ GameInventoryTest.java | 320 +++++++++++++++++++++++++++++++++ InventoryTradingDemo.java | 126 +++++++++++++ README.md | 227 ++++++++++++++--------- reflection.md | 104 +++++++++++ 8 files changed, 1470 insertions(+), 84 deletions(-) create mode 100644 CraftingStation.java create mode 100644 GameInventory1LTest.java create mode 100644 GameInventoryContractTest.java create mode 100644 GameInventoryTest.java create mode 100644 InventoryTradingDemo.java create mode 100644 reflection.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a26c01a..2516bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ the following form: YYYY.0M.0D. ### Added +- Added Junit test file `GameInventory1LTest` covering every test case not convered by the others + - Added JUnit test file `GameInventory1LTest` covering the constructor, every kernel method, iterator semantics (including that the wrapped `remove()` throws `UnsupportedOperationException`), and every Standard diff --git a/CraftingStation.java b/CraftingStation.java new file mode 100644 index 0000000..760fde6 --- /dev/null +++ b/CraftingStation.java @@ -0,0 +1,156 @@ +package components.gameinventory; + +/** + * Use case #2: {@code CraftingStation} — a small component whose + * representation contains a {@link GameInventory}. + * + *

+ * A {@code CraftingStation} models a single recipe: a set of required + * ingredients (an item name mapped to the quantity needed) plus an output + * item and output quantity. Given a player's inventory, the station can + * report whether the player has enough of every ingredient, and if so, + * consume those ingredients and deposit the crafted output. + *

+ * + *

+ * This demonstrates the "component as a building block" pattern mentioned + * in the portfolio assignment: the crafting station does not reinvent + * item-quantity bookkeeping — it reuses {@code GameInventory} for both its + * internal recipe representation and the player's inventory parameter. + *

+ */ +public final class CraftingStation { + + /** + * Required ingredients, stored as a GameInventory whose quantities mean + * "you must have at least this many of this item". + */ + private final GameInventory recipe; + + /** Item produced by one successful craft. */ + private final String outputItem; + + /** Quantity of {@link #outputItem} produced per successful craft. */ + private final int outputQuantity; + + /** + * Creates a new crafting station for a recipe with no ingredients yet. + * + * @param outputItem + * the item produced by this station + * @param outputQuantity + * how many of {@code outputItem} are produced per craft + */ + public CraftingStation(String outputItem, int outputQuantity) { + assert outputItem != null : "Violation of: outputItem is not null"; + assert outputItem.length() > 0 : "Violation of: |outputItem| > 0"; + assert outputQuantity > 0 : "Violation of: outputQuantity > 0"; + this.outputItem = outputItem; + this.outputQuantity = outputQuantity; + this.recipe = new GameInventory1L(); + } + + /** + * Adds (or increases) an ingredient requirement for this recipe. + * + * @param ingredient + * the ingredient item name + * @param quantity + * how much of {@code ingredient} the recipe requires + */ + public void addIngredient(String ingredient, int quantity) { + assert ingredient != null && ingredient.length() > 0 + : "Violation of: |ingredient| > 0"; + assert quantity > 0 : "Violation of: quantity > 0"; + this.recipe.addItem(ingredient, quantity); + } + + /** + * Reports whether {@code playerInventory} has enough of every required + * ingredient to craft once. + * + * @param playerInventory + * the inventory to check + * @return true iff every ingredient required by this recipe is present in + * {@code playerInventory} with at least the required quantity + */ + public boolean canCraft(GameInventory playerInventory) { + assert playerInventory != null + : "Violation of: playerInventory is not null"; + for (String ingredient : this.recipe) { + int needed = this.recipe.getQuantity(ingredient); + if (playerInventory.getQuantity(ingredient) < needed) { + return false; + } + } + return true; + } + + /** + * Attempts one craft. If {@code playerInventory} contains every required + * ingredient, consumes exactly the required quantities and deposits the + * output; otherwise leaves {@code playerInventory} unchanged. + * + * @param playerInventory + * the inventory to craft against + * @return true iff the craft succeeded + */ + public boolean craft(GameInventory playerInventory) { + assert playerInventory != null + : "Violation of: playerInventory is not null"; + if (!this.canCraft(playerInventory)) { + return false; + } + for (String ingredient : this.recipe) { + int needed = this.recipe.getQuantity(ingredient); + playerInventory.removeItem(ingredient, needed); + } + playerInventory.addItem(this.outputItem, this.outputQuantity); + return true; + } + + /** + * Reports the output item name. + * + * @return the output item + */ + public String getOutputItem() { + return this.outputItem; + } + + /* + * Demo ------------------------------------------------------------------- + */ + + /** + * Runs a small crafting scenario. + * + * @param args + * command-line arguments (ignored) + */ + public static void main(String[] args) { + // Recipe: 2 Iron Ingot + 1 Wood Plank -> 1 Iron Sword + CraftingStation forge = new CraftingStation("Iron Sword", 1); + forge.addIngredient("Iron Ingot", 2); + forge.addIngredient("Wood Plank", 1); + + GameInventory player = new GameInventory1L(); + player.addItem("Iron Ingot", 5); + player.addItem("Wood Plank", 3); + player.addItem("Gold", 20); + + System.out.println("Before: " + player); + System.out.println("Can craft? " + forge.canCraft(player)); + + System.out.println("Craft #1 success: " + forge.craft(player)); + System.out.println("After craft #1: " + player); + + System.out.println("Craft #2 success: " + forge.craft(player)); + System.out.println("After craft #2: " + player); + + // After two crafts: 5-4 = 1 Iron Ingot, 3-2 = 1 Wood Plank, 2 Swords. + // The recipe needs 2 Iron Ingots, so the third attempt should fail. + System.out.println("Craft #3 success: " + forge.craft(player)); + System.out.println("Final: " + player); + } +} diff --git a/GameInventory1LTest.java b/GameInventory1LTest.java new file mode 100644 index 0000000..7e76e67 --- /dev/null +++ b/GameInventory1LTest.java @@ -0,0 +1,319 @@ +package components.gameinventory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Test; + +/** + * JUnit tests for {@link GameInventory1L}, focused on the constructor, kernel + * methods, iteration, and Standard methods. + * + *

+ * Tests of non-mutating methods also verify that the inventory is left + * unchanged, usually by comparing against a separately-built "expected" + * inventory. + *

+ */ +public class GameInventory1LTest { + + /* + * Constructor / initial state -------------------------------------------- + */ + + @Test + public void testConstructorIsEmpty() { + GameInventory inv = new GameInventory1L(); + assertEquals(0, inv.size()); + assertEquals(0, inv.getQuantity("Anything")); + } + + /* + * addItem ---------------------------------------------------------------- + */ + + @Test + public void testAddItemNewEntry() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Potion", 3); + assertEquals(1, inv.size()); + assertEquals(3, inv.getQuantity("Potion")); + } + + @Test + public void testAddItemExistingEntryAccumulates() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Potion", 3); + inv.addItem("Potion", 5); + assertEquals(1, inv.size()); + assertEquals(8, inv.getQuantity("Potion")); + } + + @Test + public void testAddItemMultipleDistinct() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Sword", 1); + inv.addItem("Shield", 1); + inv.addItem("Helmet", 1); + assertEquals(3, inv.size()); + assertEquals(1, inv.getQuantity("Sword")); + assertEquals(1, inv.getQuantity("Shield")); + assertEquals(1, inv.getQuantity("Helmet")); + } + + /* + * removeItem ------------------------------------------------------------- + */ + + @Test + public void testRemoveItemPartial() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 100); + inv.removeItem("Gold", 25); + assertEquals(75, inv.getQuantity("Gold")); + assertEquals(1, inv.size()); + } + + @Test + public void testRemoveItemAllDeletesEntry() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Arrow", 12); + inv.removeItem("Arrow", 12); + assertEquals(0, inv.getQuantity("Arrow")); + assertEquals(0, inv.size()); + } + + @Test + public void testRemoveItemLastOneDeletesEntry() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Key", 1); + inv.removeItem("Key", 1); + assertEquals(0, inv.size()); + } + + @Test + public void testRemoveItemDoesNotTouchOthers() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 10); + inv.addItem("Arrow", 20); + inv.removeItem("Gold", 5); + assertEquals(5, inv.getQuantity("Gold")); + assertEquals(20, inv.getQuantity("Arrow")); + assertEquals(2, inv.size()); + } + + /* + * getQuantity ------------------------------------------------------------ + */ + + @Test + public void testGetQuantityMissingReturnsZero() { + GameInventory inv = new GameInventory1L(); + assertEquals(0, inv.getQuantity("Nothing")); + } + + @Test + public void testGetQuantityPresent() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Mushroom", 4); + assertEquals(4, inv.getQuantity("Mushroom")); + } + + @Test + public void testGetQuantityRestoresState() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Mushroom", 4); + GameInventory expected = new GameInventory1L(); + expected.addItem("Mushroom", 4); + inv.getQuantity("Mushroom"); + inv.getQuantity("Nonexistent"); + assertEquals(expected, inv); + } + + /* + * size ------------------------------------------------------------------- + */ + + @Test + public void testSizeEmpty() { + assertEquals(0, new GameInventory1L().size()); + } + + @Test + public void testSizeOne() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Bread", 7); + assertEquals(1, inv.size()); + } + + @Test + public void testSizeCountsDistinctKeysNotTotalQuantity() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Bread", 100); + inv.addItem("Water", 50); + // 150 items total, but 2 distinct keys. + assertEquals(2, inv.size()); + } + + @Test + public void testSizeMany() { + GameInventory inv = new GameInventory1L(); + for (int i = 0; i < 20; i++) { + inv.addItem("item" + i, i + 1); + } + assertEquals(20, inv.size()); + } + + /* + * iterator --------------------------------------------------------------- + */ + + @Test + public void testIteratorEmpty() { + assertFalse(new GameInventory1L().iterator().hasNext()); + } + + @Test + public void testIteratorYieldsEveryKeyExactlyOnce() { + GameInventory inv = new GameInventory1L(); + inv.addItem("a", 1); + inv.addItem("b", 2); + inv.addItem("c", 3); + Set seen = new HashSet<>(); + for (String name : inv) { + assertTrue("duplicate key: " + name, seen.add(name)); + } + Set expected = new HashSet<>(); + expected.add("a"); + expected.add("b"); + expected.add("c"); + assertEquals(expected, seen); + } + + @Test + public void testIteratorRemoveThrows() { + GameInventory inv = new GameInventory1L(); + inv.addItem("x", 1); + Iterator it = inv.iterator(); + it.next(); + try { + it.remove(); + fail("iterator.remove() should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException expected) { + // expected + } + } + + /* + * Standard methods ------------------------------------------------------- + */ + + @Test + public void testNewInstanceReturnsEmpty() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Torch", 2); + GameInventory fresh = inv.newInstance(); + assertEquals(0, fresh.size()); + } + + @Test + public void testNewInstanceDoesNotMutateReceiver() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Torch", 2); + GameInventory expected = new GameInventory1L(); + expected.addItem("Torch", 2); + inv.newInstance(); + assertEquals(expected, inv); + } + + @Test + public void testNewInstanceDynamicType() { + GameInventory inv = new GameInventory1L(); + GameInventory fresh = inv.newInstance(); + assertTrue(fresh instanceof GameInventory1L); + } + + @Test + public void testClearEmptiesInventory() { + GameInventory inv = new GameInventory1L(); + inv.addItem("A", 1); + inv.addItem("B", 2); + inv.clear(); + assertEquals(0, inv.size()); + assertFalse(inv.hasItem("A")); + assertFalse(inv.hasItem("B")); + } + + @Test + public void testClearOnAlreadyEmpty() { + GameInventory inv = new GameInventory1L(); + inv.clear(); + assertEquals(0, inv.size()); + } + + @Test + public void testTransferFromMovesContents() { + GameInventory dest = new GameInventory1L(); + GameInventory src = new GameInventory1L(); + src.addItem("Coin", 10); + src.addItem("Map", 1); + dest.transferFrom(src); + assertEquals(10, dest.getQuantity("Coin")); + assertEquals(1, dest.getQuantity("Map")); + assertEquals(2, dest.size()); + assertEquals(0, src.size()); + } + + @Test + public void testTransferFromOverwritesDestinationContents() { + GameInventory dest = new GameInventory1L(); + dest.addItem("Old", 99); + GameInventory src = new GameInventory1L(); + src.addItem("New", 1); + dest.transferFrom(src); + assertEquals(0, dest.getQuantity("Old")); + assertEquals(1, dest.getQuantity("New")); + assertEquals(1, dest.size()); + assertEquals(0, src.size()); + } + + @Test + public void testTransferFromIntoFreshlyClearedDest() { + GameInventory dest = new GameInventory1L(); + GameInventory src = new GameInventory1L(); + src.addItem("X", 3); + dest.clear(); + dest.transferFrom(src); + assertEquals(3, dest.getQuantity("X")); + assertEquals(0, src.size()); + } + + /* + * Sanity: a fresh inventory equals a cleared-then-unused inventory. ----- + */ + + @Test + public void testClearMakesInventoryEqualToFresh() { + GameInventory a = new GameInventory1L(); + a.addItem("stuff", 42); + a.clear(); + GameInventory b = new GameInventory1L(); + assertEquals(b, a); + } + + @Test + public void testDistinctInventoriesNotEqualByDefault() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + b.addItem("X", 1); + assertNotEquals(a, b); + } + +} diff --git a/GameInventoryContractTest.java b/GameInventoryContractTest.java new file mode 100644 index 0000000..7ef1606 --- /dev/null +++ b/GameInventoryContractTest.java @@ -0,0 +1,300 @@ +package components.gameinventory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.Test; + +/** + * JUnit tests for precondition (design-by-contract) boundaries on + * {@link GameInventory1L}. + * + *

+ * These tests verify that every method throws {@link AssertionError} when its + * preconditions are violated. They complement {@link GameInventory1LTest} and + * {@link GameInventoryTest}, which cover the happy-path behaviour. + *

+ * + *

+ * Important: assertions must be enabled when running this + * suite. In VSCode the {@code java.debug.settings.vmArgs} setting already + * includes {@code -ea}. From the command line, pass {@code -ea} to the JVM: + * {@code java -ea -cp ... org.junit.runner.JUnitCore + * components.gameinventory.GameInventoryContractTest} + *

+ */ +public class GameInventoryContractTest { + + // ----------------------------------------------------------------------- + // Helper + // ----------------------------------------------------------------------- + + /** + * Returns an inventory pre-loaded with one entry: "Gold" → 10. + */ + private static GameInventory oneEntry() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 10); + return inv; + } + + // ----------------------------------------------------------------------- + // addItem — quantity preconditions + // ----------------------------------------------------------------------- + + @Test + public void testAddItemZeroQuantityThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.addItem("Gold", 0); + fail("Expected AssertionError for qty == 0"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testAddItemNegativeQuantityThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.addItem("Gold", -1); + fail("Expected AssertionError for qty < 0"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testAddItemLargeNegativeQuantityThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.addItem("Gold", Integer.MIN_VALUE); + fail("Expected AssertionError for qty == Integer.MIN_VALUE"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // addItem — item-name preconditions + // ----------------------------------------------------------------------- + + @Test + public void testAddItemNullNameThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.addItem(null, 1); + fail("Expected AssertionError for null item name"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testAddItemEmptyNameThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.addItem("", 1); + fail("Expected AssertionError for empty item name"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // removeItem — quantity preconditions + // ----------------------------------------------------------------------- + + @Test + public void testRemoveItemZeroQuantityThrows() { + GameInventory inv = oneEntry(); + try { + inv.removeItem("Gold", 0); + fail("Expected AssertionError for qty == 0"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testRemoveItemNegativeQuantityThrows() { + GameInventory inv = oneEntry(); + try { + inv.removeItem("Gold", -5); + fail("Expected AssertionError for qty < 0"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // removeItem — "not enough" preconditions + // ----------------------------------------------------------------------- + + @Test + public void testRemoveItemMoreThanPresentThrows() { + GameInventory inv = oneEntry(); // Gold=10 + try { + inv.removeItem("Gold", 11); + fail("Expected AssertionError for removing more than present"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testRemoveItemFromMissingKeyThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.removeItem("Arrow", 1); + fail("Expected AssertionError for removing from absent key"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testRemoveItemExactlyPresentDoesNotThrow() { + // Boundary: removing exactly what is there must succeed. + GameInventory inv = oneEntry(); // Gold=10 + inv.removeItem("Gold", 10); // should not throw + assertEquals(0, inv.size()); + } + + @Test + public void testRemoveItemAfterFullRemovalThrows() { + // Once the entry is gone, a second remove must throw. + GameInventory inv = oneEntry(); + inv.removeItem("Gold", 10); + try { + inv.removeItem("Gold", 1); + fail("Expected AssertionError: entry was deleted"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // removeItem — name preconditions + // ----------------------------------------------------------------------- + + @Test + public void testRemoveItemNullNameThrows() { + GameInventory inv = oneEntry(); + try { + inv.removeItem(null, 1); + fail("Expected AssertionError for null item name"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testRemoveItemEmptyNameThrows() { + GameInventory inv = oneEntry(); + try { + inv.removeItem("", 1); + fail("Expected AssertionError for empty item name"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // transferItem — secondary method preconditions + // ----------------------------------------------------------------------- + + @Test + public void testTransferItemMoreThanPresentThrows() { + GameInventory a = oneEntry(); // Gold=10 + GameInventory b = new GameInventory1L(); + try { + a.transferItem(b, "Gold", 11); + fail("Expected AssertionError: transferring more than present"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testTransferItemZeroQuantityThrows() { + GameInventory a = oneEntry(); + GameInventory b = new GameInventory1L(); + try { + a.transferItem(b, "Gold", 0); + fail("Expected AssertionError for qty == 0"); + } catch (AssertionError expected) { + // correct + } + } + + @Test + public void testTransferItemNullOtherThrows() { + GameInventory a = oneEntry(); + try { + a.transferItem(null, "Gold", 1); + fail("Expected AssertionError for null destination"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // mostAbundantItem — empty inventory precondition + // ----------------------------------------------------------------------- + + @Test + public void testMostAbundantItemOnEmptyThrows() { + GameInventory inv = new GameInventory1L(); + try { + inv.mostAbundantItem(); + fail("Expected AssertionError: inventory is empty"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // mergeFrom — null source precondition + // ----------------------------------------------------------------------- + + @Test + public void testMergeFromNullSourceThrows() { + GameInventory dest = oneEntry(); + try { + dest.mergeFrom(null); + fail("Expected AssertionError for null source"); + } catch (AssertionError expected) { + // correct + } + } + + // ----------------------------------------------------------------------- + // Verify state is unchanged after a caught precondition violation + // ----------------------------------------------------------------------- + + @Test + public void testStateUnchangedAfterBadAdd() { + GameInventory inv = oneEntry(); // Gold=10 + try { + inv.addItem("Gold", -1); + } catch (AssertionError ignored) { + // expected; fall through + } + // The inventory must be exactly as it was. + assertEquals(1, inv.size()); + assertEquals(10, inv.getQuantity("Gold")); + } + + @Test + public void testStateUnchangedAfterBadRemove() { + GameInventory inv = oneEntry(); // Gold=10 + try { + inv.removeItem("Gold", 999); + } catch (AssertionError ignored) { + // expected; fall through + } + assertEquals(1, inv.size()); + assertEquals(10, inv.getQuantity("Gold")); + } +} diff --git a/GameInventoryTest.java b/GameInventoryTest.java new file mode 100644 index 0000000..44d18d2 --- /dev/null +++ b/GameInventoryTest.java @@ -0,0 +1,320 @@ +package components.gameinventory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * JUnit tests for the secondary methods on {@link GameInventory} and the + * Object overrides defined on {@link GameInventorySecondary}, exercised + * through {@link GameInventory1L}. + */ +public class GameInventoryTest { + + /* + * hasItem ---------------------------------------------------------------- + */ + + @Test + public void testHasItemTrue() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Sword", 1); + assertTrue(inv.hasItem("Sword")); + } + + @Test + public void testHasItemFalseOnEmpty() { + GameInventory inv = new GameInventory1L(); + assertFalse(inv.hasItem("Sword")); + } + + @Test + public void testHasItemFalseAfterFullRemoval() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Torch", 3); + inv.removeItem("Torch", 3); + assertFalse(inv.hasItem("Torch")); + } + + @Test + public void testHasItemDoesNotMutate() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Torch", 3); + GameInventory expected = new GameInventory1L(); + expected.addItem("Torch", 3); + inv.hasItem("Torch"); + inv.hasItem("Nothing"); + assertEquals(expected, inv); + } + + /* + * totalItems ------------------------------------------------------------- + */ + + @Test + public void testTotalItemsEmpty() { + assertEquals(0, new GameInventory1L().totalItems()); + } + + @Test + public void testTotalItemsSingleEntry() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 42); + assertEquals(42, inv.totalItems()); + } + + @Test + public void testTotalItemsMultipleEntries() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 42); + inv.addItem("Arrow", 8); + inv.addItem("Sword", 1); + assertEquals(51, inv.totalItems()); + } + + @Test + public void testTotalItemsDoesNotMutate() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 42); + GameInventory expected = new GameInventory1L(); + expected.addItem("Gold", 42); + inv.totalItems(); + assertEquals(expected, inv); + } + + /* + * mostAbundantItem ------------------------------------------------------- + */ + + @Test + public void testMostAbundantSingleItem() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 100); + assertEquals("Gold", inv.mostAbundantItem()); + } + + @Test + public void testMostAbundantClearWinner() { + GameInventory inv = new GameInventory1L(); + inv.addItem("Gold", 100); + inv.addItem("Arrow", 8); + inv.addItem("Sword", 1); + assertEquals("Gold", inv.mostAbundantItem()); + } + + @Test + public void testMostAbundantTieReturnsOneOfTheWinners() { + GameInventory inv = new GameInventory1L(); + inv.addItem("A", 5); + inv.addItem("B", 5); + inv.addItem("C", 2); + String winner = inv.mostAbundantItem(); + // Contract allows any item with the maximum quantity. Verify that + // whatever was returned, its quantity equals the max. + assertNotNull(winner); + assertEquals(5, inv.getQuantity(winner)); + } + + /* + * transferItem ----------------------------------------------------------- + */ + + @Test + public void testTransferItemPartial() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("Coin", 10); + a.transferItem(b, "Coin", 4); + assertEquals(6, a.getQuantity("Coin")); + assertEquals(4, b.getQuantity("Coin")); + } + + @Test + public void testTransferItemAllRemovesFromSource() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("Coin", 10); + a.transferItem(b, "Coin", 10); + assertFalse(a.hasItem("Coin")); + assertEquals(0, a.size()); + assertEquals(10, b.getQuantity("Coin")); + assertEquals(1, b.size()); + } + + @Test + public void testTransferItemIntoExistingStack() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("Coin", 10); + b.addItem("Coin", 5); + a.transferItem(b, "Coin", 3); + assertEquals(7, a.getQuantity("Coin")); + assertEquals(8, b.getQuantity("Coin")); + } + + @Test + public void testTransferItemLeavesOtherItemsAlone() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("Coin", 10); + a.addItem("Gem", 2); + a.transferItem(b, "Coin", 4); + assertEquals(2, a.getQuantity("Gem")); + assertEquals(0, b.getQuantity("Gem")); + } + + /* + * mergeFrom -------------------------------------------------------------- + */ + + @Test + public void testMergeFromEmptySource() { + GameInventory dest = new GameInventory1L(); + dest.addItem("Gold", 10); + GameInventory expected = new GameInventory1L(); + expected.addItem("Gold", 10); + GameInventory src = new GameInventory1L(); + dest.mergeFrom(src); + assertEquals(expected, dest); + assertEquals(0, src.size()); + } + + @Test + public void testMergeFromDisjointKeys() { + GameInventory dest = new GameInventory1L(); + GameInventory src = new GameInventory1L(); + dest.addItem("Gold", 10); + src.addItem("Arrow", 4); + dest.mergeFrom(src); + assertEquals(10, dest.getQuantity("Gold")); + assertEquals(4, dest.getQuantity("Arrow")); + assertEquals(2, dest.size()); + assertEquals(0, src.size()); + } + + @Test + public void testMergeFromOverlappingKeysSums() { + GameInventory dest = new GameInventory1L(); + GameInventory src = new GameInventory1L(); + dest.addItem("Gold", 10); + dest.addItem("Map", 1); + src.addItem("Gold", 5); + src.addItem("Key", 2); + dest.mergeFrom(src); + assertEquals(15, dest.getQuantity("Gold")); + assertEquals(1, dest.getQuantity("Map")); + assertEquals(2, dest.getQuantity("Key")); + assertEquals(3, dest.size()); + assertEquals(0, src.size()); + } + + @Test + public void testMergeFromIntoEmptyDest() { + GameInventory dest = new GameInventory1L(); + GameInventory src = new GameInventory1L(); + src.addItem("A", 1); + src.addItem("B", 2); + dest.mergeFrom(src); + assertEquals(1, dest.getQuantity("A")); + assertEquals(2, dest.getQuantity("B")); + assertEquals(2, dest.size()); + assertEquals(0, src.size()); + } + + /* + * equals / hashCode / toString ------------------------------------------ + */ + + @Test + public void testEqualsSameContents() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("X", 1); + a.addItem("Y", 2); + b.addItem("X", 1); + b.addItem("Y", 2); + assertEquals(a, b); + } + + @Test + public void testEqualsDifferentQuantities() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("X", 1); + b.addItem("X", 2); + assertNotEquals(a, b); + } + + @Test + public void testEqualsDifferentSizes() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("X", 1); + b.addItem("X", 1); + b.addItem("Y", 1); + assertNotEquals(a, b); + } + + @Test + public void testEqualsReflexive() { + GameInventory a = new GameInventory1L(); + a.addItem("X", 1); + assertEquals(a, a); + } + + @Test + public void testEqualsNullIsFalse() { + GameInventory a = new GameInventory1L(); + assertNotEquals(null, a); + } + + @Test + public void testEqualsDifferentTypeIsFalse() { + GameInventory a = new GameInventory1L(); + assertNotEquals("not an inventory", a); + } + + @Test + public void testHashCodeConsistentWithEqualsRegardlessOfInsertionOrder() { + GameInventory a = new GameInventory1L(); + GameInventory b = new GameInventory1L(); + a.addItem("X", 1); + a.addItem("Y", 2); + b.addItem("Y", 2); + b.addItem("X", 1); + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + public void testToStringEmpty() { + assertEquals("{}", new GameInventory1L().toString()); + } + + @Test + public void testToStringContainsEachEntry() { + GameInventory a = new GameInventory1L(); + a.addItem("Gold", 10); + a.addItem("Sword", 1); + String s = a.toString(); + assertTrue(s.startsWith("{")); + assertTrue(s.endsWith("}")); + assertTrue(s.contains("Gold=10")); + assertTrue(s.contains("Sword=1")); + } + + @Test + public void testToStringDoesNotMutate() { + GameInventory a = new GameInventory1L(); + a.addItem("Gold", 10); + GameInventory expected = new GameInventory1L(); + expected.addItem("Gold", 10); + a.toString(); + assertEquals(expected, a); + } + +} diff --git a/InventoryTradingDemo.java b/InventoryTradingDemo.java new file mode 100644 index 0000000..75f705f --- /dev/null +++ b/InventoryTradingDemo.java @@ -0,0 +1,126 @@ +package components.gameinventory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Use case #1: a scripted RPG trading scene. + * + *

+ * This demo exercises the full {@link GameInventory} API — kernel mutators, + * secondary queries, transfers, and merges — by narrating a short sequence: + * a player loots a chest, visits a shopkeeper to sell potions for gold, and + * collects a quest reward. Output is printed to {@code System.out} so the + * before/after state of each inventory is visible. + *

+ * + *

+ * This is a command-line demo: no GUI, no input — just + * {@code public static void main}. + *

+ */ +public final class InventoryTradingDemo { + + /** No instances; utility class. */ + private InventoryTradingDemo() { + } + + /** + * Prints a labeled snapshot of an inventory. + */ + private static void show(String label, GameInventory inv) { + System.out.println(" " + label + " (" + + inv.size() + " distinct, " + + inv.totalItems() + " total)"); + System.out.println(" " + inv); + } + + /** + * Snapshots the keys currently in {@code src} into a list so we can + * iterate over them while mutating {@code src}. + */ + private static List keySnapshot(GameInventory src) { + List names = new ArrayList<>(); + for (String name : src) { + names.add(name); + } + return names; + } + + /** + * Entry point for the trading demo. + * + * @param args + * command-line arguments (ignored) + */ + public static void main(String[] args) { + GameInventory player = new GameInventory1L(); + GameInventory chest = new GameInventory1L(); + GameInventory shopkeeper = new GameInventory1L(); + GameInventory questReward = new GameInventory1L(); + + // --- Scene 1: starting state ----------------------------------- + player.addItem("Gold", 50); + player.addItem("Health Potion", 2); + player.addItem("Iron Sword", 1); + + chest.addItem("Gold", 120); + chest.addItem("Health Potion", 6); + chest.addItem("Diamond", 1); + + System.out.println("== Scene 1: starting out =="); + show("Player", player); + show("Chest", chest); + System.out.println(); + + // --- Scene 2: loot the chest ----------------------------------- + System.out.println("== Scene 2: looting the chest =="); + for (String name : keySnapshot(chest)) { + int qty = chest.getQuantity(name); + chest.transferItem(player, name, qty); + } + show("Player", player); + show("Chest", chest); + System.out.println(); + + // --- Scene 3: sell potions to the shopkeeper ------------------- + System.out.println("== Scene 3: trading with shopkeeper =="); + shopkeeper.addItem("Gold", 500); + shopkeeper.addItem("Steel Shield", 1); + + int sellQty = 4; + int pricePerPotion = 10; + if (player.getQuantity("Health Potion") >= sellQty + && shopkeeper.getQuantity("Gold") >= sellQty * pricePerPotion) { + player.transferItem(shopkeeper, "Health Potion", sellQty); + shopkeeper.transferItem(player, "Gold", sellQty * pricePerPotion); + System.out.println(" Sold " + sellQty + " Health Potions for " + + sellQty * pricePerPotion + " Gold."); + } + show("Player", player); + show("Shopkeeper", shopkeeper); + System.out.println(); + + // --- Scene 4: claim the quest reward --------------------------- + System.out.println("== Scene 4: claiming the quest reward =="); + questReward.addItem("Gold", 75); + questReward.addItem("Elixir", 2); + player.mergeFrom(questReward); + show("Player", player); + show("Quest reward", questReward); + System.out.println(); + + // --- Epilogue -------------------------------------------------- + System.out.println("== Epilogue =="); + System.out.println(" Carrying " + player.totalItems() + + " items across " + player.size() + " stacks."); + if (player.size() > 0) { + String top = player.mostAbundantItem(); + System.out.println(" Most abundant stack: " + + top + " (" + player.getQuantity(top) + ")"); + } + if (player.hasItem("Diamond")) { + System.out.println(" Still carrying that Diamond from the chest!"); + } + } +} diff --git a/README.md b/README.md index 14aa94d..e698d53 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,149 @@ -# Portfolio Project +# GameInventory + +An OSU-discipline software component that models a **video game inventory** — +a finite mapping from item names to positive integer quantities, with no +stack limit and no weight cap. Items are added, removed, transferred between +inventories, merged, and queried through a small, well-specified API. + +This component was built as the portfolio project for CSE 2231. It follows +the software sequence discipline: a kernel interface, an enhanced interface +layered on top, an abstract class that implements all secondary methods +using only the kernel, and a thin kernel implementation over +`java.util.HashMap`. + +## Why this component? + +Games like Minecraft, Kingdom Come: Deliverance, Fallout, and Baldur's +Gate 3 all use some notion of an inventory — but they often add weight +limits and max stack sizes that slow down play without adding much +strategic depth. `GameInventory` deliberately strips both of those away, so +it can serve as a clean building block for any RPG-style project that just +needs to track *what* the player has and *how much*. + +## Hierarchy + +``` +Standard Iterable + \ / + \ / + GameInventoryKernel + | + GameInventory (enhanced interface) + | + GameInventorySecondary (secondary methods + Object overrides) + | + GameInventory1L (HashMap-backed kernel implementation) +``` + +## Quick start + +```java +import components.gameinventory.GameInventory; +import components.gameinventory.GameInventory1L; + +GameInventory player = new GameInventory1L(); +player.addItem("Gold", 50); +player.addItem("Health Potion", 3); + +GameInventory chest = new GameInventory1L(); +chest.addItem("Gold", 100); +chest.transferItem(player, "Gold", 100); // player now has 150 gold + +System.out.println(player); // {Gold=150, Health Potion=3} +System.out.println(player.mostAbundantItem()); // Gold +``` + +## API overview + +**Kernel methods** (in `GameInventoryKernel`): + +| Method | What it does | +|---|---| +| `addItem(item, qty)` | add `qty` of `item` (creates the entry if new) | +| `removeItem(item, qty)` | remove `qty` of `item` (deletes the entry if it hits zero) | +| `getQuantity(item)` | returns the current count, or 0 if the item isn't present | +| `size()` | returns the number of distinct item names | +| `iterator()` | iterates over the names of items currently in the inventory | + +**Secondary methods** (in `GameInventory`): + +| Method | What it does | +|---|---| +| `hasItem(item)` | true iff `item` is present with quantity > 0 | +| `totalItems()` | sum of all quantities across all items | +| `mostAbundantItem()` | name of an item tied for the largest quantity | +| `transferItem(other, item, qty)` | move `qty` of `item` from this to `other` | +| `mergeFrom(source)` | combine everything from `source` into this; `source` ends empty | + +**Standard methods** come from `Standard`: `newInstance`, +`clear`, `transferFrom`. + +## Project layout + +``` +src/ +├── components/ +│ └── gameinventory/ +│ ├── GameInventoryKernel.java kernel interface +│ ├── GameInventory.java enhanced interface +│ ├── GameInventorySecondary.java abstract class +│ └── GameInventory1L.java kernel implementation +├── InventoryTradingDemo.java use case #1 — scripted scene +└── CraftingStation.java use case #2 — layered component + +test/ +└── components/ + └── gameinventory/ + ├── GameInventory1LTest.java kernel + Standard tests + └── GameInventoryTest.java secondary + Object-override tests + +doc/ +└── 01..06 assignment write-ups + +CHANGELOG.md Keep-a-Changelog style history, CalVer dated +``` + +## Use cases + +Two worked examples live in `src/`: + +- **`InventoryTradingDemo`** — a scripted RPG scene: the player loots a + chest, sells potions to a shopkeeper for gold, and claims a quest reward. + This exercises the full API end to end. +- **`CraftingStation`** — a small component that uses a `GameInventory` as + part of its *own* representation. A station holds a recipe (also a + `GameInventory`), checks a player's inventory for the required + ingredients, and consumes them to produce an output item. This is the + "component as building block" pattern. + +Each use case has a `main` method you can run directly. + +## Testing + +Run the JUnit suites under `test/components/gameinventory/`: + +- `GameInventory1LTest` — constructor, every kernel method, iterator + semantics (including the wrapped `remove()` throwing + `UnsupportedOperationException`), and every Standard method. +- `GameInventoryTest` — every secondary method and the `equals` / + `hashCode` / `toString` overrides. Non-mutating tests also check that + the inventory is unchanged by comparing against a separately-built + "expected" inventory. -The purpose of this repo is to provide a framework for creating your own -component in the software sequence discipline. If you were unsure whether -or not to make your own, consider the following testimonial: +Tests that depend on iteration order (e.g. `toString`, `mostAbundantItem` +on a tie) verify contract-level properties rather than a specific literal +string or key, because iteration order on a `HashMap` is not guaranteed. -> I really enjoyed the portfolio project! It gave me a stronger understanding -> of the OSU software discipline while also giving me the flexibility to -> design something that reflected my interests. This made the experience -> rewarding and enjoyable as I created a product I was proud of! +## Convention & correspondence -## Recommended Steps to Get Started +Documented at the top of `GameInventory1L`: -When starting your portfolio project, the following steps should make your life -a bit easier. +- **Convention:** the backing `Map` is non-null, every key + is a non-empty string, every value is strictly positive. Entries whose + quantity would drop to zero are deleted rather than stored as zero. +- **Correspondence:** the abstract inventory is the partial function whose + domain is the map's key set, where `this[k] = items.get(k)`. -### Step 1: Create a Repo From This Template +## License - - -Assuming you're reading this README from GitHub, you can make use of this -repo by clicking the `Use this template` button in the top-right corner of -this page. If you can't find the button, [this link][use-this-template] -should work as well. Personally, I would recommend using the -`Create a new repository` option, which will allow you to name the -repository after your component. Given that you will be submitting pull -requests to me through Carmen, you'll want to make sure your repository -is public. Then, you can click `Create repository`. After that, you can -go through all the usual steps of cloning a repository on your system to -get to work. I use GitHub Desktop to clone projects, and it has a nice -feature of letting you open a repo directly in VSCode from the -`Repository` menu. - -### Step 2: Install Recommended Plugins - - - -When you open VSCode with this project, you should get a notification in the -bottom right corner that there are some recommended extensions to install. -Click install all. If you ignored this message or it never came up, feel free -to press CTRL+SHIFT+P and type "Show Recommended Extensions". Install all of the -extensions listed. - -### Step 3: Install the Latest JDK - - - -If you do not have an available JDK on your system, you may be prompted to -install one by VSCode. The default seems to be Red Hat's OpenJDK, which seems to -require you to register for an account or to install on the command line. -Regardless, there is no mac support. As a result, I would just recommend -installing the latest JDK [directly from Oracle's site][jdk-downloads]. - -### Step 4: Add Key Libraries to Project - - - -As you are probably all aware at this point, you need the components jar to get -anything running. My advice is to [download it from here][components-jar]. Then, -drop it into the `lib` folder in the project. Git automatically ignores anything -you put here by default, so don't worry about committing it to version control. - -Similarly, you will need the testing APIs (e.g., JUnit). Perhaps the easiest way -to include them in your project is to click the beaker symbol in the left -sidebar; it's right below the extensions button which looks like four squares. -If you do not see this button, try creating a Java file in `src`. From there, -you can click "Enable Java Tests" and then click "JUnit" from the -dropdown. That's it! You should now see the two JUnit libraries in the lib -folder. - -**Note**: if you're using VSCode for class projects, you might be wondering -why you never had to do this. In general, it's bad practice to commit binaries -to version control. However, we have no way of managing dependencies with the -custom `components.jar`, so I included them directly in the template. I did not -include them here, so you could see how it might be done from scratch. If at any -point you're struggling with Step 3, just copy the lib folder from the monorepo -template. - -## Next Steps - - - -Now that you have everything setup, you can begin crafting your component. There -will be deadlines for each step in Carmen, but you're free to complete each step -as early as you'd like. To start, you'll want to visit the [doc](doc/) directory -for each assignment file. - -[components-jar]: https://cse22x1.engineering.osu.edu/common/components.jar -[jdk-downloads]: https://www.oracle.com/java/technologies/downloads/ -[use-this-template]: https://github.com/new?template_name=portfolio-project&template_owner=jrg94 +See `LICENSE` in the repo root. diff --git a/reflection.md b/reflection.md new file mode 100644 index 0000000..0a89e44 --- /dev/null +++ b/reflection.md @@ -0,0 +1,104 @@ +# Part 6 Reflection + + +--- + +### How much better (or worse) do you understand software development now, and why? + +The biggest shift for me wasn't learning new syntax — it was actually +living with a component across six assignments instead of writing +throwaway homework. I designed `GameInventory` in Part 1, built a +proof-of-concept in Part 2, and then had to keep untangling earlier +decisions in every part after that. In Part 3 I realized I couldn't +implement my secondary methods without a `size()` kernel method and +without making the kernel `Iterable`, so I went back and changed +the interface. In Part 4 I hit an iterator-invalidation problem in +`mergeFrom` — I couldn't for-each over the source while removing from it — +and had to change the implementation strategy to a `while (source.size() > +0)` drain. None of that was hard in isolation, but feeling the cost of a +bad early decision in a later assignment is a real-world experience +textbook problems don't reproduce. + +### Did the portfolio project surface any gaps in your own knowledge? If so, what were they and how did you address them? + +Yeah 2: +- I didn't really get why the OSU discipline separates kernel + from secondary until I had to write `GameInventorySecondary` using only + kernel methods. Being forbidden from touching the HashMap directly + forced me to actually use the abstraction I'd designed, and that made + me catch two missing kernel methods. I slightly forgive all of you for + forcing me to only use kernel methods on tests. +- I didn't think about iterator safety at all until I realized + `HashMap.keySet().iterator()` lets callers delete things, which would + let them bypass the kernel. Wrapping the iterator to throw on `remove()` + was a small change that tightened encapsulation a lot. + +### Has your perspective on software development changed? Do you still enjoy it? + +I enjoy it more than I did going in, but for different reasons. I used to +think "good code" mostly meant code that worked; now I think a lot more +about the contract someone else reads before calling my method. The +design-by-contract assertions in `addItem` and `removeItem` aren't there +to make the file longer — they catch bugs at the call site instead of ten +stack frames deep, which I've actually come to appreciate. + +I also underestimated how much of software development is writing about +code: the convention, the correspondence, the Javadoc, the CHANGELOG, the +README. That part surprised me. It's not my favorite thing, but I can see +why a future collaborator (or future me) would need it. + +### What skills did you pick up during this process? + +- Using `git` and GitHub for branching and pull-request workflow instead + of zip files +- Writing a CHANGELOG that a reader can actually use to see what changed +- Translating an informal idea ("inventory") into a formal interface + (math model, contracts, pre/postconditions) +- Writing a representation invariant and abstraction function +- Reading and applying the software-sequence discipline on a component I + actually designed, not one the instructor pre-built +- Markdown, basic repo hygiene, using CheckStyle and the formatter + +### Rephrase those skills as resume bullets + +- Designed and implemented a layered software component in Java from + interface through kernel implementation, following design-by-contract + and a written representation invariant. +- Wrote a JUnit test suite covering kernel, secondary, and standard + methods, including iterator-safety and contract-edge-case tests. +- Authored technical documentation — Javadoc, a project README, + convention and correspondence, and a Keep-a-Changelog history — aimed + at external readers. +- Used Git and GitHub with a feature-branch / pull-request workflow + across six iterative deliverables. + +### How has this project affected your career trajectory? + +It reinforced that I'm interested in game-adjacent software. The project +started because inventory systems in the RPGs I play (Minecraft, KCD, +Fallout, BG3) always frustrated me with artificial limits. Building the +component that I wanted reminded me that software is how you +get to fix the small things that bug you, not just ship features someone +else scoped. Whether that turns into gameplay programming, tools, or +something adjacent, I'm more interested in the path, not less. + +### What's next, and who could mentor you? + +Concrete next steps: +- Finish the component by wiring it into a small playable prototype (a + text-adventure or a Minecraft-style crafting sandbox) so it actuall + does something and doesnt just rot like my projects. +- Pick up a game-focused framework — LibGDX or Unity — and port some of + what I've built. +- Contribute to an open-source mod or tool for a game I already play, + to get used to reading code I didn't write. + +For mentors: my instructor and TAs this semester have already been +useful for design feedback. Beyond that, the CSE department runs office +hours for project-based advising, and OSU's ACM student chapter has +members with internship experience I can ask about the jump from +coursework to industry. If I'm serious about games, connecting with a +dev from a studio like Digital Extremes or a local indie via LinkedIn +alumni search would probably be the single highest-leverage thing I +could do.Im far more likely to just make a game with some friends +though. Game development dont make enough money for me. From d16893bdf1f02ece124c6775faf3bf951df857e0 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Fri, 24 Apr 2026 22:41:36 -0400 Subject: [PATCH 02/12] Rename CraftingStation.java to src/CraftingStation.java --- CraftingStation.java => src/CraftingStation.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CraftingStation.java => src/CraftingStation.java (100%) diff --git a/CraftingStation.java b/src/CraftingStation.java similarity index 100% rename from CraftingStation.java rename to src/CraftingStation.java From f6c333b16bd2543e2d6b29ecf1d81f05cb98c097 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Fri, 24 Apr 2026 22:42:21 -0400 Subject: [PATCH 03/12] Rename InventoryTradingDemo.java to src/InventoryTradingDemo.java --- InventoryTradingDemo.java => src/InventoryTradingDemo.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename InventoryTradingDemo.java => src/InventoryTradingDemo.java (100%) diff --git a/InventoryTradingDemo.java b/src/InventoryTradingDemo.java similarity index 100% rename from InventoryTradingDemo.java rename to src/InventoryTradingDemo.java From 227b6a9d3ffbb7e1c9a0bf97ce591e7920962646 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Fri, 24 Apr 2026 23:37:48 -0400 Subject: [PATCH 04/12] Refactor GameInventoryMVP and clean up comments --- GameInventoryMVP.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GameInventoryMVP.java b/GameInventoryMVP.java index 303c687..8a86a6d 100644 --- a/GameInventoryMVP.java +++ b/GameInventoryMVP.java @@ -4,8 +4,6 @@ /** * Proof-of-Concept for an RPG GameInventory component. * - * This is NOT the full OSU-discipline version. - * It is a minimal working implementation to prove feasibility. */ public class GameInventoryMVP { @@ -126,4 +124,4 @@ public static void main(String[] args) { System.out.println("Does player have Iron Sword? " + player.hasItem("Iron Sword")); System.out.println("Does player have Diamond? " + player.hasItem("Diamond")); } -} \ No newline at end of file +} From 82d55a0577a104760116f6541d27db95c3a5db92 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:18:09 -0400 Subject: [PATCH 05/12] Rename GameInventory.java to src/components/gameinventory/GameInventory.java --- .../components/gameinventory/GameInventory.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventory.java => src/components/gameinventory/GameInventory.java (100%) diff --git a/GameInventory.java b/src/components/gameinventory/GameInventory.java similarity index 100% rename from GameInventory.java rename to src/components/gameinventory/GameInventory.java From 8420367771d46eec4e73a8fa1da11d9141fce20b Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:19:41 -0400 Subject: [PATCH 06/12] Rename GameInventory1L.java to src/components/gameinventory/GameInventory1L.java --- .../components/gameinventory/GameInventory1L.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventory1L.java => src/components/gameinventory/GameInventory1L.java (100%) diff --git a/GameInventory1L.java b/src/components/gameinventory/GameInventory1L.java similarity index 100% rename from GameInventory1L.java rename to src/components/gameinventory/GameInventory1L.java From 4383b6e0fe7a9257d5d86fc59ce3bddbefc7f55a Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:21:37 -0400 Subject: [PATCH 07/12] Rename GameInventory1LTest.java to test/components/gameinventory/GameInventory1LTest.java --- .../components/gameinventory/GameInventory1LTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventory1LTest.java => test/components/gameinventory/GameInventory1LTest.java (100%) diff --git a/GameInventory1LTest.java b/test/components/gameinventory/GameInventory1LTest.java similarity index 100% rename from GameInventory1LTest.java rename to test/components/gameinventory/GameInventory1LTest.java From f7e5f86ccc5a90f49292a836c9566cb3af18f5de Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:21:58 -0400 Subject: [PATCH 08/12] Rename GameInventoryContractTest.java to test/components/gameinventory/GameInventoryContractTest.java --- .../components/gameinventory/GameInventoryContractTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventoryContractTest.java => test/components/gameinventory/GameInventoryContractTest.java (100%) diff --git a/GameInventoryContractTest.java b/test/components/gameinventory/GameInventoryContractTest.java similarity index 100% rename from GameInventoryContractTest.java rename to test/components/gameinventory/GameInventoryContractTest.java From ceb1b08566ef108c8e7216df741c0de1d7040317 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:22:24 -0400 Subject: [PATCH 09/12] Rename GameInventoryKernel.java to src/components/gameinventory/GameInventoryKernel.java --- .../components/gameinventory/GameInventoryKernel.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventoryKernel.java => src/components/gameinventory/GameInventoryKernel.java (100%) diff --git a/GameInventoryKernel.java b/src/components/gameinventory/GameInventoryKernel.java similarity index 100% rename from GameInventoryKernel.java rename to src/components/gameinventory/GameInventoryKernel.java From 04c128b4dde1c2856419071d9d97419aa2caebc1 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:22:41 -0400 Subject: [PATCH 10/12] Rename GameInventoryTest.java to test/components/gameinventory/GameInventoryTest.java --- .../components/gameinventory/GameInventoryTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventoryTest.java => test/components/gameinventory/GameInventoryTest.java (100%) diff --git a/GameInventoryTest.java b/test/components/gameinventory/GameInventoryTest.java similarity index 100% rename from GameInventoryTest.java rename to test/components/gameinventory/GameInventoryTest.java From 1fc480aed48c3297feefc12cf254b5cd7977bc50 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:22:56 -0400 Subject: [PATCH 11/12] Rename GameInventoryMVP.java to src/components/gameinventory/GameInventoryMVP.java --- .../components/gameinventory/GameInventoryMVP.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventoryMVP.java => src/components/gameinventory/GameInventoryMVP.java (100%) diff --git a/GameInventoryMVP.java b/src/components/gameinventory/GameInventoryMVP.java similarity index 100% rename from GameInventoryMVP.java rename to src/components/gameinventory/GameInventoryMVP.java From 29f33bf2d9061477b8e7d5d09aa7822c57381841 Mon Sep 17 00:00:00 2001 From: UditDewan Date: Sat, 25 Apr 2026 00:23:13 -0400 Subject: [PATCH 12/12] Rename GameInventorySecondary.java to src/components/gameinventory/GameInventorySecondary.java --- .../components/gameinventory/GameInventorySecondary.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GameInventorySecondary.java => src/components/gameinventory/GameInventorySecondary.java (100%) diff --git a/GameInventorySecondary.java b/src/components/gameinventory/GameInventorySecondary.java similarity index 100% rename from GameInventorySecondary.java rename to src/components/gameinventory/GameInventorySecondary.java