UNPKG

akiha-circuit

Version:

Draws electric circuit diagram by ASCII art

1,199 lines (1,047 loc) 41.9 kB
/* * akiha-circuit * * Copyright (c) 2019 Yuichiro MORIGUCHI * * This software is released under the MIT License. * http://opensource.org/licenses/mit-license.php **/ var common = require("./akiha-common.js"); var returnMachine, undef = void 0, BOUND = -1, UP = { x:0, y:-1 }, RIGHT = { x:1, y:0 }, DOWN = { x:0, y:1 }, LEFT = { x:-1, y:0 }; function log(message) { //console.log(message); } function isNode(ch) { return ch !== BOUND && /[\*\+]/.test(ch); } function quadro(inputString) { var TURN = [UP, RIGHT, DOWN, LEFT], input = inputString.split(/\r\n|\r|\n/), i, j, xNow = 1, yNow = 1, direction = 0, maxLength = 0, cellMatrix = [], me; function drawBound(y) { var j; cellMatrix[y] = []; for(j = 0; j < maxLength; j++) { cellMatrix[y][j] = { ch: BOUND }; } cellMatrix[y][j + 1] = { ch: BOUND }; } for(i = 0; i < input.length; i++) { maxLength = maxLength < input[i].length ? input[i].length : maxLength; } maxLength += 2; for(i = 0; i < input.length; i++) { cellMatrix[i + 1] = []; cellMatrix[i + 1][0] = { ch: BOUND }; for(j = 0; j < maxLength - 2; j++) { cellMatrix[i + 1][j + 1] = { ch: j < input[i].length ? input[i].charAt(j) : ' ' }; } cellMatrix[i + 1][j + 1] = { ch: BOUND }; } drawBound(0); drawBound(i + 1); me = { getChar: function(xoffset, yoffset) { return me.get(xoffset, yoffset).ch; }, isWhitespace: function(xoffset, yoffset) { var ch = me.getChar(xoffset, yoffset); return ch === BOUND || /[ ]/.test(ch); }, get: function(xoffset, yoffset) { if(xoffset === undef || yoffset === undef) { return cellMatrix[yNow][xNow]; } else if(xNow + xoffset < 0 || xNow + xoffset >= maxLength || yNow + yoffset < 0 || yNow + yoffset >= cellMatrix.length) { return { ch: BOUND }; } else { return cellMatrix[yNow + yoffset][xNow + xoffset]; } }, getForward: function(offset) { return me.get(TURN[direction].x * offset, TURN[direction].y * offset); }, move: function(direction) { xNow += direction.x; yNow += direction.y; if(xNow < 0) { xNow = 0; } else if(xNow >= maxLength) { xNow = maxLength - 1; } if(yNow < 0) { yNow = 0; } else if(yNow >= cellMatrix.length) { yNow = cellMatrix.length - 1; } return me; }, moveForward: function() { return me.move(TURN[direction]); }, moveBackward: function() { return me.move(TURN[(direction + 2) % 4]); }, moveCrLf: function() { xNow = 1; return me.move(DOWN); }, moveInit: function() { xNow = yNow = 1; return me; }, direction: function(dir) { var i = 0; for(i = 0; i < TURN.length; i++) { if(TURN[i] === dir) { direction = i; return me; } } throw new Error("invaild direction"); }, getDirection: function() { return TURN[direction]; }, isDirectionHorizontal: function() { return me.getDirection() === LEFT || me.getDirection() === RIGHT; }, isDirectionVertical: function() { return me.getDirection() === UP || me.getDirection() === DOWN; }, turnRight: function() { direction++; if(direction >= 4) { direction = 0; } return me; }, turnLeft: function() { direction--; if(direction < 0) { direction = 3; } return me; }, getPosition: function() { return { x: xNow, y: yNow, direction: direction }; }, setPosition: function(position) { xNow = position.x; yNow = position.y; direction = position.direction; return me; }, loops: [], loopNew: function() { me.loops.push([]); return me; }, loopAdd: function() { var neighbor = 0; neighbor += me.isWhitespace(1, 0) ? 0 : 1; neighbor += me.isWhitespace(-1, 0) ? 0 : 1; neighbor += me.isWhitespace(0, 1) ? 0 : 1; neighbor += me.isWhitespace(0, -1) ? 0 : 1; me.loops[me.loops.length - 1].push({ x: xNow, y: yNow, neighbor: neighbor }); return me; }, loopAddSerial: function() { var l = me.loops[me.loops.length - 1]; l.push({ x: l[l.length - 1].x, y: l[l.length - 1].y, neighbor: l[l.length - 1].neighbor }); return me; }, loopRemove: function() { me.loops.pop(); return me; }, setVoltage: function(voltage) { var l = me.loops[me.loops.length - 1]; l[l.length - 1].voltage = voltage; }, getLoop: function() { var l = me.loops[me.loops.length - 1]; return l[l.length - 1]; }, isElementExist: function() { var l = me.loops[me.loops.length - 1], el = l[l.length - 1]; return el.resist !== undef || el.voltage !== undef || el.capacitance !== undef || el.inductance !== undef || el.voltageAC !== undef; } }; return me; } function CallMachine(machine, next) { if(next === null) { throw new Error("Null pointer Exception"); } this.machine = machine; this.next = next; } function ReturnMachine() {} var returnMachine = new ReturnMachine(); function engine(quadro, initMachine) { var state = [], machineResult, popState, i; if(initMachine.init === null) { throw new Error("Null pointer Exception"); } state.push({ state: initMachine.init, stateName: initMachine.name }); for(i = 0; state.length > 0; i++) { if(i > 100000) { throw new Error("Maybe Infinite Loop"); } else if(typeof state[state.length - 1].state !== "function") { throw new Error("Invaild state : " + JSON.stringify(state[state.length - 1])); } machineResult = state[state.length - 1].state(quadro); if(machineResult === null) { throw new Error("Null pointer Exception"); } else if(machineResult instanceof CallMachine) { state.push({ state: machineResult.machine.init, stateName: machineResult.machine.name, next: machineResult.next, position: quadro.getPosition() }); log("entering " + state[state.length - 1].stateName); } else if(machineResult instanceof ReturnMachine) { log("leaving " + state[state.length - 1].stateName); popState = state.pop(); if(state.length > 0) { state[state.length - 1].state = popState.next; } if(popState.position !== undef) { quadro.setPosition(popState.position); } } else { state[state.length - 1].state = machineResult; } } } function akiha(input) { var machineFindBorder = (function() { var me = { name: "findBorder", init: function(quadro) { if(isNode(quadro.getChar())) { return new CallMachine(machineScanBorder, me.halt); } else if(quadro.getChar() === BOUND) { quadro.moveCrLf(); return me.left; } else { quadro.move(RIGHT); return me.init; } }, left: function(quadro) { if(quadro.getChar() === BOUND) { throw new Error("No curcuit"); } else { return me.init; } }, halt: function(quadro) { return returnMachine; } }; return me; })(); var machineScanBorder = (function() { var machineDrawBorderAux = (function() { var me = { name: "drawBorderAux", init: function(quadro) { return new CallMachine(machineDrawBorderAux1(UP), me.down); }, down: function(quadro) { return new CallMachine(machineDrawBorderAux1(DOWN), me.left); }, left: function(quadro) { return new CallMachine(machineDrawBorderAux1(LEFT), me.right); }, right: function(quadro) { return new CallMachine(machineDrawBorderAux1(RIGHT), me.done); }, done: function(quadro) { return returnMachine; } }; return me; })(); function machineDrawBorderAux1(direction) { var me = { name: "drawBorderAux1", init: function(quadro) { if(quadro.getChar() === BOUND) { return returnMachine; } else { if(direction === UP || direction === DOWN) { quadro.get().borderAuxY = true; } else { quadro.get().borderAuxX = true; } quadro.move(direction); return me.init; } } }; return me; } var me = { name: "scanBorder", init: function(quadro) { quadro.direction(RIGHT); quadro.get().borderAuxStart = true; return new CallMachine(machineDrawBorderAux, me.initMove); }, initMove: function(quadro) { quadro.moveForward(); if(quadro.isWhitespace()) { throw new Error("Unclosed circuit"); } return me.move; }, move: function(quadro) { if(quadro.get().borderAuxStart) { return machineBorder.init; } else if(isNode(quadro.getChar())) { return new CallMachine(machineDrawBorderAux, me.turn); } else if(quadro.getChar() !== BOUND) { quadro.moveForward(); return me.move; } else { throw new Error("Unclosed circuit"); } }, turn: function(quadro) { quadro.turnLeft().moveForward(); if(!quadro.isWhitespace()) { return me.move; } quadro.moveBackward().turnRight().moveForward(); if(!quadro.isWhitespace()) { return me.move; } quadro.moveBackward().turnRight().moveForward(); if(!quadro.isWhitespace()) { return me.move; } throw new Error("Unclosed circuit"); } }; return me; })(); var machineBorder = (function() { var me = { name: "border", init: function(quadro) { quadro.moveInit(); return me.findStart; }, findStart: function(quadro) { if(quadro.get().borderAuxX && quadro.get().borderAuxY) { return me.drawBorder; } else if(quadro.getChar() === BOUND) { quadro.moveCrLf(); if(quadro.getChar() === BOUND) { throw new Error("internal error"); } return me.findStart; } else { quadro.move(RIGHT); return me.findStart; } }, drawBorder: function(quadro) { quadro.get().borderStart = true; quadro.get().border = true; quadro.get().borderX = true; quadro.get().borderY = true; quadro.get().borderUp = true; quadro.get().borderLeft = true; quadro.direction(RIGHT).moveForward(); return me.forward; }, forward: function(quadro) { var cell = quadro.get(); if(cell.borderStart) { return machineGrid.init; } else if(quadro.getChar() === BOUND) { quadro.moveBackward(); return me.turn; } else { cell.border = true; cell.borderX = cell.borderX || quadro.isDirectionHorizontal(); cell.borderY = cell.borderY || quadro.isDirectionVertical(); cell.borderUp = cell.borderUp || quadro.getDirection() === RIGHT; cell.borderLeft = cell.borderLeft || quadro.getDirection() === DOWN; quadro.moveForward(); return me.forward; } }, turn: function(quadro) { var cell = quadro.get(); if(cell.borderAuxX && cell.borderAuxY) { quadro.turnRight(); return me.forward; } else { cell.border = undef; cell.borderX = undef; cell.borderY = undef; cell.borderUp = undef; cell.borderLeft = undef; quadro.moveBackward(); return me.turn; } } }; return me; })(); var machineGrid = (function() { var me = { name: "grid", init: function(quadro) { return new CallMachine(machineGridDown1, me.scanCell); }, scanCell: function(quadro) { return new CallMachine(machineScanCell, me.halt); }, halt: function(quadro) { return returnMachine; } }; return me; })(); var machineGridDown1 = (function() { var me = { name: "gridDown1", init: function (quadro) { if(isNode(quadro.getChar())) { return new CallMachine(machineGridRight, me.next); } else if(!quadro.get().borderY) { return returnMachine; } else { quadro.move(DOWN); return me.init; } }, next: function(quadro) { quadro.move(DOWN); return me.init; } }; return me; })(); var machineGridRight = (function() { var me = { name: "gridRight", init: function(quadro) { quadro.get().gridX = true; if(isNode(quadro.getChar())) { return new CallMachine(machineGridVertical, me.initNext); } else { quadro.move(RIGHT); return me.init; } }, initNext: function(quadro) { quadro.move(RIGHT); return me.move; }, move: function(quadro) { quadro.get().gridX = true; if(isNode(quadro.getChar())) { return new CallMachine(machineGridVertical, me.next); } else if(quadro.get().borderY) { return returnMachine; } else { quadro.move(RIGHT); return me.move; } }, next: function(quadro) { if(quadro.get().borderY) { return returnMachine; } else { quadro.move(RIGHT); return me.move; } } }; return me; })(); var machineGridVertical = (function() { var me = { name: "gridVertical", init: function(quadro) { return new CallMachine(machineGridVerticalUp, me.next); }, next: function(quadro) { return new CallMachine(machineGridVerticalDown, me.end); }, end: function(quadro) { return returnMachine; } }; return me; })(); function makeMachineGridVertical(dir) { var me = { name: "gridVertical2", init: function(quadro) { quadro.get().gridY = true; if(isNode(quadro.getChar())) { return new CallMachine(machineGridHorizontal, me.next); } else if(quadro.get().borderX) { return returnMachine; } else { quadro.move(dir); return me.init; } }, next: function(quadro) { var cell = quadro.get(); if(cell.borderX && (cell.borderUp && dir === UP || !cell.borderUp && dir === DOWN)) { return returnMachine; } else { quadro.move(dir); return me.init; } } }; return me; } var machineGridVerticalUp = makeMachineGridVertical(UP); var machineGridVerticalDown = makeMachineGridVertical(DOWN); var machineGridHorizontal = (function() { var me = { name: "gridHorizontal", init: function(quadro) { return new CallMachine(machineGridHorizontalLeft, me.next); }, next: function(quadro) { return new CallMachine(machineGridHorizontalRight, me.end); }, end: function(quadro) { return returnMachine; } }; return me; })(); function makeMachineGridHorizontal(dir) { var me = { name: "gridHorizontal2", init: function(quadro) { quadro.get().gridX = true; if(quadro.get().borderY) { return returnMachine; } else { quadro.move(dir); return me.init; } } }; return me; } var machineGridHorizontalLeft = makeMachineGridHorizontal(LEFT); var machineGridHorizontalRight = makeMachineGridHorizontal(RIGHT); function makeMachineScanCell(machineAttrHorizontal, machineAttrVertical) { var machineScanDown = (function() { var me = { name: "scanDown", init: function(quadro) { return new CallMachine(machineScanRight, me.move); }, nextInit: function(quadro) { if(quadro.get().borderX) { return returnMachine; } else if(quadro.get().gridX && quadro.get().gridY) { return new CallMachine(machineScanRight, me.move); } else { quadro.move(DOWN); return me.nextInit; } }, move: function(quadro) { quadro.move(DOWN); return me.nextInit; } }; return me; })(); var machineScanRight = (function() { var me = { name: "scanRight", init: function(quadro) { var cell = quadro.get(); if(cell.cellScanned === RIGHT) { quadro.move(RIGHT); return me.move; } else if(isNode(quadro.getChar()) || !quadro.isWhitespace(1, 0)) { quadro.direction(RIGHT); return new CallMachine(machineScanCellClockwise, me.next); } else { quadro.move(RIGHT); return me.move; } }, move: function(quadro) { var cell = quadro.get(); if(cell.cellScanned === RIGHT) { return me.next; } else if(isNode(quadro.getChar()) && !quadro.isWhitespace(1, 0)) { quadro.direction(RIGHT); return new CallMachine(machineScanCellClockwise, me.next); } else { quadro.move(RIGHT); return me.next; } }, next: function(quadro) { if(quadro.get().cellScanned === RIGHT) { quadro.move(RIGHT); return me.next; } else { return me.next2; } }, next2: function(quadro) { if(quadro.get().borderY) { return returnMachine; } else { return me.move; } } }; return me; })(); var machineScanCellClockwise = (function() { var me = { name: "scanCellClockwise", init: function(quadro) { quadro.loopNew(); quadro.get().clockwiseBegin = true; return me.move; }, move: function(quadro) { if(isNode(quadro.getChar())) { quadro.loopAdd(); quadro.get().cellScanned = quadro.getDirection(); quadro.moveForward(); return me.node; } else { quadro.get().cellScanned = quadro.getDirection(); quadro.moveForward(); return me.move; } }, node: function(quadro) { if(isNode(quadro.getChar())) { if(quadro.get().clockwiseBegin) { quadro.get().clockwiseBegin = false; quadro.loopAdd(); return returnMachine; } quadro.turnRight().moveForward(); if(quadro.isWhitespace()) { quadro.moveBackward().turnLeft().moveForward(); if(quadro.isWhitespace()) { quadro.moveBackward().turnLeft().moveForward(); if(quadro.isWhitespace()) { quadro.loopRemove(); quadro.moveInit(); return me.noloop; } } quadro.moveBackward(); quadro.loopAdd(); quadro.get().cellScanned = quadro.getDirection(); quadro.moveForward(); return me.node; } else { quadro.moveBackward(); return me.move; } } else { if(/[<>^v]/.test(quadro.getChar()) && !quadro.elementDefined) { quadro.elementDefined = true; if(quadro.isElementExist()) { quadro.loopAddSerial(); } return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.resist = val; }), me.afterLabel); } else if(/[cm]/.test(quadro.getChar()) && !quadro.elementDefined) { quadro.elementDefined = true; if(quadro.isElementExist()) { quadro.loopAddSerial(); } return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.inductance = val; }), me.afterLabel); } else if(/[~]/.test(quadro.getChar()) && !quadro.elementDefined) { quadro.elementDefined = true; if(quadro.isElementExist()) { quadro.loopAddSerial(); } return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.voltageAC = val; }), me.afterLabel); } else if(quadro.isDirectionVertical() && quadro.getChar() === "-" && !quadro.elementDefined) { quadro.elementDefined = true; if(quadro.isElementExist()) { quadro.loopAddSerial(); } if(quadro.getForward(1).ch === " ") { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.capacitance = val; }), me.afterLabel); } else if(quadro.getChar(1, 0) === "-" || quadro.getChar(-1, 0) === "-") { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.voltage = val; }), me.afterLabel); } else { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.voltage = -val; }), me.afterLabel); } } else if(quadro.isDirectionHorizontal() && quadro.getChar() === "|" && !quadro.elementDefined) { quadro.elementDefined = true; if(quadro.isElementExist()) { quadro.loopAddSerial(); } if(quadro.getForward(1).ch === " ") { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.capacitance = val; }), me.afterLabel); } else if(quadro.getChar(0, 1) === "|" || quadro.getChar(0, -1) === "|") { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.voltage = val; }), me.afterLabel); } else { return new CallMachine(makeMachineScanLabel(quadro.getDirection(), function(loop, text, val) { loop.voltage = -val; }), me.afterLabel); } } else if((quadro.isDirectionVertical() && quadro.getChar() === "|") || (quadro.isDirectionHorizontal() && quadro.getChar() === "-")) { quadro.elementDefined = false; } quadro.get().cellScanned = quadro.getDirection(); quadro.moveForward(); return me.node; } }, noloop: function(quadro) { quadro.move(RIGHT); if(quadro.get().clockwiseBegin) { quadro.get().clockwiseBegin = undef; return returnMachine; } else if(quadro.getChar() === BOUND) { quadro.moveCrLf(); if(quadro.getChar() === BOUND) { throw new Error("internal error"); } quadro.move(LEFT); } return me.noloop; }, afterLabel: function(quadro) { quadro.get().cellScanned = quadro.getDirection(); quadro.moveForward(); return me.node; } }; return me; })(); function makeMachineScanLabel(direction, setFunction) { var labelChars = /[0-9A-Za-zΩµ\.]/, me; var machineScanLabelLeft = (function() { var me; me = { name: "scanLabelLeft", init: function(quadro) { quadro.move(UP); return me.scan; }, scan: function(quadro) { if((!quadro.isWhitespace() && quadro.get().gridX) || quadro.getChar() === BOUND) { throw new Error("No label"); } else if(labelChars.test(quadro.getChar())) { return me.findLabel; } else { quadro.move(LEFT); return me.scan; } }, findLabel: function(quadro) { if(quadro.getChar() === BOUND || !labelChars.test(quadro.getChar())) { quadro.move(RIGHT).move(UP); quadro.getLoop().text = ""; quadro.getLoop().name = ""; return me.findLabelUp; } else { quadro.move(LEFT); return me.findLabel; } }, findLabelUp: function(quadro) { if(quadro.getChar() === BOUND || !labelChars.test(quadro.getChar())) { quadro.move(DOWN); return me.readLabel; } else { return me.readName; } }, readName: function(quadro) { if(quadro.getChar() !== BOUND && labelChars.test(quadro.getChar())) { quadro.getLoop().name += quadro.getChar(); quadro.move(RIGHT); return me.readName; } else { quadro.move(LEFT); return me.readNameReturn; } }, readNameReturn: function(quadro) { if(quadro.getChar() !== BOUND && labelChars.test(quadro.getChar())) { quadro.move(LEFT); return me.readNameReturn; } else { quadro.move(RIGHT).move(DOWN); return me.readLabel; } }, readLabel: function(quadro) { var text, val; if(labelChars.test(quadro.getChar())) { quadro.getLoop().text += quadro.getChar(); quadro.move(RIGHT); return me.readLabel; } else { text = quadro.getLoop().text; val = common.convertEngineerUnit(text.replace(/([0-9]+(?:\.[0-9]+)?[kMGTmuµnp]?).*/, "$1")); setFunction(quadro.getLoop(), text, val); return returnMachine; } } }; return me; })(); function makeMachineScanLabelUpDown(direction) { var me; me = { name: "scanLabelUpDown", init: function(quadro) { if((!quadro.isWhitespace() && quadro.get().gridY) || quadro.getChar() === BOUND) { return returnMachine; } else if(labelChars.test(quadro.getChar())) { quadro.getLoop().text = ""; quadro.getLoop().name = ""; if(quadro.getChar(0, -1) !== BOUND && labelChars.test(quadro.getChar(0, -1))) { quadro.move(UP); return new CallMachine(machineReadLabelUpDownProp("name"), me.moveDown); } else if(quadro.getChar(0, 1) !== BOUND && labelChars.test(quadro.getChar(0, 1))) { return new CallMachine(machineReadLabelUpDownProp("name"), me.moveDown); } return machineReadLabelUpDown.init; } else { quadro.move(direction); return me.init; } }, moveDown: function(quadro) { quadro.move(DOWN); return machineReadLabelUpDown.init; } }; return me; } function machineReadLabelUpDownProp(prop) { var me; me = { name: "readLabelUpDown", init: function(quadro) { var text, val; if(labelChars.test(quadro.getChar()) && quadro.getChar() !== BOUND) { quadro.getLoop()[prop] += quadro.getChar(); quadro.move(RIGHT); return me.init; } else { text = quadro.getLoop()[prop]; if(prop === "text") { val = common.convertEngineerUnit(text.replace(/([0-9]+(?:\.[0-9]+)?[kMGTmuµnp]?).*/, "$1")); setFunction(quadro.getLoop(), text, val); } return returnMachine; } } }; return me; } var machineReadLabelUpDown = machineReadLabelUpDownProp("text"); var machineScanPolarity = (function() { var me; me = { name: "scanPolarity", init: function(quadro) { if(direction === RIGHT || direction === DOWN) { quadro.turnRight().moveForward().turnRight(); } else { quadro.turnLeft().moveForward().turnLeft(); } return me.scanNegative; }, scanNegative: function(quadro) { if(quadro.getChar() === "+") { quadro.getLoop().polarity = -1; return returnMachine; } else if((!quadro.isWhitespace() && (quadro.get().gridX || quadro.get().gridY)) || ((direction === LEFT || direction === RIGHT) && /[\-]/.test(quadro.getChar(0, -1))) || ((direction === UP || direction === DOWN) && /[\|]/.test(quadro.getChar(1, 0))) || quadro.getChar() === BOUND) { quadro.turnLeft().turnLeft().moveForward(); return me.scanPositive; } else { quadro.moveForward(); return me.scanNegative; } }, scanPositive: function(quadro) { if(quadro.getChar() === "+") { quadro.getLoop().polarity = 1; return returnMachine; } else if((!quadro.isWhitespace() && (quadro.get().gridX || quadro.get().gridY)) || ((direction === LEFT || direction === RIGHT) && /[\-]/.test(quadro.getChar(0, -1))) || ((direction === UP || direction === DOWN) && /[\|]/.test(quadro.getChar(1, 0))) || quadro.getChar() === BOUND) { quadro.getLoop().polarity = 0; return returnMachine; } else { quadro.moveForward(); return me.scanPositive; } } }; return me; })(); if(direction === LEFT || direction === RIGHT) { me = { name: "scanLabel", init: function(quadro) { return new CallMachine(machineScanPolarity, me.label); }, label: function(quadro) { return machineScanLabelLeft.init; } }; } else { me = { name: "scanLabel", init: function(quadro) { return new CallMachine(machineScanPolarity, me.label); }, label: function(quadro) { quadro.move(RIGHT); return new CallMachine(makeMachineScanLabelUpDown(UP), me.down); }, down: function(quadro) { if(quadro.getLoop().text !== undef) { return returnMachine; } else { return new CallMachine(makeMachineScanLabelUpDown(DOWN), me.after); } }, after: function(quadro) { if(quadro.getLoop().text !== undef) { return returnMachine; } else { throw new Error("No label"); } } }; } return me; } return machineScanDown; } var machineScanCell = makeMachineScanCell(); function relocateLoopNo(loops) { var i, j, noX = [], noY = [], loopsNew; function insert(array, val) { var i; for(i = 0; i < array.length; i++) { if(array[i] === val) { return; } else if(array[i] > val) { array.splice(i, 0, val); return; } } array.push(val); } function getIndex(array, val) { var i; for(i = 0; i < array.length; i++) { if(array[i] === val) { return i; } } throw new Error("internal error"); } loopsNew = common.deepcopy(loops); for(i = 0; i < loops.length; i++) { for(j = 0; j < loops[i].length; j++) { insert(noX, loops[i][j].x); insert(noY, loops[i][j].y); } } for(i = 0; i < loops.length; i++) { for(j = 0; j < loops[i].length; j++) { loopsNew[i][j].x = getIndex(noX, loops[i][j].x); loopsNew[i][j].y = getIndex(noY, loops[i][j].y); } } return { loops: loopsNew, xMaxNodes: noX.length, yMaxNodes: noY.length }; } var quadroObject = quadro(input); engine(quadroObject, machineFindBorder); return relocateLoopNo(quadroObject.loops); } module.exports = { parse: akiha };