-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGameInventorySecondary.java
More file actions
193 lines (173 loc) · 6.66 KB
/
Copy pathGameInventorySecondary.java
File metadata and controls
193 lines (173 loc) · 6.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package components.gameinventory;
import java.util.Iterator;
/**
* {@code GameInventorySecondary} is a layered implementation of the secondary
* methods of {@link GameInventory}.
*
* <p>
* Every method in this class is implemented using only the kernel methods
* ({@code addItem}, {@code removeItem}, {@code getQuantity}, {@code size}) and
* the iteration provided by {@code Iterable<String>}. The abstract class does
* not know or depend on the underlying representation, so a concrete
* implementation (e.g. {@code GameInventory1L}) need only implement the kernel
* methods and the {@code Standard} methods ({@code newInstance}, {@code clear},
* {@code transferFrom}).
* </p>
*
* @author (your name)
*/
public abstract class GameInventorySecondary implements GameInventory {
/*
* Common methods (from Object) --------------------------------------------
*/
/**
* Returns a string representation of this inventory in the form
* {@code {item1=qty1, item2=qty2, ...}}. Items appear in iterator order.
*
* @return a string representation of this inventory
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
boolean first = true;
for (String item : this) {
if (!first) {
sb.append(", ");
}
// Iterator yields item names that are in domain(this), so by the
// inventory invariant |item| > 0. getQuantity's precondition holds.
sb.append(item).append("=").append(this.getQuantity(item));
first = false;
}
sb.append("}");
return sb.toString();
}
/**
* Two inventories are equal iff they contain exactly the same items with
* exactly the same quantities.
*
* @param obj
* the object to compare with
* @return true iff {@code obj} is a {@code GameInventory} with the same
* contents as this
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof GameInventory)) {
return false;
}
GameInventory other = (GameInventory) obj;
// size() has no precondition, so this is always safe.
if (this.size() != other.size()) {
return false;
}
// Since both sizes are equal, if every item of this has a matching
// quantity in other, the two are equal.
for (String item : this) {
// |item| > 0 by the inventory invariant (this's iterator). That
// also satisfies other.getQuantity's precondition (|item| > 0).
if (this.getQuantity(item) != other.getQuantity(item)) {
return false;
}
}
return true;
}
/**
* Hash code that is consistent with {@link #equals(Object)}: equal
* inventories produce equal hash codes.
*
* @return a hash code for this inventory
*/
@Override
public int hashCode() {
int hash = 0;
for (String item : this) {
// Order-independent: two equal inventories iterate in possibly
// different orders but produce the same sum.
// |item| > 0 by the iterator invariant, so getQuantity is safe.
hash += item.hashCode() * this.getQuantity(item);
}
return hash;
}
/*
* Secondary methods (from GameInventory) ----------------------------------
*/
@Override
public final boolean hasItem(String item) {
assert item != null : "Violation of: item is not null";
assert item.length() > 0 : "Violation of: |item| > 0";
// getQuantity precondition |item| > 0 satisfied by assertion above.
return this.getQuantity(item) > 0;
}
@Override
public final int totalItems() {
int total = 0;
for (String item : this) {
// |item| > 0 by inventory invariant (iterator only yields items
// currently in this inventory).
total += this.getQuantity(item);
}
return total;
}
@Override
public final String mostAbundantItem() {
assert this.size() > 0 : "Violation of: |domain(this)| > 0";
String best = null;
int bestQty = 0;
for (String item : this) {
// |item| > 0 by iterator invariant, so getQuantity is safe.
int qty = this.getQuantity(item);
if (best == null || qty > bestQty) {
best = item;
bestQty = qty;
}
}
// Loop executed at least once because size() > 0, so best != null.
return best;
}
@Override
public final void transferItem(GameInventory other, String item,
int quantity) {
assert other != null : "Violation of: other is not null";
assert other != this : "Violation of: other /= this";
assert item != null : "Violation of: item is not null";
assert item.length() > 0 : "Violation of: |item| > 0";
assert quantity > 0 : "Violation of: quantity > 0";
assert this.getQuantity(item) >= quantity
: "Violation of: quantity <= this[item]";
// removeItem preconditions: |item| > 0 (asserted), quantity > 0
// (asserted), quantity <= this[item] (asserted). All satisfied.
this.removeItem(item, quantity);
// addItem preconditions: |item| > 0 (asserted) and quantity > 0
// (asserted). Both satisfied.
other.addItem(item, quantity);
}
@Override
public final void mergeFrom(GameInventory source) {
assert source != null : "Violation of: source is not null";
assert source != this : "Violation of: source /= this";
/*
* Drain source one item at a time. We cannot iterate source while also
* removing from it (the iterator would be invalidated), so we grab a
* fresh iterator each pass, pull one name, then remove it entirely
* from source and add it to this.
*/
while (source.size() > 0) {
Iterator<String> it = source.iterator();
String item = it.next();
// |item| > 0 by source's inventory invariant.
int qty = source.getQuantity(item);
// removeItem preconditions: |item| > 0 (invariant), qty > 0 (by
// inventory invariant: every present item has quantity > 0), and
// qty <= source[item] because qty IS source[item].
source.removeItem(item, qty);
// addItem preconditions: |item| > 0 (invariant) and qty > 0
// (invariant). Both satisfied.
this.addItem(item, qty);
}
}
}