iPuzzle/js/puzzle/GroupManager.js

100 lines
2.7 KiB
JavaScript

class GroupManager {
constructor() {
this.groups = new Map(); // groupId -> Set<pieceId>
this.pieceToGroup = new Map(); // pieceId -> groupId
this._nextId = 1;
}
createSingletonGroup(pieceId) {
const gid = this._nextId++;
this.groups.set(gid, new Set([pieceId]));
this.pieceToGroup.set(pieceId, gid);
return gid;
}
getGroupId(pieceId) {
return this.pieceToGroup.get(pieceId) ?? null;
}
/** Returns the Set<pieceId> for the group containing pieceId, or null. */
getGroup(pieceId) {
const gid = this.getGroupId(pieceId);
if (gid === null) return null;
return this.groups.get(gid) ?? null;
}
/** Returns all piece IDs in the same group as pieceId (including itself). */
getPeersOf(pieceId) {
return this.getGroup(pieceId) ?? new Set([pieceId]);
}
/**
* Merge the groups containing pieceIdA and pieceIdB into a single new group.
* @returns {number} the new group ID
*/
merge(pieceIdA, pieceIdB) {
const gidA = this.getGroupId(pieceIdA);
const gidB = this.getGroupId(pieceIdB);
if (gidA === null || gidB === null) return gidA ?? gidB;
if (gidA === gidB) return gidA; // already in the same group
const newGid = this._nextId++;
const members = new Set([...this.groups.get(gidA), ...this.groups.get(gidB)]);
this.groups.delete(gidA);
this.groups.delete(gidB);
this.groups.set(newGid, members);
members.forEach(id => this.pieceToGroup.set(id, newGid));
return newGid;
}
/** Total number of distinct locked groups. */
get groupCount() {
return this.groups.size;
}
/** Total number of tracked pieces. */
get pieceCount() {
return this.pieceToGroup.size;
}
/**
* Serialize to a plain array of arrays for localStorage.
* @returns {number[][]}
*/
serialize() {
return Array.from(this.groups.values()).map(set => Array.from(set));
}
/**
* Replace all internal state from a serialized groups array.
* Used for applying remote state updates.
* @param {number[][]} groupsList
*/
rebuildFromGroups(groupsList) {
this.groups.clear();
this.pieceToGroup.clear();
this._nextId = 1;
groupsList.forEach(members => {
const gid = this._nextId++;
const set = new Set(members);
this.groups.set(gid, set);
members.forEach(id => this.pieceToGroup.set(id, gid));
});
}
/**
* Rebuild from serialized data.
* @param {number[][]} groupsList
*/
static deserialize(groupsList) {
const gm = new GroupManager();
groupsList.forEach(members => {
const gid = gm._nextId++;
const set = new Set(members);
gm.groups.set(gid, set);
members.forEach(id => gm.pieceToGroup.set(id, gid));
});
return gm;
}
}