add engine
This commit is contained in:
parent
67c7cf242a
commit
5552949d71
5
engine/deno.json
Normal file
5
engine/deno.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"fmt": {
|
||||||
|
"indentWidth": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
210
engine/src/circuit.ts
Normal file
210
engine/src/circuit.ts
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
export class Circuit {
|
||||||
|
constructor(
|
||||||
|
private comps: Component[],
|
||||||
|
private inputComps: Component[],
|
||||||
|
private pins: Pin[],
|
||||||
|
private pinConsumers: Map<Pin, Component[]>,
|
||||||
|
private pinInCount: number,
|
||||||
|
private pinOutCount: number,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
createState(): State {
|
||||||
|
return new State(this.pins, this.pinInCount, this.pinOutCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulate(state: State) {
|
||||||
|
const queue: Component[] = [];
|
||||||
|
for (const comp of this.inputComps) {
|
||||||
|
queue.push(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queue.length) {
|
||||||
|
const comp = queue.shift()!;
|
||||||
|
comp.simulate(state);
|
||||||
|
|
||||||
|
for (const pin of comp.outputs) {
|
||||||
|
queue.push(...this.pinConsumers.get(pin)!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Component {
|
||||||
|
constructor(
|
||||||
|
public kind: ComponentKind,
|
||||||
|
public inputs: (Pin | null)[],
|
||||||
|
public outputs: Pin[],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
simulate(state: State) {
|
||||||
|
const k = this.kind;
|
||||||
|
switch (k.tag) {
|
||||||
|
case "PinIn": {
|
||||||
|
state.setPin(this.outputs[0], state.getIn(k.idx));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "PinOut": {
|
||||||
|
state.setOut(k.idx, state.getPin(this.inputs[0]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Nand": {
|
||||||
|
const lhs = state.getPin(this.inputs[0]);
|
||||||
|
const rhs = state.getPin(this.inputs[1]);
|
||||||
|
state.setPin(
|
||||||
|
this.outputs[0],
|
||||||
|
!(lhs && rhs),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`not handled (${k})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ComponentKind =
|
||||||
|
| { tag: "PinIn" | "PinOut"; idx: number }
|
||||||
|
| { tag: "Nand" };
|
||||||
|
|
||||||
|
export class Pin {
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class State {
|
||||||
|
private pinsHigh = new Set<Pin>();
|
||||||
|
private pinsInHigh = new Set<number>();
|
||||||
|
private pinsOutHigh = new Set<number>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private pins: Pin[],
|
||||||
|
private pinInCount: number,
|
||||||
|
private pinOutCount: number,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
getPin(pin: Pin | null): boolean {
|
||||||
|
return pin !== null && this.pinsHigh.has(pin);
|
||||||
|
}
|
||||||
|
setPin(pin: Pin, value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
this.pinsHigh.add(pin);
|
||||||
|
} else {
|
||||||
|
this.pinsHigh.delete(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIn(idx: number): boolean {
|
||||||
|
return this.pinsInHigh.has(idx);
|
||||||
|
}
|
||||||
|
setIn(idx: number, value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
this.pinsInHigh.add(idx);
|
||||||
|
} else {
|
||||||
|
this.pinsInHigh.delete(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getOut(idx: number): boolean {
|
||||||
|
return this.pinsOutHigh.has(idx);
|
||||||
|
}
|
||||||
|
setOut(idx: number, value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
this.pinsOutHigh.add(idx);
|
||||||
|
} else {
|
||||||
|
this.pinsOutHigh.delete(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prettyPrint() {
|
||||||
|
console.log(
|
||||||
|
`inputs: [${
|
||||||
|
new Array(this.pinInCount)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => this.pinsInHigh.has(i) ? 1 : 0)
|
||||||
|
.map((v) => v.toString())
|
||||||
|
.join(", ")
|
||||||
|
}]`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`outputs: [${
|
||||||
|
new Array(this.pinOutCount)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => this.pinsOutHigh.has(i) ? 1 : 0)
|
||||||
|
.map((v) => v.toString())
|
||||||
|
.join(", ")
|
||||||
|
}]`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`state: [${
|
||||||
|
new Array(this.pins.length)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => this.pinsHigh.has(this.pins[i]) ? 1 : 0)
|
||||||
|
.map((v) => v.toString())
|
||||||
|
.join(", ")
|
||||||
|
}]`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CircuitBuilder {
|
||||||
|
private comps: Component[] = [];
|
||||||
|
private inputComps: Component[] = [];
|
||||||
|
private pins: Pin[] = [];
|
||||||
|
private pinInCount = 0;
|
||||||
|
private pinOutCount = 0;
|
||||||
|
|
||||||
|
build(): Circuit {
|
||||||
|
const pinConsumers = new Map<Pin, Component[]>();
|
||||||
|
|
||||||
|
for (const pin of this.pins) {
|
||||||
|
pinConsumers.set(pin, []);
|
||||||
|
}
|
||||||
|
for (const comp of this.comps) {
|
||||||
|
for (const pin of comp.inputs) {
|
||||||
|
if (!pin) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pinConsumers.get(pin)!.push(comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Circuit(
|
||||||
|
this.comps,
|
||||||
|
this.inputComps,
|
||||||
|
this.pins,
|
||||||
|
pinConsumers,
|
||||||
|
this.pinInCount,
|
||||||
|
this.pinOutCount,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPinIn(): Component {
|
||||||
|
const idx = this.pinInCount;
|
||||||
|
this.pinInCount += 1;
|
||||||
|
const comp = this.addComponent({ tag: "PinIn", idx }, 0, 1);
|
||||||
|
this.inputComps.push(comp);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPinOut(): Component {
|
||||||
|
const idx = this.pinOutCount;
|
||||||
|
this.pinOutCount += 1;
|
||||||
|
return this.addComponent({ tag: "PinOut", idx }, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
addNand(): Component {
|
||||||
|
return this.addComponent({ tag: "Nand" }, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addComponent(
|
||||||
|
kind: ComponentKind,
|
||||||
|
inputCount: number,
|
||||||
|
outputCount: number,
|
||||||
|
) {
|
||||||
|
const inputs = new Array(inputCount).fill(null);
|
||||||
|
const outputs = new Array(outputCount).fill(0).map(() => new Pin());
|
||||||
|
const comp = new Component(kind, inputs, outputs);
|
||||||
|
this.comps.push(comp);
|
||||||
|
this.pins.push(...outputs);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
engine/src/main.ts
Normal file
30
engine/src/main.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { CircuitBuilder } from "./circuit.ts";
|
||||||
|
|
||||||
|
const builder = new CircuitBuilder();
|
||||||
|
|
||||||
|
const i0 = builder.addPinIn();
|
||||||
|
const i1 = builder.addPinIn();
|
||||||
|
const o0 = builder.addPinOut();
|
||||||
|
|
||||||
|
const and = builder.addNand();
|
||||||
|
|
||||||
|
and.inputs[0] = i0.outputs[0];
|
||||||
|
and.inputs[1] = i1.outputs[0];
|
||||||
|
|
||||||
|
o0.inputs[0] = and.outputs[0];
|
||||||
|
|
||||||
|
const circuit = builder.build();
|
||||||
|
|
||||||
|
const state = circuit.createState();
|
||||||
|
|
||||||
|
state.setIn(0, true);
|
||||||
|
state.setIn(1, true);
|
||||||
|
|
||||||
|
console.log("-- before --");
|
||||||
|
state.prettyPrint();
|
||||||
|
|
||||||
|
circuit.simulate(state);
|
||||||
|
|
||||||
|
console.log("-- after --");
|
||||||
|
state.prettyPrint();
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user