'use strict' class Cartographer { constructor () {} start () { const nodeData = new Map() this.propagateFrom(nodeData, "fa") this.matchEdges(nodeData) const dataByDepth = Array.from(nodeData.values()) dataByDepth.sort((p, q) => { if (p.depth != q.depth) { return p.depth - q.depth } return p.from - q.from }) nodeData.get("fa").solved = true nodeData.get("ea").position.x = 10 nodeData.get("ea").solved = true // Entente entrance nodeData.get("eq").position.y = 10 nodeData.get("eq").solved = true // Entente exit const unsolved = this.solve(nodeData, dataByDepth) for (const datum of unsolved) { console.log('Unsolved:', datum) } const colors = new Map([ [Zone.forest, '#FF0000'], [Zone.studio, '#FF8000'], [Zone.circular, '#FFFF00'], [Zone.stones, '#00FF00'], [Zone.rainre, '#00FFFF'], [Zone.antechannel, '#0000FF'], [Zone.metamondst, '#FF00FF'], [Zone.capsule, '#808080'], [Zone.nataniev, '#C0C0C0'], [Zone.entente, '#FFFFFF'] ]) const nodeOutput = [] const edgeOutput = [] for (const datum of nodeData.values()) { nodeOutput.push( `
${ datum.nodeID }${ datum.nodeID }
${datum .position.x * 60}${datum .position.y * 60}30.030.0rectangle${colors.get( datum.zone )}
14
` ) for (const edge of datum.edges) { edgeOutput.push( `
${ edge.from }${ edge.to }
#000000standard
0.00.0
` ) } } const outputPrefix = `
1` const outputSuffix = `
` const output = outputPrefix + nodeOutput.join('\n\t\t') + '\n\n\t\t' + edgeOutput.join('\n\t\t') + outputSuffix console.clear() console.log(output) } matchEdges (nodeData) { let edgeID = 0 for (const datum of nodeData.values()) { for (const edge of datum.edges) { if (edge.id == null) { edge.id = edgeID++ } } } for (const datum of nodeData.values()) { for (const edge of datum.edges) { if (edge.match == null) { const otherDatum = nodeData.get(edge.to) for (const otherEdge of otherDatum.edges) { if (otherEdge.match == null && otherEdge.to == datum.nodeID) { edge.match = otherEdge.id otherEdge.match = edge.id } } } } } } solve (nodeData, dataByDepth) { const unsolved = [] for (const datum of dataByDepth) { datum.edges.sort( function (p, q) { const pZoneDiff = nodeData.get(p.to).zone == datum.zone ? 0 : 1 const qZoneDiff = nodeData.get(q.to).zone == datum.zone ? 0 : 1 if (pZoneDiff != qZoneDiff) { return pZoneDiff - qZoneDiff } const pDiff = (p.toOrientation - p.fromOrientation + 8) % 4 const qDiff = (p.toOrientation - p.fromOrientation + 8) % 4 if (pDiff != qDiff) { return pDiff - qDiff } if (p.priority != q.priority) { return p.priority - q.priority } return nodeData.get(p.to).depth - nodeData.get(q.to).depth } ) const edges = datum.edges.filter( function (edge) { const toDatum = nodeData.get(edge.to) return toDatum.solved && toDatum.depth < datum.depth } ) for (const edge of edges) { if (nodeData.get(edge.to).depth < datum.depth) { datum.solved = true this.deriveNodeSpace(datum, nodeData.get(edge.to), edge) break } } if (!datum.solved) { unsolved.push(datum) } } return unsolved } deriveNodeSpace (datum, otherDatum, edge) { datum.position.x = otherDatum.position.x datum.position.y = otherDatum.position.y const toOrientation = (edge.toOrientation + otherDatum.heading) % 4 const fromOrientation = edge.fromOrientation datum.heading = (fromOrientation - toOrientation + 4) % 4 switch (toOrientation) { case 0: datum.position.y++ break case 1: datum.position.x-- break case 2: datum.position.y-- break case 3: datum.position.x++ break } } propagateFrom (nodeData, nodeID, depth = 0) { const recordEdge = ( from, fromOrientation, to, toField, toOrientationField, priority, puzzleID = null ) => { return { from, fromOrientation, to: to[toField], toOrientation: to[toOrientationField] == null ? fromOrientation : to[toOrientationField], priority, puzzleID, match: null } } const node = nodesByID.get(nodeID) if (nodeData.has(nodeID)) { return } const datum = { nodeID, zone: node.zone, depth, solved: false, position: { x: 0, y: 0 }, heading: 0, edges: [] } nodeData.set(nodeID, datum) const neighborIDs = new Set() for (let i = 0; i < 4; i++) { const subject = node.subjects[i] if (subject.mapIgnore) { continue } if (subject.nodeID != null) { datum.edges.push( recordEdge( nodeID, i, subject, 'nodeID', 'orientation', subject.type == SubjectType.node ? 1 : 2, subject.puzzleID ) ) neighborIDs.add(subject.nodeID) } if (subject.alternateNodeID != null) { datum.edges.push( recordEdge( nodeID, i, subject, 'alternateNodeID', 'alternateOrientation', 3, subject.puzzleID ) ) neighborIDs.add(subject.alternateNodeID) } } for (const id of neighborIDs.keys()) { this.propagateFrom(nodeData, id, depth + 1) } } }