Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
227 changes: 143 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
@@ -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<GameInventory> Iterable<String>
\ /
\ /
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<GameInventory>`: `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<String, Integer>` 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

<!-- TODO: use GitHub to create a repo from this template -->

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

<!-- TODO: install recommended plugins and delete this comment -->

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

<!-- TODO: install latest JDK and delete this comment -->

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

<!-- TODO: add key libraries to project and delete this comment -->

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

<!-- TODO: navigate to part 1 of the portfolio project and delete this comment -->

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.
104 changes: 104 additions & 0 deletions reflection.md
Original file line number Diff line number Diff line change
@@ -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<String>`, 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.
Loading