/** * A hash map that associates a 'Massive'-object with a Vector3 (typically this is the force * exerted on the object). The number of key-value pairs is not limited. */ public class MassiveForceHashMap { private int size; private Massive[] keys; private Vector3[] values; /** * Initializes 'this' as an empty map. */ public MassiveForceHashMap() { this(16); } public MassiveForceHashMap(int capacity) { this.size = 0; this.keys = new Massive[capacity]; this.values = new Vector3[capacity]; } /** * Adds a new key-value association to this map. If the key already exists in this map, * the value is replaced and the old value is returned. Otherwise 'null' is returned. * Precondition: key != null. */ public Vector3 put(Massive key, Vector3 value) { if (size > keys.length / 2) doubleCapacity(); int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length; for (int i = 0; i < keys.length; i++) { int pos = (idx + i) % keys.length; if (values[pos] == null) { keys[pos] = key; values[pos] = value; size++; return null; } else if (keys[pos].equals(key)) { Vector3 old = values[pos]; values[pos] = value; return old; } } throw new RuntimeException(); } private void doubleCapacity() { Massive[] oldKeys = keys; Vector3[] oldValues = values; keys = new Massive[keys.length * 2]; values = new Vector3[values.length * 2]; size = 0; for (int i = 0; i < oldKeys.length; i++) { Massive k = oldKeys[i]; Vector3 v = oldValues[i]; if (v != null) put(k, v); } } /** * Returns the value associated with the specified key, i.e. the method returns the force vector * associated with the specified key. Returns 'null' if the key is not contained in this map. * Precondition: key != null. */ public Vector3 get(Massive key) { int pos = find(key); return (pos == -1) ? null : values[pos]; } private int find(Massive key) { int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length; for (int i = 0; i < keys.length; i++) { int pos = (idx + i) % keys.length; if (keys[pos] == null) { break; } else if (keys[pos].equals(key)) { return pos; } } return -1; } /** * Deletes the mapping for the specified key from this map if present. * Returns the previous value associated with key, or null if there was * no mapping for key. * Precondition: key != null */ public Vector3 delete(Massive key) { int pos = find(key); if (pos == -1) return null; Vector3 val = values[pos]; values[pos] = null; return val; } /** * Returns 'true' if this map contains a mapping for the specified key. */ public boolean containsKey(Massive key) { return this.get(key) != null; } /** * Returns a readable representation of this map, with all key-value pairs. Their order is not * defined. */ @Override public String toString() { if (size == 0) return "{}"; StringBuilder sb = new StringBuilder("{"); for (int i = 0; i < keys.length; i++) { Massive k = keys[i]; Vector3 v = values[i]; if (k != null && v != null) { sb.append("\n "); sb.append(k); sb.append(": "); sb.append(v); sb.append(","); } } sb.deleteCharAt(sb.length() - 1); sb.append("\n}"); return sb.toString(); } /** * Compares `this` with the specified object for equality. Returns `true` if the specified * `o` is not `null` and is of type `MassiveForceHashMap` and both `this` and `o` have equal * key-value pairs, i.e. the number of key-value pairs is the same in both maps and every * key-value pair in `this` equals one key-value pair in `o`. Two key-value pairs are * equal if the two keys are equal and the two values are equal. Otherwise, `false` is returned. */ @Override public boolean equals(Object o) { if (!(o instanceof MassiveForceHashMap map) || map.size != size) return false; for (int i = 0; i < keys.length; i++) { Massive k1 = keys[i]; Vector3 v1 = values[i]; if (k1 == null || v1 == null) continue; Vector3 v2 = map.get(k1); if (!v1.equals(v2)) return false; } return true; } /** * Returns the hashCode of `this`. */ @Override public int hashCode() { int hash = 0; for (int i = 0; i < keys.length; i++) { Massive k = keys[i]; Vector3 v = values[i]; if (k == null || v == null) continue; hash ^= k.hashCode(); hash ^= v.hashCode(); } return hash; } /** * Returns a list of all the keys in no specified order. */ public MassiveLinkedList keyList() { MassiveLinkedList list = new MassiveLinkedList(); for (int i = 0; i < keys.length; i++) { if (keys[i] != null && values[i] != null) list.addLast(keys[i]); } return list; } }