├── .gitignore
├── README
├── examples
├── iccounter.txt
└── twodigitcounter.txt
├── images
├── and.png
├── arrdown.png
├── arrup.png
├── btnsmallleft.png
├── btnsmallleftover.png
├── btnsmallmid.png
├── btnsmallmidover.png
├── btnsmallright.png
├── btnsmallrightover.png
├── buffer.png
├── clock.png
├── constoff.png
├── conston.png
├── decoder.png
├── delete.png
├── delic.png
├── dflipflop.png
├── encoder.png
├── input.png
├── move.png
├── nand.png
├── newfile.png
├── newic.png
├── nor.png
├── not.png
├── open.png
├── or.png
├── outoff.png
├── outon.png
├── output.png
├── pushswitchaclosed.png
├── pushswitchaopen.png
├── pushswitchbclosed.png
├── pushswitchbopen.png
├── save.png
├── select.png
├── sepend.png
├── sepmid.png
├── sevsega.png
├── sevsegb.png
├── sevsegbase.png
├── sevsegc.png
├── sevsegd.png
├── sevsegdecoder.png
├── sevsegdp.png
├── sevsege.png
├── sevsegf.png
├── sevsegg.png
├── switchclosed.png
├── switchopen.png
├── xnor.png
└── xor.png
├── index.html
└── scripts
├── button.js
├── environment.js
├── gate.js
├── lz-string-1.3.3.js
├── main.js
├── saving.js
├── toolbar.js
├── tools.js
├── wire.js
└── wiregroup.js
/.gitignore:
--------------------------------------------------------------------------------
1 | */Thumbs.db
2 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/README
--------------------------------------------------------------------------------
/examples/iccounter.txt:
--------------------------------------------------------------------------------
1 | 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
--------------------------------------------------------------------------------
/examples/twodigitcounter.txt:
--------------------------------------------------------------------------------
1 | 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
--------------------------------------------------------------------------------
/images/and.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/and.png
--------------------------------------------------------------------------------
/images/arrdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/arrdown.png
--------------------------------------------------------------------------------
/images/arrup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/arrup.png
--------------------------------------------------------------------------------
/images/btnsmallleft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallleft.png
--------------------------------------------------------------------------------
/images/btnsmallleftover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallleftover.png
--------------------------------------------------------------------------------
/images/btnsmallmid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallmid.png
--------------------------------------------------------------------------------
/images/btnsmallmidover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallmidover.png
--------------------------------------------------------------------------------
/images/btnsmallright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallright.png
--------------------------------------------------------------------------------
/images/btnsmallrightover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/btnsmallrightover.png
--------------------------------------------------------------------------------
/images/buffer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/buffer.png
--------------------------------------------------------------------------------
/images/clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/clock.png
--------------------------------------------------------------------------------
/images/constoff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/constoff.png
--------------------------------------------------------------------------------
/images/conston.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/conston.png
--------------------------------------------------------------------------------
/images/decoder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/decoder.png
--------------------------------------------------------------------------------
/images/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/delete.png
--------------------------------------------------------------------------------
/images/delic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/delic.png
--------------------------------------------------------------------------------
/images/dflipflop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/dflipflop.png
--------------------------------------------------------------------------------
/images/encoder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/encoder.png
--------------------------------------------------------------------------------
/images/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/input.png
--------------------------------------------------------------------------------
/images/move.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/move.png
--------------------------------------------------------------------------------
/images/nand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/nand.png
--------------------------------------------------------------------------------
/images/newfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/newfile.png
--------------------------------------------------------------------------------
/images/newic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/newic.png
--------------------------------------------------------------------------------
/images/nor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/nor.png
--------------------------------------------------------------------------------
/images/not.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/not.png
--------------------------------------------------------------------------------
/images/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/open.png
--------------------------------------------------------------------------------
/images/or.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/or.png
--------------------------------------------------------------------------------
/images/outoff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/outoff.png
--------------------------------------------------------------------------------
/images/outon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/outon.png
--------------------------------------------------------------------------------
/images/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/output.png
--------------------------------------------------------------------------------
/images/pushswitchaclosed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/pushswitchaclosed.png
--------------------------------------------------------------------------------
/images/pushswitchaopen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/pushswitchaopen.png
--------------------------------------------------------------------------------
/images/pushswitchbclosed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/pushswitchbclosed.png
--------------------------------------------------------------------------------
/images/pushswitchbopen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/pushswitchbopen.png
--------------------------------------------------------------------------------
/images/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/save.png
--------------------------------------------------------------------------------
/images/select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/select.png
--------------------------------------------------------------------------------
/images/sepend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sepend.png
--------------------------------------------------------------------------------
/images/sepmid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sepmid.png
--------------------------------------------------------------------------------
/images/sevsega.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsega.png
--------------------------------------------------------------------------------
/images/sevsegb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegb.png
--------------------------------------------------------------------------------
/images/sevsegbase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegbase.png
--------------------------------------------------------------------------------
/images/sevsegc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegc.png
--------------------------------------------------------------------------------
/images/sevsegd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegd.png
--------------------------------------------------------------------------------
/images/sevsegdecoder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegdecoder.png
--------------------------------------------------------------------------------
/images/sevsegdp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegdp.png
--------------------------------------------------------------------------------
/images/sevsege.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsege.png
--------------------------------------------------------------------------------
/images/sevsegf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegf.png
--------------------------------------------------------------------------------
/images/sevsegg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/sevsegg.png
--------------------------------------------------------------------------------
/images/switchclosed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/switchclosed.png
--------------------------------------------------------------------------------
/images/switchopen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/switchopen.png
--------------------------------------------------------------------------------
/images/xnor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/xnor.png
--------------------------------------------------------------------------------
/images/xor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Metapyziks/Logic-Sim/9b30e553741f259808aa489cd32d91abddbe2377/images/xor.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LogicSim - Logic gate simulator
5 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/scripts/button.js:
--------------------------------------------------------------------------------
1 | Button = new Object();
2 | Button.images = new Object();
3 | Button.images.small = new Object();
4 | Button.images.small.up = new Object();
5 | Button.images.small.up.left = images.btnsmallleft;
6 | Button.images.small.up.mid = images.btnsmallmid;
7 | Button.images.small.up.right = images.btnsmallright;
8 | Button.images.small.over = new Object();
9 | Button.images.small.over.left = images.btnsmallleftover;
10 | Button.images.small.over.mid = images.btnsmallmidover;
11 | Button.images.small.over.right = images.btnsmallrightover;
12 |
13 | Button.Base = function(x, y, width, height, contents)
14 | {
15 | this.isButton = true;
16 |
17 | this.x = x;
18 | this.y = y;
19 | this.width = width;
20 | this.height = height;
21 |
22 | this.text = (typeof(contents) == "string" ? contents : "");
23 | this.image = (typeof(contents) == "string" ? null : contents);
24 |
25 | this.mouseOver = false;
26 | this.selected = false;
27 |
28 | this.isPositionOver = function(posX, posY)
29 | {
30 | return posX >= this.x && posY >= this.y
31 | && posX < this.x + this.width && posY < this.y + this.height;
32 | }
33 |
34 | this.mouseMove = function(mouseX, mouseY)
35 | {
36 | this.mouseOver = this.isPositionOver(mouseX, mouseY);
37 | }
38 |
39 | this.mouseDown = function(mouseX, mouseY)
40 | {
41 |
42 | }
43 |
44 | this.renderBack = function(context)
45 | {
46 | if (this.selected)
47 | {
48 | context.fillStyle = "#A0D1EF";
49 | context.fillRect(-4, -4, this.width + 8, this.height + 8);
50 | }
51 | }
52 |
53 | this.render = function(context)
54 | {
55 | context.translate(this.x, this.y);
56 |
57 | this.renderBack(context);
58 |
59 | if (this.image)
60 | {
61 | context.drawImage(this.image, (this.width - this.image.width) / 2,
62 | (this.height - this.image.height) / 2);
63 | }
64 | else if (this.text)
65 | {
66 | context.fillStyle = "#FFFFFF";
67 | context.font = "11px sans-serif";
68 | context.textAlign = "center";
69 | context.fillText(this.text, this.width / 2, 12);
70 | context.textAlign = "left";
71 | }
72 |
73 | context.translate(-this.x, -this.y);
74 | }
75 | }
76 |
77 | Button.Tool = function(image, mouseDown)
78 | {
79 | this.__proto__ = new Button.Base(0, 0, image.width, image.height, image);
80 | this.mouseDown = mouseDown;
81 | }
82 |
83 | Button.Small = function(x, y, width, contents)
84 | {
85 | this.upImages = [Button.images.small.up.left, Button.images.small.up.mid, Button.images.small.up.right];
86 | this.overImages = [Button.images.small.over.left, Button.images.small.over.mid, Button.images.small.over.right];
87 |
88 | this.__proto__ = new Button.Base(x, y, width, 16, contents);
89 |
90 | this.renderBack = function(context)
91 | {
92 | var imgs = this.mouseOver ? this.overImages : this.upImages;
93 |
94 | context.drawImage(imgs[0], 0, 0);
95 | context.fillStyle = context.createPattern(imgs[1], "repeat-x");
96 | context.fillRect(1, 0, this.width - 2, this.height);
97 | context.drawImage(imgs[2], this.width - 1, 0);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/scripts/environment.js:
--------------------------------------------------------------------------------
1 | function Environment()
2 | {
3 | this.gates = new Array();
4 | this.wireGroups = new Array();
5 |
6 | this.clear = function()
7 | {
8 | this.gates = new Array();
9 | this.wireGroups = new Array();
10 | }
11 |
12 | this.save = function()
13 | {
14 | var obj = { gates: [], wires: [] };
15 |
16 | for (var i = 0; i < this.gates.length; ++i)
17 | {
18 | var gate = this.gates[i];
19 | var gobj = {
20 | t: gate.type.ctorname,
21 | x: gate.x,
22 | y: gate.y,
23 | o: gate.getOutputs(),
24 | d: gate.saveData()
25 | };
26 |
27 | if (gobj.t == "CustomIC") {
28 | gobj.i = logicSim.customGroup.items.indexOf(gate.type);
29 | gobj.e = gate.environment.save();
30 | }
31 |
32 | obj.gates.push(gobj);
33 | }
34 |
35 | for (var i = 0; i < this.wireGroups.length; ++i)
36 | {
37 | var wires = this.wireGroups[i].getWires();
38 | for (var j = 0; j < wires.length; ++j)
39 | {
40 | var wire = wires[j];
41 | obj.wires.push({
42 | sx: wire.start.x,
43 | sy: wire.start.y,
44 | ex: wire.end.x,
45 | ey: wire.end.y
46 | });
47 | }
48 | }
49 |
50 | return obj;
51 | }
52 |
53 | this.load = function(obj, ics)
54 | {
55 | for (var i = 0; i < obj.gates.length; ++i)
56 | {
57 | var info = obj.gates[i];
58 | var gate = null;
59 |
60 | if (info.t == "CustomIC") {
61 | gate = new Gate(ics[info.i], info.x, info.y);
62 | var env = new Environment();
63 | env.load(info.e, ics);
64 | gate.environment = env;
65 | } else {
66 | var ctor = window[info.t];
67 | gate = new Gate(new ctor(), info.x, info.y);
68 | }
69 |
70 | this.placeGate(gate);
71 | gate.setOutputs(info.o);
72 | gate.loadData(info.d);
73 | }
74 |
75 | for (var i = 0; i < obj.wires.length; ++i)
76 | {
77 | var info = obj.wires[i];
78 | this.placeWire(new Pos(info.sx, info.sy), new Pos(info.ex, info.ey));
79 | }
80 | }
81 |
82 | this.clone = function()
83 | {
84 | var env = new Environment();
85 |
86 | for (var i = 0; i < this.gates.length; ++i) {
87 | env.placeGate(this.gates[i].clone());
88 | }
89 |
90 | var wires = this.getAllWires();
91 | for (var i = 0; i < wires.length; ++i) {
92 | env.placeWire(wires[i].start, wires[i].end);
93 | }
94 |
95 | return env;
96 | }
97 |
98 | var myIOSort = function (a, b) {
99 | if (a.y < b.y) return -1;
100 | if (a.y == b.y) return a.x < b.x ? -1 : a.x == b.x ? 0 : 1;
101 | return 1;
102 | }
103 |
104 | this.getInputs = function()
105 | {
106 | var inputs = new Array();
107 | for (var i = 0; i < this.gates.length; ++i) {
108 | var gate = this.gates[i];
109 | if (gate.type.ctorname == "ICInput") {
110 | inputs.push(gate);
111 | }
112 | }
113 |
114 | return inputs.sort(myIOSort);
115 | }
116 |
117 | this.getOutputs = function()
118 | {
119 | var outputs = new Array();
120 | for (var i = 0; i < this.gates.length; ++i) {
121 | var gate = this.gates[i];
122 | if (gate.type.ctorname == "ICOutput") {
123 | outputs.push(gate);
124 | }
125 | }
126 |
127 | return outputs.sort(myIOSort);
128 | }
129 |
130 | this.tryMerge = function(env, offset, selected, shallow)
131 | {
132 | if (offset == null) offset = new Pos(0, 0);
133 | if (selected == null) selected = false;
134 | if (shallow == null) shallow = false;
135 |
136 | for (var i = 0; i < env.gates.length; ++i) {
137 | var gate = env.gates[i].clone(shallow);
138 | gate.x += offset.x;
139 | gate.y += offset.y;
140 | gate.selected = selected;
141 | if (!this.canPlaceGate(gate)) return false;
142 | this.placeGate(gate);
143 | }
144 |
145 | var wires = env.getAllWires();
146 | for (var i = 0; i < wires.length; ++i) {
147 | var wire = wires[i];
148 | wire = new Wire(wire.start.add(offset), wire.end.add(offset));
149 | if (!this.canPlaceWire(wire)) return false;
150 | this.placeWire(wire.start, wire.end, selected);
151 | }
152 |
153 | return true;
154 | }
155 |
156 | this.getAllWires = function()
157 | {
158 | var wires = [];
159 | for (var i = this.wireGroups.length - 1; i >= 0; i--) {
160 | wires.pushMany(this.wireGroups[i].getWires());
161 | }
162 |
163 | return wires;
164 | }
165 |
166 | this.deselectAll = function()
167 | {
168 | for (var i = this.gates.length - 1; i >= 0; --i) {
169 | this.gates[i].selected = false;
170 | }
171 |
172 | var wires = this.getAllWires();
173 | for (var i = wires.length - 1; i >= 0; --i) {
174 | wires[i].selected = false;
175 | }
176 | }
177 |
178 | this.canPlaceGate = function(gate)
179 | {
180 | var rect = gate.getRect();
181 |
182 | if (rect.x < 256) return false;
183 |
184 | for (var i = 0; i < this.gates.length; ++i) {
185 | var other = this.gates[i].getRect();
186 |
187 | if (rect.intersects(other)) return false;
188 | }
189 |
190 | var crossed = false;
191 | for (var i = 0; i < this.wireGroups.length; ++ i) {
192 | var group = this.wireGroups[i];
193 | var wires = group.getWires();
194 |
195 | for (var j = 0; j < wires.length; ++ j) {
196 | var wire = wires[j];
197 | if (wire.start.x < rect.right && wire.end.x > rect.left
198 | && wire.start.y <= rect.bottom && wire.end.y >= rect.top)
199 | return false;
200 | }
201 |
202 | for (var j = 0; j < gate.outputs.length; ++ j) {
203 | var out = gate.outputs[j];
204 | if (group.crossesPos(out.getPosition(gate.type, gate.x, gate.y))) {
205 | if (crossed || group.input != null) return false;
206 |
207 | crossed = true;
208 | }
209 | }
210 | }
211 |
212 | return true;
213 | }
214 |
215 | this.placeGate = function(gate)
216 | {
217 | gate.unlinkAll();
218 |
219 | var r0 = gate.getRect(logicSim.getGridSize());
220 |
221 | for (var i = 0; i < this.gates.length; ++ i) {
222 | var other = this.gates[i];
223 | var r1 = other.getRect(logicSim.getGridSize());
224 |
225 | if (r0.left == r1.right || r1.left == r0.right
226 | || r0.top == r1.bottom || r1.top == r0.bottom) {
227 | for (var j = 0; j < gate.inputs.length; ++ j) {
228 | var inp = gate.inputs[j];
229 | for (var k = 0; k < other.outputs.length; ++ k) {
230 | var out = other.outputs[k];
231 |
232 | if (inp.getPosition(gate.type, gate.x, gate.y).equals(
233 | out.getPosition(other.type, other.x, other.y))) {
234 | gate.linkInput(other, out, inp);
235 | }
236 | }
237 | }
238 |
239 | for (var j = 0; j < gate.outputs.length; ++ j) {
240 | var out = gate.outputs[j];
241 | for (var k = 0; k < other.inputs.length; ++ k) {
242 | var inp = other.inputs[k];
243 |
244 | if (out.getPosition(gate.type, gate.x, gate.y).equals(
245 | inp.getPosition(other.type, other.x, other.y))) {
246 | other.linkInput(gate, out, inp);
247 | }
248 | }
249 | }
250 | }
251 | }
252 |
253 | for (var i = 0; i < this.wireGroups.length; ++ i) {
254 | var group = this.wireGroups[i];
255 |
256 | for (var j = 0; j < gate.inputs.length; ++ j) {
257 | var pos = gate.inputs[j].getPosition(gate.type, gate.x, gate.y);
258 |
259 | if (group.crossesPos(pos)) group.addOutput(gate, gate.inputs[j]);
260 | }
261 |
262 | for (var j = 0; j < gate.outputs.length; ++ j) {
263 | var pos = gate.outputs[j].getPosition(gate.type, gate.x, gate.y);
264 |
265 | if (group.crossesPos(pos)) group.setInput(gate, gate.outputs[j]);
266 | }
267 | }
268 |
269 | this.gates.push(gate);
270 | }
271 |
272 | this.removeGate = function(gate)
273 | {
274 | var index = this.gates.indexOf(gate);
275 | this.gates.splice(index, 1);
276 |
277 | for (var i = 0; i < this.gates.length; ++ i) {
278 | if (this.gates[i].isLinked(gate)) {
279 | this.gates[i].unlinkGate(gate);
280 | }
281 |
282 | if (gate.isLinked(this.gates[i])) {
283 | gate.unlinkGate(this.gates[i]);
284 | }
285 | }
286 |
287 | for (var i = 0; i < this.wireGroups.length; ++ i) {
288 | var group = this.wireGroups[i];
289 |
290 | if (group.input != null && group.input.gate == gate) {
291 | group.input = null;
292 | }
293 |
294 | for (var j = group.outputs.length - 1; j >= 0; -- j) {
295 | if (group.outputs[j].gate == gate) {
296 | group.outputs.splice(j, 1);
297 | }
298 | }
299 | }
300 | }
301 |
302 | this.canPlaceWire = function(wire)
303 | {
304 | var input = null;
305 |
306 | if (wire.start.x < 256) return false;
307 |
308 | for (var i = 0; i < this.wireGroups.length; ++ i) {
309 | var group = this.wireGroups[i];
310 |
311 | if (group.canAddWire(wire)) {
312 | if (wire.start.equals(wire.end)) return false;
313 |
314 | if (group.input != null) {
315 | if (input != null && !group.input.equals(input)) {
316 | return false;
317 | }
318 |
319 | input = group.input;
320 | }
321 | }
322 | }
323 |
324 | for (var i = 0; i < this.gates.length; ++ i) {
325 | var gate = this.gates[i];
326 | var rect = gate.getRect(logicSim.getGridSize());
327 |
328 | if (wire.start.x < rect.right && wire.end.x > rect.left
329 | && wire.start.y <= rect.bottom && wire.end.y >= rect.top) {
330 | return false;
331 | }
332 |
333 | if (wire.start.x == rect.right || rect.left == wire.end.x
334 | || wire.start.y == rect.bottom || rect.top == wire.end.y) {
335 | for (var j = 0; j < gate.outputs.length; ++ j) {
336 | var inp = new Link(gate, gate.outputs[j]);
337 | var pos = gate.outputs[j].getPosition(gate.type, gate.x, gate.y);
338 |
339 | if (wire.crossesPos(pos)) {
340 | if (input != null && !inp.equals(input)) return false;
341 |
342 | input = inp;
343 | }
344 | }
345 | }
346 | }
347 |
348 | return true;
349 | }
350 |
351 | this.placeWire = function(start, end, selected)
352 | {
353 | if (start.equals(end)) {
354 | return;
355 | }
356 |
357 | // Here we go...
358 |
359 | selected = selected != null ? true : false;
360 | var wire = new Wire(start, end);
361 | wire.selected = selected;
362 |
363 | var group = new WireGroup();
364 | group.addWire(wire);
365 |
366 | // Check for gate input / output intersections
367 | for (var i = 0; i < this.gates.length; ++ i) {
368 | var gate = this.gates[i];
369 | var rect = gate.getRect(logicSim.getGridSize());
370 |
371 | if (wire.start.x == rect.right || rect.left == wire.end.x
372 | || wire.start.y == rect.bottom || rect.top == wire.end.y) {
373 | for (var j = 0; j < gate.inputs.length; ++ j) {
374 | var pos = gate.inputs[j].getPosition(gate.type, gate.x, gate.y);
375 |
376 | if (wire.crossesPos(pos)) {
377 | wire.group.addOutput(gate, gate.inputs[j]);
378 | }
379 | }
380 |
381 | for (var j = 0; j < gate.outputs.length; ++ j) {
382 | var pos = gate.outputs[j].getPosition(gate.type, gate.x, gate.y);
383 |
384 | if (wire.crossesPos(pos)) {
385 | wire.group.setInput(gate, gate.outputs[j]);
386 | }
387 | }
388 | }
389 | }
390 |
391 | // Find all wire groups that are connected to the new wire, and
392 | // dump their wires, input and outputs into the new group
393 | var wires = null;
394 | for (var i = this.wireGroups.length - 1; i >= 0; -- i) {
395 | var oldGroup = this.wireGroups[i];
396 | if (oldGroup.canAddWire(wire)) {
397 | this.wireGroups.splice(i, 1);
398 |
399 | wires = oldGroup.getWires();
400 | for (var j = 0; j < wires.length; ++ j) {
401 | var newWire = new Wire(wires[j].start, wires[j].end);
402 | newWire.selected = wires[j].selected;
403 | group.addWire(newWire);
404 | }
405 |
406 | if (oldGroup.input != null) {
407 | group.setInput(oldGroup.input.gate, oldGroup.input.socket);
408 | }
409 |
410 | for (var j = 0; j < oldGroup.outputs.length; ++ j) {
411 | group.addOutput(oldGroup.outputs[j].gate, oldGroup.outputs[j].socket);
412 | }
413 | }
414 | }
415 |
416 | // Merge wires that run along eachother
417 | wires = group.getWires();
418 | for (var i = wires.length - 1; i >= 0; -- i) {
419 | var w = wires[i];
420 | for (var j = i - 1; j >= 0; -- j) {
421 | var other = wires[j];
422 |
423 | if (w.runsAlong(other)) {
424 | w.merge(other);
425 | wires.splice(j, 1);
426 | break;
427 | }
428 | }
429 | }
430 |
431 | // Split at intersections
432 | for (var i = 0; i < wires.length; ++ i) {
433 | var w = wires[i];
434 | for (var j = i + 1; j < wires.length; ++ j) {
435 | var other = wires[j];
436 |
437 | if (w.isHorizontal() == other.isHorizontal()) continue;
438 |
439 | if (w.intersects(other)) {
440 | wires.pushMany(w.split(other));
441 | wires.pushMany(other.split(w));
442 | }
443 | }
444 | }
445 |
446 | // Connect touching wires
447 | for (var i = 0; i < wires.length; ++ i) {
448 | var w = wires[i];
449 | for (var j = i + 1; j < wires.length; ++ j) {
450 | var other = wires[j];
451 |
452 | if (w.intersects(other)) {
453 | w.connect(other);
454 | other.connect(w);
455 | }
456 | }
457 | }
458 |
459 | // Add the new group to the environment
460 | this.wireGroups.push(group);
461 | }
462 |
463 | this.removeWire = function(wire)
464 | {
465 | this.removeWires([wire]);
466 | }
467 |
468 | this.removeWires = function(toRemove)
469 | {
470 | var survivors = new Array();
471 |
472 | for (var i = 0; i < toRemove.length; ++ i) {
473 | var group = toRemove[i].group;
474 | if (this.wireGroups.contains(group)) {
475 | var wires = group.getWires();
476 |
477 | for (var j = 0; j < wires.length; ++ j) {
478 | var w = wires[j];
479 | if (!toRemove.containsEqual(w)) {
480 | survivors.push({start: w.start, end: w.end});
481 | }
482 | }
483 |
484 | var gindex = this.wireGroups.indexOf(group);
485 | this.wireGroups.splice(gindex, 1);
486 | group.removeAllOutputs();
487 | }
488 | }
489 |
490 | for (var i = 0; i < survivors.length; ++ i) {
491 | this.placeWire(survivors[i].start, survivors[i].end);
492 | }
493 | }
494 |
495 | this.step = function()
496 | {
497 | for (var i = 0; i < this.gates.length; ++ i) {
498 | this.gates[i].step();
499 | }
500 |
501 | for (var i = 0; i < this.gates.length; ++ i) {
502 | this.gates[i].commit();
503 | }
504 | }
505 |
506 | this.render = function(context, offset, selectClr)
507 | {
508 | if (offset == null) {
509 | offset = new Pos(0, 0);
510 | }
511 |
512 | for (var i = 0; i < this.wireGroups.length; ++ i) {
513 | this.wireGroups[i].render(context, offset, selectClr);
514 | }
515 |
516 | for (var i = 0; i < this.gates.length; ++ i) {
517 | this.gates[i].render(context, offset, selectClr);
518 | }
519 | }
520 | }
521 |
--------------------------------------------------------------------------------
/scripts/gate.js:
--------------------------------------------------------------------------------
1 | SocketFace = new Object();
2 |
3 | SocketFace.left = "LEFT";
4 | SocketFace.top = "TOP";
5 | SocketFace.right = "RIGHT";
6 | SocketFace.bottom = "BOTTOM";
7 |
8 | function SocketInfo(face, offset, label)
9 | {
10 | this.face = face;
11 | this.offset = offset;
12 | this.label = label;
13 |
14 | this.isLeft = this.face == SocketFace.left;
15 | this.isTop = this.face == SocketFace.top;
16 | this.isRight = this.face == SocketFace.right;
17 | this.isBottom = this.face == SocketFace.bottom;
18 |
19 | this.getPosition = function(gateType, x, y)
20 | {
21 | return new Pos(
22 | x +
23 | ((this.face == SocketFace.left) ? 0
24 | : (this.face == SocketFace.right) ? gateType.width
25 | : this.offset * 8),
26 | y +
27 | ((this.face == SocketFace.top) ? 0
28 | : (this.face == SocketFace.bottom) ? gateType.height
29 | : this.offset * 8)
30 | );
31 | }
32 | }
33 |
34 | function GateType(name, width, height, inputs, outputs)
35 | {
36 | this.isGateType = true;
37 |
38 | this.name = name;
39 |
40 | this.width = width;
41 | this.height = height;
42 |
43 | this.inputs = inputs;
44 | this.outputs = outputs;
45 |
46 | this.func = function(gate, inputs)
47 | {
48 | return [false];
49 | }
50 |
51 | this.initialize = function(gate)
52 | {
53 |
54 | }
55 |
56 | this.click = function(gate)
57 | {
58 |
59 | }
60 |
61 | this.mouseDown = function(gate)
62 | {
63 |
64 | }
65 |
66 | this.mouseUp = function(gate)
67 | {
68 |
69 | }
70 |
71 | this.saveData = function(gate)
72 | {
73 | return null;
74 | }
75 |
76 | this.loadData = function(gate, data)
77 | {
78 |
79 | }
80 |
81 | this.render = function(context, x, y, gate)
82 | {
83 | context.strokeStyle = "#000000";
84 | context.lineWidth = 2;
85 |
86 | for (var i = 0; i < this.inputs.length + this.outputs.length; ++ i)
87 | {
88 | var inp = (i < this.inputs.length ? this.inputs[i] : this.outputs[i - this.inputs.length]);
89 | var start = inp.getPosition(this, x, y);
90 | var end = inp.getPosition(this, x, y);
91 |
92 | if (inp.face == SocketFace.left || inp.face == SocketFace.right)
93 | end.x = x + this.width / 2;
94 | else
95 | end.y = y + this.height / 2;
96 |
97 | context.beginPath();
98 | context.moveTo(start.x, start.y);
99 | context.lineTo(end.x, end.y);
100 | context.stroke();
101 | context.closePath();
102 | }
103 | }
104 | }
105 |
106 | function DefaultGate(name, image, renderOverride, inputs, outputs)
107 | {
108 | this.__proto__ = new GateType(name, image.width, image.height, inputs, outputs);
109 |
110 | this.ctorname = arguments.callee.caller.name;
111 |
112 | this.image = image;
113 | this.renderOverride = renderOverride;
114 |
115 | this.render = function(context, x, y, gate)
116 | {
117 | this.__proto__.render(context, x, y, gate);
118 | if (!this.renderOverride)
119 | context.drawImage(this.image, x, y);
120 | }
121 | }
122 |
123 | function CustomIC(name, environment)
124 | {
125 | var envInputs = environment.getInputs();
126 | var envOutputs = environment.getOutputs();
127 |
128 | var inputs = new Array();
129 | var outputs = new Array();
130 |
131 | this.ctorname = arguments.callee.name;
132 |
133 | this.environment = environment;
134 |
135 | for (var i = 0; i < envInputs.length; ++ i) {
136 | var input = envInputs[i];
137 | inputs[i] = new SocketInfo(SocketFace.left, 2 + i * 2, "I" + i)
138 | }
139 |
140 | for (var i = 0; i < envOutputs.length; ++ i) {
141 | var input = envOutputs[i];
142 | outputs[i] = new SocketInfo(SocketFace.right, 2 + i * 2, "O" + i)
143 | }
144 |
145 | this.__proto__ = new GateType(name, 64,
146 | Math.max(32, 16 * (Math.max(envInputs.length, envOutputs.length) + 1)),
147 | inputs, outputs);
148 |
149 | this.initialize = function(gate)
150 | {
151 | gate.environment = this.environment.clone();
152 | }
153 |
154 | this.func = function(gate, inputs)
155 | {
156 | var ins = gate.environment.getInputs();
157 | for (var i = 0; i < ins.length; ++ i) {
158 | ins[i].value = inputs[i];
159 | }
160 |
161 | gate.environment.step();
162 |
163 | var vals = new Array();
164 | var outs = gate.environment.getOutputs();
165 | for (var i = 0; i < outs.length; ++ i) {
166 | vals[i] = outs[i].value;
167 | }
168 |
169 | return vals;
170 | }
171 |
172 | this.render = function(context, x, y, gate)
173 | {
174 | this.__proto__.render(context, x, y, gate);
175 |
176 | context.strokeStyle = "#000000";
177 | context.fillStyle = "#ffffff";
178 | context.lineWidth = 3;
179 |
180 | context.beginPath();
181 | context.rect(x + 9.5, y + 1.5, this.width - 19, this.height - 3);
182 | context.fill();
183 | context.stroke();
184 | context.closePath();
185 |
186 | context.fillStyle = "#000000";
187 | context.font = "bold 16px sans-serif";
188 | context.textAlign = "center";
189 | context.textBaseline = "middle";
190 |
191 | var width = context.measureText(this.name).width;
192 |
193 | if (this.width - 16 > this.height) {
194 | context.fillText(this.name, x + this.width / 2, y + this.height / 2, this.width - 24);
195 | } else {
196 | context.save();
197 | context.translate(x + this.width / 2, y + this.height / 2);
198 | context.rotate(Math.PI / 2);
199 | context.fillText(this.name, 0, 0, this.height - 12);
200 | context.restore();
201 | }
202 |
203 | context.textAlign = "left";
204 | context.textBaseline = "alphabetic";
205 | }
206 | }
207 |
208 | function BufferGate()
209 | {
210 | this.__proto__ = new DefaultGate("BUF", images.buffer, false,
211 | [
212 | new SocketInfo(SocketFace.left, 2, "A")
213 | ],
214 | [
215 | new SocketInfo(SocketFace.right, 2, "Q")
216 | ]
217 | );
218 |
219 | this.func = function(gate, inputs)
220 | {
221 | return [inputs[0]];
222 | }
223 | }
224 |
225 | function AndGate()
226 | {
227 | this.__proto__ = new DefaultGate("AND", images.and, false,
228 | [
229 | new SocketInfo(SocketFace.left, 1, "A"),
230 | new SocketInfo(SocketFace.left, 3, "B")
231 | ],
232 | [
233 | new SocketInfo(SocketFace.right, 2, "Q")
234 | ]
235 | );
236 |
237 | this.func = function(gate, inputs)
238 | {
239 | return [inputs[0] && inputs[1]];
240 | }
241 | }
242 |
243 | function OrGate()
244 | {
245 | this.__proto__ = new DefaultGate("OR", images.or, false,
246 | [
247 | new SocketInfo(SocketFace.left, 1, "A"),
248 | new SocketInfo(SocketFace.left, 3, "B")
249 | ],
250 | [
251 | new SocketInfo(SocketFace.right, 2, "Q")
252 | ]
253 | );
254 |
255 | this.func = function(gate, inputs)
256 | {
257 | return [inputs[0] || inputs[1]];
258 | }
259 | }
260 |
261 | function XorGate()
262 | {
263 | this.__proto__ = new DefaultGate("XOR", images.xor, false,
264 | [
265 | new SocketInfo(SocketFace.left, 1, "A"),
266 | new SocketInfo(SocketFace.left, 3, "B")
267 | ],
268 | [
269 | new SocketInfo(SocketFace.right, 2, "Q")
270 | ]
271 | );
272 |
273 | this.func = function(gate, inputs)
274 | {
275 | return [inputs[0] ^ inputs[1]];
276 | }
277 | }
278 |
279 | function NotGate()
280 | {
281 | this.__proto__ = new DefaultGate("NOT", images.not, false,
282 | [
283 | new SocketInfo(SocketFace.left, 2, "A")
284 | ],
285 | [
286 | new SocketInfo(SocketFace.right, 2, "Q")
287 | ]
288 | );
289 |
290 | this.func = function(gate, inputs)
291 | {
292 | return [!inputs[0]];
293 | }
294 | }
295 |
296 | function NandGate()
297 | {
298 | this.__proto__ = new DefaultGate("NAND", images.nand, false,
299 | [
300 | new SocketInfo(SocketFace.left, 1, "A"),
301 | new SocketInfo(SocketFace.left, 3, "B")
302 | ],
303 | [
304 | new SocketInfo(SocketFace.right, 2, "Q")
305 | ]
306 | );
307 |
308 | this.func = function(gate, inputs)
309 | {
310 | return [!inputs[0] || !inputs[1]];
311 | }
312 | }
313 |
314 | function NorGate()
315 | {
316 | this.__proto__ = new DefaultGate("NOR", images.nor, false,
317 | [
318 | new SocketInfo(SocketFace.left, 1, "A"),
319 | new SocketInfo(SocketFace.left, 3, "B")
320 | ],
321 | [
322 | new SocketInfo(SocketFace.right, 2, "Q")
323 | ]
324 | );
325 |
326 | this.func = function(gate, inputs)
327 | {
328 | return [!inputs[0] && !inputs[1]];
329 | }
330 | }
331 |
332 | function XnorGate()
333 | {
334 | this.__proto__ = new DefaultGate("XNOR", images.xnor, false,
335 | [
336 | new SocketInfo(SocketFace.left, 1, "A"),
337 | new SocketInfo(SocketFace.left, 3, "B")
338 | ],
339 | [
340 | new SocketInfo(SocketFace.right, 2, "Q")
341 | ]
342 | );
343 |
344 | this.func = function(gate, inputs)
345 | {
346 | return [inputs[0] == inputs[1]];
347 | }
348 | }
349 |
350 | function ConstInput()
351 | {
352 | this.onImage = images.conston;
353 | this.offImage = images.constoff;
354 |
355 | this.__proto__ = new DefaultGate("IN", this.onImage, true, [],
356 | [
357 | new SocketInfo(SocketFace.right, 2, "Q")
358 | ]
359 | );
360 |
361 | this.initialize = function(gate)
362 | {
363 | gate.on = true;
364 | }
365 |
366 | this.click = function(gate)
367 | {
368 | gate.on = !gate.on;
369 | }
370 |
371 | this.func = function(gate, inputs)
372 | {
373 | return [gate.on];
374 | }
375 |
376 | this.saveData = function(gate)
377 | {
378 | return gate.on;
379 | }
380 |
381 | this.loadData = function(gate, data)
382 | {
383 | gate.on = data;
384 | }
385 |
386 | this.render = function(context, x, y, gate)
387 | {
388 | this.__proto__.render(context, x, y);
389 | context.drawImage(gate == null || gate.on ? this.onImage : this.offImage, x, y);
390 | }
391 | }
392 |
393 | function ClockInput()
394 | {
395 | this.__proto__ = new DefaultGate("CLOCK", images.clock, false, [],
396 | [
397 | new SocketInfo(SocketFace.right, 2, "Q")
398 | ]
399 | );
400 |
401 | this.func = function(gate, inputs)
402 | {
403 | var period = 1000 / gate.freq;
404 | return [new Date().getTime() % period >= period / 2];
405 | }
406 |
407 | this.initialize = function(gate)
408 | {
409 | gate.freq = 1;
410 | }
411 |
412 | this.saveData = function(gate)
413 | {
414 | return gate.freq;
415 | }
416 |
417 | this.loadData = function(gate, data)
418 | {
419 | gate.freq = data;
420 | }
421 |
422 | this.click = function(gate)
423 | {
424 | gate.freq *= 2;
425 |
426 | if (gate.freq >= 32)
427 | gate.freq = 0.125;
428 | }
429 | }
430 |
431 | function ToggleSwitch()
432 | {
433 | this.openImage = images.switchopen;
434 | this.closedImage = images.switchclosed;
435 |
436 | this.__proto__ = new DefaultGate("TSWITCH", this.openImage, true,
437 | [
438 | new SocketInfo(SocketFace.left, 2, "A"),
439 | ],
440 | [
441 | new SocketInfo(SocketFace.right, 2, "Q")
442 | ]
443 | );
444 |
445 | this.func = function(gate, inputs)
446 | {
447 | return [!gate.open && inputs[0]];
448 | }
449 |
450 | this.initialize = function(gate)
451 | {
452 | gate.open = true;
453 | }
454 |
455 | this.click = function(gate)
456 | {
457 | gate.open = !gate.open;
458 | }
459 |
460 | this.saveData = function(gate)
461 | {
462 | return gate.open;
463 | }
464 |
465 | this.loadData = function(gate, data)
466 | {
467 | gate.open = data;
468 | }
469 |
470 | this.render = function(context, x, y, gate)
471 | {
472 | this.__proto__.render(context, x, y);
473 | context.drawImage(gate == null || gate.open ? this.openImage : this.closedImage, x, y);
474 | }
475 | }
476 |
477 | function PushSwitchA()
478 | {
479 | this.openImage = images.pushswitchaopen;
480 | this.closedImage = images.pushswitchaclosed;
481 |
482 | this.__proto__ = new DefaultGate("PSWITCHA", this.openImage, true,
483 | [
484 | new SocketInfo(SocketFace.left, 2, "A"),
485 | ],
486 | [
487 | new SocketInfo(SocketFace.right, 2, "Q")
488 | ]
489 | );
490 |
491 | this.func = function(gate, inputs)
492 | {
493 | return [!gate.open && inputs[0]];
494 | }
495 |
496 | this.initialize = function(gate)
497 | {
498 | gate.open = true;
499 | }
500 |
501 | this.mouseDown = function(gate)
502 | {
503 | gate.open = false;
504 | }
505 |
506 | this.mouseUp = function(gate)
507 | {
508 | gate.open = true;
509 | }
510 |
511 | this.render = function(context, x, y, gate)
512 | {
513 | this.__proto__.render(context, x, y);
514 | context.drawImage(gate == null || gate.open ? this.openImage : this.closedImage, x, y);
515 | }
516 | }
517 |
518 | function PushSwitchB()
519 | {
520 | this.openImage = images.pushswitchbopen;
521 | this.closedImage = images.pushswitchbclosed;
522 |
523 | this.__proto__ = new DefaultGate("PSWITCHB", this.closedImage, true,
524 | [
525 | new SocketInfo(SocketFace.left, 2, "A"),
526 | ],
527 | [
528 | new SocketInfo(SocketFace.right, 2, "Q")
529 | ]
530 | );
531 |
532 | this.func = function(gate, inputs)
533 | {
534 | return [!gate.open && inputs[0]];
535 | }
536 |
537 | this.initialize = function(gate)
538 | {
539 | gate.open = false;
540 | }
541 |
542 | this.mouseDown = function(gate)
543 | {
544 | gate.open = true;
545 | }
546 |
547 | this.mouseUp = function(gate)
548 | {
549 | gate.open = false;
550 | }
551 |
552 | this.render = function(context, x, y, gate)
553 | {
554 | this.__proto__.render(context, x, y);
555 | context.drawImage(gate != null && gate.open ? this.openImage : this.closedImage, x, y);
556 | }
557 | }
558 |
559 | function OutputDisplay()
560 | {
561 | this.onImage = images.outon;
562 | this.offImage = images.outoff;
563 |
564 | this.__proto__ = new DefaultGate("OUT", this.onImage, true,
565 | [
566 | new SocketInfo(SocketFace.left, 2, "A"),
567 | ],
568 | []
569 | );
570 |
571 | this.func = function(gate, inputs)
572 | {
573 | gate.on = inputs[0];
574 | return [];
575 | }
576 |
577 | this.initialize = function(gate)
578 | {
579 | gate.on = false;
580 | }
581 |
582 | this.render = function(context, x, y, gate)
583 | {
584 | this.__proto__.render(context, x, y);
585 | context.drawImage(gate == null || !gate.on ? this.offImage : this.onImage, x, y);
586 | }
587 | }
588 |
589 | function SevenSegDisplay()
590 | {
591 | this.baseImage = images.sevsegbase;
592 | this.segImages =
593 | [
594 | images.sevsega, images.sevsegb, images.sevsegc, images.sevsegdp,
595 | images.sevsegd, images.sevsege, images.sevsegf, images.sevsegg
596 | ];
597 |
598 | this.__proto__ = new DefaultGate("SEVSEG", this.baseImage, true,
599 | [
600 | new SocketInfo(SocketFace.right, 2, "A"),
601 | new SocketInfo(SocketFace.right, 4, "B"),
602 | new SocketInfo(SocketFace.right, 6, "C"),
603 | new SocketInfo(SocketFace.right, 8, "DP"),
604 | new SocketInfo(SocketFace.left, 8, "D"),
605 | new SocketInfo(SocketFace.left, 6, "E"),
606 | new SocketInfo(SocketFace.left, 4, "F"),
607 | new SocketInfo(SocketFace.left, 2, "G")
608 | ],
609 | []
610 | );
611 |
612 | this.func = function(gate, inputs)
613 | {
614 | gate.active = inputs;
615 | return [];
616 | }
617 |
618 | this.initialize = function(gate)
619 | {
620 | gate.active = [false, false, false, false, false, false, false, false];
621 | }
622 |
623 | this.render = function(context, x, y, gate)
624 | {
625 | this.__proto__.render(context, x, y);
626 | context.drawImage(this.baseImage, x, y);
627 |
628 | if (gate != null)
629 | for (var i = 0; i < 8; ++ i)
630 | if (gate.active[i])
631 | context.drawImage(this.segImages[i], x, y);
632 | }
633 | }
634 |
635 | function DFlipFlop()
636 | {
637 | this.__proto__ = new DefaultGate("DFLIPFLOP", images.dflipflop, false,
638 | [
639 | new SocketInfo(SocketFace.left, 2, "D"),
640 | new SocketInfo(SocketFace.left, 6, ">")
641 | ],
642 | [
643 | new SocketInfo(SocketFace.right, 2, "Q"),
644 | new SocketInfo(SocketFace.right, 6, "NQ")
645 | ]
646 | );
647 |
648 | this.func = function(gate, inputs)
649 | {
650 | if (!gate.oldClock && inputs[1]) {
651 | gate.state = inputs[0];
652 | }
653 |
654 | gate.oldClock = inputs[1];
655 |
656 | return [gate.state, !gate.state];
657 | }
658 |
659 | this.initialize = function(gate)
660 | {
661 | gate.state = false;
662 | gate.oldClock = false;
663 | }
664 |
665 | this.saveData = function(gate)
666 | {
667 | return [gate.state, gate.oldClock];
668 | }
669 |
670 | this.loadData = function(gate, data)
671 | {
672 | gate.state = data[0];
673 | gate.oldClock = data[1];
674 | }
675 | }
676 |
677 | function Encoder()
678 | {
679 | var inputs = [];
680 | for (var i = 0; i < 9; ++ i)
681 | inputs[i] = new SocketInfo(SocketFace.left, 2 + i * 2, "I" + i);
682 |
683 | var outputs = [];
684 | for (var i = 0; i < 4; ++ i)
685 | outputs[i] = new SocketInfo(SocketFace.right, 4 + i * 4, "O" + i);
686 |
687 | this.__proto__ = new DefaultGate("ENCODER", images.encoder, false, inputs, outputs);
688 |
689 | this.func = function(gate, inp)
690 | {
691 | var val = 0;
692 | for (var i = 8; i >= 0; -- i)
693 | {
694 | if (inp[i])
695 | {
696 | val = i + 1;
697 | break;
698 | }
699 | }
700 |
701 | var out = [];
702 | for (var i = 0; i < 4; ++ i)
703 | out[i] = (val & (1 << i)) != 0;
704 |
705 | return out;
706 | }
707 | }
708 |
709 | function Decoder()
710 | {
711 | var inputs = [];
712 | for (var i = 0; i < 4; ++ i)
713 | inputs[i] = new SocketInfo(SocketFace.left, 4 + i * 4, "I" + i);
714 |
715 | var outputs = [];
716 | for (var i = 0; i < 9; ++ i)
717 | outputs[i] = new SocketInfo(SocketFace.right, 2 + i * 2, "O" + i);
718 |
719 | this.__proto__ = new DefaultGate("DECODER", images.decoder, false, inputs, outputs);
720 |
721 | this.func = function(gate, inp)
722 | {
723 | var val = 0;
724 | for (var i = 0; i < 4; ++ i)
725 | if (inp[i]) val += 1 << i;
726 |
727 | var out = [];
728 | for (var i = 0; i < 9; ++ i)
729 | out[i] = val == (i + 1);
730 |
731 | return out;
732 | }
733 | }
734 |
735 | function SevenSegDecoder()
736 | {
737 | var inputs = [];
738 | for (var i = 0; i < 4; ++ i)
739 | inputs[i] = new SocketInfo(SocketFace.left, 2 + i * 4, "I" + i);
740 |
741 | var outputs = [];
742 | for (var i = 0; i < 7; ++ i)
743 | outputs[i] = new SocketInfo(SocketFace.right, 2 + i * 2, "O" + i);
744 |
745 | this.__proto__ = new DefaultGate("7447", images.sevsegdecoder, false, inputs, outputs);
746 |
747 | var myOutputs = [
748 | [ true, true, true, false, true, true, true ],
749 | [ true, true, false, false, false, false, false ],
750 | [ false, true, true, true, false, true, true ],
751 | [ true, true, true, true, false, false, true ],
752 | [ true, true, false, true, true, false, false ],
753 | [ true, false, true, true, true, false, true ],
754 | [ true, false, true, true, true, true, true ],
755 | [ true, true, true, false, false, false, false ],
756 | [ true, true, true, true, true, true, true ],
757 | [ true, true, true, true, true, false, true ],
758 | [ false, false, false, false, false, false, false ]
759 | ];
760 |
761 | this.func = function(gate, inp)
762 | {
763 | var val = 0;
764 | for (var i = 0; i < 4; ++ i)
765 | if (inp[i]) val += 1 << i;
766 |
767 | return myOutputs[Math.min(val, myOutputs.length - 1)];
768 | }
769 | }
770 |
771 | function ICInput()
772 | {
773 | this.__proto__ = new DefaultGate("ICINPUT", images.input, false,
774 | [],
775 | [
776 | new SocketInfo(SocketFace.right, 2, "A")
777 | ]
778 | );
779 |
780 | this.initialize = function(gate)
781 | {
782 | gate.value = false;
783 | }
784 |
785 | this.func = function(gate, inputs)
786 | {
787 | return [gate.value];
788 | }
789 | }
790 |
791 | function ICOutput()
792 | {
793 | this.__proto__ = new DefaultGate("ICOUTPUT", images.output, false,
794 | [
795 | new SocketInfo(SocketFace.left, 2, "A")
796 | ],
797 | []
798 | );
799 |
800 | this.initialize = function(gate)
801 | {
802 | gate.value = false;
803 | }
804 |
805 | this.func = function(gate, inputs)
806 | {
807 | gate.value = inputs[0];
808 | return [];
809 | }
810 | }
811 |
812 | function Link(gate, socket)
813 | {
814 | this.gate = gate;
815 | this.socket = socket;
816 |
817 | this.getValue = function()
818 | {
819 | return this.gate.getOutput(this.socket);
820 | }
821 |
822 | this.equals = function(obj)
823 | {
824 | return this.gate == obj.gate && this.socket == obj.socket;
825 | }
826 | }
827 |
828 | function Gate(gateType, x, y, noInit)
829 | {
830 | if (noInit == null) noInit = false;
831 |
832 | var myOutputs = new Array();
833 | var myNextOutputs = new Array();
834 | var myInLinks = new Array();
835 |
836 | this.type = gateType;
837 |
838 | this.x = x;
839 | this.y = y;
840 |
841 | this.isMouseDown = false;
842 |
843 | this.width = this.type.width;
844 | this.height = this.type.height;
845 |
846 | this.inputs = this.type.inputs;
847 | this.outputs = this.type.outputs;
848 |
849 | this.selected = false;
850 |
851 | for (var i = 0; i < this.type.inputs.length; ++i)
852 | myInLinks[i] = null;
853 |
854 | for (var i = 0; i < this.type.outputs.length; ++i)
855 | myOutputs[i] = false;
856 |
857 | this.clone = function(shallow)
858 | {
859 | if (shallow == null) shallow = false;
860 |
861 | var copy = new Gate(this.type, this.x, this.y, shallow);
862 |
863 | if (!shallow) copy.loadData(this.saveData());
864 |
865 | return copy;
866 | }
867 |
868 | this.getRect = function(gridSize)
869 | {
870 | if (!gridSize)
871 | gridSize = 1;
872 |
873 | var rl = Math.round(this.x);
874 | var rt = Math.round(this.y);
875 | var rr = Math.round(this.x + this.width);
876 | var rb = Math.round(this.y + this.height);
877 |
878 | rl = Math.floor(rl / gridSize) * gridSize;
879 | rt = Math.floor(rt / gridSize) * gridSize;
880 | rr = Math.ceil(rr / gridSize) * gridSize;
881 | rb = Math.ceil(rb / gridSize) * gridSize;
882 |
883 | return new Rect(rl, rt, rr - rl, rb - rt);
884 | }
885 |
886 | this.linkInput = function(gate, output, input)
887 | {
888 | var index = this.inputs.indexOf(input);
889 | myInLinks[index] = new Link(gate, output);
890 | }
891 |
892 | this.isLinked = function(gate)
893 | {
894 | for (var i = 0; i < this.inputs.length; ++ i)
895 | if (myInLinks[i] != null && myInLinks[i].gate == gate)
896 | return true;
897 |
898 | return false;
899 | }
900 |
901 | this.unlinkAll = function()
902 | {
903 | for (var i = 0; i < this.inputs.length; ++ i)
904 | myInLinks[i] = null;
905 | }
906 |
907 | this.unlinkGate = function(gate)
908 | {
909 | for (var i = 0; i < this.inputs.length; ++ i)
910 | if (myInLinks[i] != null && myInLinks[i].gate == gate)
911 | myInLinks[i] = null;
912 | }
913 |
914 | this.unlinkInput = function(input)
915 | {
916 | var index = this.inputs.indexOf(input);
917 | myInLinks[index] = null;
918 | }
919 |
920 | this.getOutputs = function()
921 | {
922 | return myOutputs;
923 | }
924 |
925 | this.setOutputs = function(outputs)
926 | {
927 | myOutputs = outputs;
928 | }
929 |
930 | this.getOutput = function(output)
931 | {
932 | var index = this.outputs.indexOf(output);
933 | return myOutputs[index];
934 | }
935 |
936 | this.click = function()
937 | {
938 | this.type.click(this);
939 | }
940 |
941 | this.mouseDown = function()
942 | {
943 | this.isMouseDown = true;
944 | this.type.mouseDown(this);
945 | }
946 |
947 | this.mouseUp = function()
948 | {
949 | this.isMouseDown = false;
950 | this.type.mouseUp(this);
951 | }
952 |
953 | this.step = function()
954 | {
955 | var inVals = new Array();
956 |
957 | for (var i = 0; i < this.inputs.length; ++ i)
958 | {
959 | var link = myInLinks[i];
960 | inVals[i] = (myInLinks[i] == null)
961 | ? false : link.getValue();
962 | }
963 |
964 | myNextOutputs = this.type.func(this, inVals);
965 | }
966 |
967 | this.commit = function()
968 | {
969 | myOutputs = myNextOutputs;
970 | }
971 |
972 | this.saveData = function()
973 | {
974 | return this.type.saveData(this);
975 | }
976 |
977 | this.loadData = function(data)
978 | {
979 | this.type.loadData(this, data);
980 | }
981 |
982 | this.render = function(context, offset, selectClr)
983 | {
984 | if (this.selected) {
985 | var rect = this.getRect();
986 |
987 | if (selectClr == null) selectClr = "#6666FF";
988 |
989 | context.globalAlpha = 0.5;
990 | context.fillStyle = selectClr;
991 | context.fillRect(rect.left - 4 + offset.x, rect.top - 4 + offset.y,
992 | rect.width + 8, rect.height + 8);
993 | context.globalAlpha = 1.0;
994 | }
995 |
996 | this.type.render(context, this.x + offset.x, this.y + offset.y, this);
997 |
998 | context.strokeStyle = "#000000";
999 | context.lineWidth = 2;
1000 | context.fillStyle = "#9999FF";
1001 |
1002 | for (var i = 0; i < this.inputs.length + this.outputs.length; ++ i) {
1003 | var inp = (i < this.inputs.length ? this.inputs[i]
1004 | : this.outputs[i - this.inputs.length]);
1005 | var pos = inp.getPosition(this.type, this.x, this.y);
1006 |
1007 | if (i < this.inputs.length) {
1008 | if (myInLinks[i] != null) {
1009 | context.fillStyle = myInLinks[i].getValue() ? "#FF9999" : "#9999FF";
1010 | } else {
1011 | context.fillStyle = "#999999";
1012 | }
1013 | } else {
1014 | context.fillStyle = myOutputs[i - this.inputs.length]
1015 | ? "#FF9999" : "#9999FF";
1016 | }
1017 |
1018 | context.beginPath();
1019 | context.arc(pos.x + offset.x, pos.y + offset.y, 4, 0, Math.PI * 2, true);
1020 | context.fill();
1021 | context.stroke();
1022 | context.closePath();
1023 | }
1024 | }
1025 |
1026 | if (!noInit) {
1027 | this.type.initialize(this);
1028 | }
1029 | }
1030 |
--------------------------------------------------------------------------------
/scripts/lz-string-1.3.3.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013 Pieroxy
2 | // This work is free. You can redistribute it and/or modify it
3 | // under the terms of the WTFPL, Version 2
4 | // For more information see LICENSE.txt or http://www.wtfpl.net/
5 | //
6 | // For more information, the home page:
7 | // http://pieroxy.net/blog/pages/lz-string/testing.html
8 | //
9 | // LZ-based compression algorithm, version 1.3.3
10 | var LZString = {
11 |
12 |
13 | // private property
14 | _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
15 | _f : String.fromCharCode,
16 |
17 | compressToBase64 : function (input) {
18 | if (input == null) return "";
19 | var output = "";
20 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
21 | var i = 0;
22 |
23 | input = this.compress(input);
24 |
25 | while (i < input.length*2) {
26 |
27 | if (i%2==0) {
28 | chr1 = input.charCodeAt(i/2) >> 8;
29 | chr2 = input.charCodeAt(i/2) & 255;
30 | if (i/2+1 < input.length)
31 | chr3 = input.charCodeAt(i/2+1) >> 8;
32 | else
33 | chr3 = NaN;
34 | } else {
35 | chr1 = input.charCodeAt((i-1)/2) & 255;
36 | if ((i+1)/2 < input.length) {
37 | chr2 = input.charCodeAt((i+1)/2) >> 8;
38 | chr3 = input.charCodeAt((i+1)/2) & 255;
39 | } else
40 | chr2=chr3=NaN;
41 | }
42 | i+=3;
43 |
44 | enc1 = chr1 >> 2;
45 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
46 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
47 | enc4 = chr3 & 63;
48 |
49 | if (isNaN(chr2)) {
50 | enc3 = enc4 = 64;
51 | } else if (isNaN(chr3)) {
52 | enc4 = 64;
53 | }
54 |
55 | output = output +
56 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
57 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
58 |
59 | }
60 |
61 | return output;
62 | },
63 |
64 | decompressFromBase64 : function (input) {
65 | if (input == null) return "";
66 | var output = "",
67 | ol = 0,
68 | output_,
69 | chr1, chr2, chr3,
70 | enc1, enc2, enc3, enc4,
71 | i = 0, f=this._f;
72 |
73 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
74 |
75 | while (i < input.length) {
76 |
77 | enc1 = this._keyStr.indexOf(input.charAt(i++));
78 | enc2 = this._keyStr.indexOf(input.charAt(i++));
79 | enc3 = this._keyStr.indexOf(input.charAt(i++));
80 | enc4 = this._keyStr.indexOf(input.charAt(i++));
81 |
82 | chr1 = (enc1 << 2) | (enc2 >> 4);
83 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
84 | chr3 = ((enc3 & 3) << 6) | enc4;
85 |
86 | if (ol%2==0) {
87 | output_ = chr1 << 8;
88 |
89 | if (enc3 != 64) {
90 | output += f(output_ | chr2);
91 | }
92 | if (enc4 != 64) {
93 | output_ = chr3 << 8;
94 | }
95 | } else {
96 | output = output + f(output_ | chr1);
97 |
98 | if (enc3 != 64) {
99 | output_ = chr2 << 8;
100 | }
101 | if (enc4 != 64) {
102 | output += f(output_ | chr3);
103 | }
104 | }
105 | ol+=3;
106 | }
107 |
108 | return this.decompress(output);
109 |
110 | },
111 |
112 | compressToUTF16 : function (input) {
113 | if (input == null) return "";
114 | var output = "",
115 | i,c,
116 | current,
117 | status = 0,
118 | f = this._f;
119 |
120 | input = this.compress(input);
121 |
122 | for (i=0 ; i> 1)+32);
127 | current = (c & 1) << 14;
128 | break;
129 | case 1:
130 | output += f((current + (c >> 2))+32);
131 | current = (c & 3) << 13;
132 | break;
133 | case 2:
134 | output += f((current + (c >> 3))+32);
135 | current = (c & 7) << 12;
136 | break;
137 | case 3:
138 | output += f((current + (c >> 4))+32);
139 | current = (c & 15) << 11;
140 | break;
141 | case 4:
142 | output += f((current + (c >> 5))+32);
143 | current = (c & 31) << 10;
144 | break;
145 | case 5:
146 | output += f((current + (c >> 6))+32);
147 | current = (c & 63) << 9;
148 | break;
149 | case 6:
150 | output += f((current + (c >> 7))+32);
151 | current = (c & 127) << 8;
152 | break;
153 | case 7:
154 | output += f((current + (c >> 8))+32);
155 | current = (c & 255) << 7;
156 | break;
157 | case 8:
158 | output += f((current + (c >> 9))+32);
159 | current = (c & 511) << 6;
160 | break;
161 | case 9:
162 | output += f((current + (c >> 10))+32);
163 | current = (c & 1023) << 5;
164 | break;
165 | case 10:
166 | output += f((current + (c >> 11))+32);
167 | current = (c & 2047) << 4;
168 | break;
169 | case 11:
170 | output += f((current + (c >> 12))+32);
171 | current = (c & 4095) << 3;
172 | break;
173 | case 12:
174 | output += f((current + (c >> 13))+32);
175 | current = (c & 8191) << 2;
176 | break;
177 | case 13:
178 | output += f((current + (c >> 14))+32);
179 | current = (c & 16383) << 1;
180 | break;
181 | case 14:
182 | output += f((current + (c >> 15))+32, (c & 32767)+32);
183 | status = 0;
184 | break;
185 | }
186 | }
187 |
188 | return output + f(current + 32);
189 | },
190 |
191 |
192 | decompressFromUTF16 : function (input) {
193 | if (input == null) return "";
194 | var output = "",
195 | current,c,
196 | status=0,
197 | i = 0,
198 | f = this._f;
199 |
200 | while (i < input.length) {
201 | c = input.charCodeAt(i) - 32;
202 |
203 | switch (status++) {
204 | case 0:
205 | current = c << 1;
206 | break;
207 | case 1:
208 | output += f(current | (c >> 14));
209 | current = (c&16383) << 2;
210 | break;
211 | case 2:
212 | output += f(current | (c >> 13));
213 | current = (c&8191) << 3;
214 | break;
215 | case 3:
216 | output += f(current | (c >> 12));
217 | current = (c&4095) << 4;
218 | break;
219 | case 4:
220 | output += f(current | (c >> 11));
221 | current = (c&2047) << 5;
222 | break;
223 | case 5:
224 | output += f(current | (c >> 10));
225 | current = (c&1023) << 6;
226 | break;
227 | case 6:
228 | output += f(current | (c >> 9));
229 | current = (c&511) << 7;
230 | break;
231 | case 7:
232 | output += f(current | (c >> 8));
233 | current = (c&255) << 8;
234 | break;
235 | case 8:
236 | output += f(current | (c >> 7));
237 | current = (c&127) << 9;
238 | break;
239 | case 9:
240 | output += f(current | (c >> 6));
241 | current = (c&63) << 10;
242 | break;
243 | case 10:
244 | output += f(current | (c >> 5));
245 | current = (c&31) << 11;
246 | break;
247 | case 11:
248 | output += f(current | (c >> 4));
249 | current = (c&15) << 12;
250 | break;
251 | case 12:
252 | output += f(current | (c >> 3));
253 | current = (c&7) << 13;
254 | break;
255 | case 13:
256 | output += f(current | (c >> 2));
257 | current = (c&3) << 14;
258 | break;
259 | case 14:
260 | output += f(current | (c >> 1));
261 | current = (c&1) << 15;
262 | break;
263 | case 15:
264 | output += f(current | c);
265 | status=0;
266 | break;
267 | }
268 |
269 |
270 | i++;
271 | }
272 |
273 | return this.decompress(output);
274 | //return output;
275 |
276 | },
277 |
278 |
279 |
280 | compress: function (uncompressed) {
281 | if (uncompressed == null) return "";
282 | var i, value,
283 | context_dictionary= {},
284 | context_dictionaryToCreate= {},
285 | context_c="",
286 | context_wc="",
287 | context_w="",
288 | context_enlargeIn= 2, // Compensate for the first entry which should not count
289 | context_dictSize= 3,
290 | context_numBits= 2,
291 | context_data_string="",
292 | context_data_val=0,
293 | context_data_position=0,
294 | ii,
295 | f=this._f;
296 |
297 | for (ii = 0; ii < uncompressed.length; ii += 1) {
298 | context_c = uncompressed.charAt(ii);
299 | if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) {
300 | context_dictionary[context_c] = context_dictSize++;
301 | context_dictionaryToCreate[context_c] = true;
302 | }
303 |
304 | context_wc = context_w + context_c;
305 | if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) {
306 | context_w = context_wc;
307 | } else {
308 | if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
309 | if (context_w.charCodeAt(0)<256) {
310 | for (i=0 ; i> 1;
331 | }
332 | } else {
333 | value = 1;
334 | for (i=0 ; i> 1;
356 | }
357 | }
358 | context_enlargeIn--;
359 | if (context_enlargeIn == 0) {
360 | context_enlargeIn = Math.pow(2, context_numBits);
361 | context_numBits++;
362 | }
363 | delete context_dictionaryToCreate[context_w];
364 | } else {
365 | value = context_dictionary[context_w];
366 | for (i=0 ; i> 1;
376 | }
377 |
378 |
379 | }
380 | context_enlargeIn--;
381 | if (context_enlargeIn == 0) {
382 | context_enlargeIn = Math.pow(2, context_numBits);
383 | context_numBits++;
384 | }
385 | // Add wc to the dictionary.
386 | context_dictionary[context_wc] = context_dictSize++;
387 | context_w = String(context_c);
388 | }
389 | }
390 |
391 | // Output the code for w.
392 | if (context_w !== "") {
393 | if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
394 | if (context_w.charCodeAt(0)<256) {
395 | for (i=0 ; i> 1;
416 | }
417 | } else {
418 | value = 1;
419 | for (i=0 ; i> 1;
441 | }
442 | }
443 | context_enlargeIn--;
444 | if (context_enlargeIn == 0) {
445 | context_enlargeIn = Math.pow(2, context_numBits);
446 | context_numBits++;
447 | }
448 | delete context_dictionaryToCreate[context_w];
449 | } else {
450 | value = context_dictionary[context_w];
451 | for (i=0 ; i> 1;
461 | }
462 |
463 |
464 | }
465 | context_enlargeIn--;
466 | if (context_enlargeIn == 0) {
467 | context_enlargeIn = Math.pow(2, context_numBits);
468 | context_numBits++;
469 | }
470 | }
471 |
472 | // Mark the end of the stream
473 | value = 2;
474 | for (i=0 ; i> 1;
484 | }
485 |
486 | // Flush the last char
487 | while (true) {
488 | context_data_val = (context_data_val << 1);
489 | if (context_data_position == 15) {
490 | context_data_string += f(context_data_val);
491 | break;
492 | }
493 | else context_data_position++;
494 | }
495 | return context_data_string;
496 | },
497 |
498 | decompress: function (compressed) {
499 | if (compressed == null) return "";
500 | var dictionary = [],
501 | next,
502 | enlargeIn = 4,
503 | dictSize = 4,
504 | numBits = 3,
505 | entry = "",
506 | result = "",
507 | i,
508 | w,
509 | bits, resb, maxpower, power,
510 | c,
511 | f = this._f,
512 | data = {string:compressed, val:compressed.charCodeAt(0), position:32768, index:1};
513 |
514 | for (i = 0; i < 3; i += 1) {
515 | dictionary[i] = i;
516 | }
517 |
518 | bits = 0;
519 | maxpower = Math.pow(2,2);
520 | power=1;
521 | while (power!=maxpower) {
522 | resb = data.val & data.position;
523 | data.position >>= 1;
524 | if (data.position == 0) {
525 | data.position = 32768;
526 | data.val = data.string.charCodeAt(data.index++);
527 | }
528 | bits |= (resb>0 ? 1 : 0) * power;
529 | power <<= 1;
530 | }
531 |
532 | switch (next = bits) {
533 | case 0:
534 | bits = 0;
535 | maxpower = Math.pow(2,8);
536 | power=1;
537 | while (power!=maxpower) {
538 | resb = data.val & data.position;
539 | data.position >>= 1;
540 | if (data.position == 0) {
541 | data.position = 32768;
542 | data.val = data.string.charCodeAt(data.index++);
543 | }
544 | bits |= (resb>0 ? 1 : 0) * power;
545 | power <<= 1;
546 | }
547 | c = f(bits);
548 | break;
549 | case 1:
550 | bits = 0;
551 | maxpower = Math.pow(2,16);
552 | power=1;
553 | while (power!=maxpower) {
554 | resb = data.val & data.position;
555 | data.position >>= 1;
556 | if (data.position == 0) {
557 | data.position = 32768;
558 | data.val = data.string.charCodeAt(data.index++);
559 | }
560 | bits |= (resb>0 ? 1 : 0) * power;
561 | power <<= 1;
562 | }
563 | c = f(bits);
564 | break;
565 | case 2:
566 | return "";
567 | }
568 | dictionary[3] = c;
569 | w = result = c;
570 | while (true) {
571 | bits = 0;
572 | maxpower = Math.pow(2,numBits);
573 | power=1;
574 | while (power!=maxpower) {
575 | resb = data.val & data.position;
576 | data.position >>= 1;
577 | if (data.position == 0) {
578 | data.position = 32768;
579 | data.val = data.string.charCodeAt(data.index++);
580 | }
581 | bits |= (resb>0 ? 1 : 0) * power;
582 | power <<= 1;
583 | }
584 |
585 | switch (c = bits) {
586 | case 0:
587 | bits = 0;
588 | maxpower = Math.pow(2,8);
589 | power=1;
590 | while (power!=maxpower) {
591 | resb = data.val & data.position;
592 | data.position >>= 1;
593 | if (data.position == 0) {
594 | data.position = 32768;
595 | data.val = data.string.charCodeAt(data.index++);
596 | }
597 | bits |= (resb>0 ? 1 : 0) * power;
598 | power <<= 1;
599 | }
600 |
601 | dictionary[dictSize++] = f(bits);
602 | c = dictSize-1;
603 | enlargeIn--;
604 | break;
605 | case 1:
606 | bits = 0;
607 | maxpower = Math.pow(2,16);
608 | power=1;
609 | while (power!=maxpower) {
610 | resb = data.val & data.position;
611 | data.position >>= 1;
612 | if (data.position == 0) {
613 | data.position = 32768;
614 | data.val = data.string.charCodeAt(data.index++);
615 | }
616 | bits |= (resb>0 ? 1 : 0) * power;
617 | power <<= 1;
618 | }
619 | dictionary[dictSize++] = f(bits);
620 | c = dictSize-1;
621 | enlargeIn--;
622 | break;
623 | case 2:
624 | return result;
625 | }
626 |
627 | if (enlargeIn == 0) {
628 | enlargeIn = Math.pow(2, numBits);
629 | numBits++;
630 | }
631 |
632 | if (dictionary[c]) {
633 | entry = dictionary[c];
634 | } else {
635 | if (c === dictSize) {
636 | entry = w + w.charAt(0);
637 | } else {
638 | return null;
639 | }
640 | }
641 | result += entry;
642 |
643 | // Add w+entry[0] to the dictionary.
644 | dictionary[dictSize++] = w + entry.charAt(0);
645 | enlargeIn--;
646 |
647 | w = entry;
648 |
649 | if (enlargeIn == 0) {
650 | enlargeIn = Math.pow(2, numBits);
651 | numBits++;
652 | }
653 |
654 | }
655 | }
656 | };
657 |
--------------------------------------------------------------------------------
/scripts/main.js:
--------------------------------------------------------------------------------
1 | var ControlMode = {
2 | wiring: 0,
3 | selecting: 1,
4 | deleting: 2
5 | };
6 |
7 | function LogicSim()
8 | {
9 | this.__proto__ = new Environment();
10 |
11 | var myIsDragging = false;
12 | var myIsSelecting = false;
13 | var myCanDrag = false;
14 |
15 | var myIsWiring = false;
16 | var myWireStart = null;
17 |
18 | var myGridSize = 8;
19 | var myGridImage = null;
20 |
21 | var myDeleteBtn = null;
22 | var mySelectBtn = null;
23 | var myMoveBtn = null;
24 |
25 | var myCtrlDown = false;
26 |
27 | var mySelection = new Environment();
28 | var myCanPlace = false;
29 | var myLastDragPos = null;
30 |
31 | var myCustoms = new Array();
32 |
33 | this.canvas = null;
34 | this.context = null;
35 |
36 | this.toolbar = null;
37 |
38 | this.mouseX = 0;
39 | this.mouseY = 0;
40 |
41 | this.mosueDownPos = null;
42 |
43 | this.mode = ControlMode.wiring;
44 |
45 | this.initialize = function()
46 | {
47 | this.canvas = document.getElementById("canvas");
48 | this.context = this.canvas.getContext("2d");
49 |
50 | this.toolbar = new Toolbar();
51 | var grp = this.toolbar.addGroup("Tools");
52 | grp.addItem(new Button.Tool(images.newfile, function() {
53 | if (confirm("Are you sure you want to delete all existing gates, "
54 | + "wires and custom circuits?")) {
55 | logicSim.clear();
56 | }
57 | }));
58 | grp.addItem(new Button.Tool(images.save, function() {
59 | Saving.save();
60 | }));
61 | grp.addItem(new Button.Tool(images.open, function() {
62 | Saving.loadFromPrompt();
63 | }));
64 | myDeleteBtn = grp.addItem(new Button.Tool(images.delete, function() {
65 | if (logicSim.mode == ControlMode.deleting)
66 | logicSim.setMode(ControlMode.wiring);
67 | else
68 | logicSim.setMode(ControlMode.deleting);
69 | }));
70 | mySelectBtn = grp.addItem(new Button.Tool(images.select, function() {
71 | if (logicSim.mode == ControlMode.wiring)
72 | logicSim.setMode(ControlMode.wiring);
73 | else
74 | logicSim.setMode(ControlMode.selecting);
75 | }));
76 | grp.addItem(new Button.Tool(images.newic, function() {
77 | if (logicSim.getOutputs().length == 0) {
78 | alert("At least one output required to create an integrated circuit.");
79 | return;
80 | }
81 |
82 | var name = prompt("Please enter a name for the new integrated circuit.", "");
83 | if (name == null) return;
84 |
85 | logicSim.customGroup.addItem(new CustomIC(name, logicSim.clone()));
86 | }));
87 |
88 | grp = this.toolbar.addGroup("Logic Gates");
89 | grp.addItem(new BufferGate());
90 | grp.addItem(new AndGate());
91 | grp.addItem(new OrGate());
92 | grp.addItem(new XorGate());
93 | grp.addItem(new NotGate());
94 | grp.addItem(new NandGate());
95 | grp.addItem(new NorGate());
96 | grp.addItem(new XnorGate());
97 |
98 | grp = this.toolbar.addGroup("Input");
99 | grp.addItem(new ConstInput());
100 | grp.addItem(new ClockInput());
101 | grp.addItem(new ToggleSwitch());
102 | grp.addItem(new PushSwitchA());
103 | grp.addItem(new PushSwitchB());
104 | grp.addItem(new ICInput());
105 |
106 | grp = this.toolbar.addGroup("Output");
107 | grp.addItem(new OutputDisplay());
108 | grp.addItem(new SevenSegDisplay());
109 | grp.addItem(new ICOutput());
110 |
111 | grp = this.toolbar.addGroup("Flip Flops", true);
112 | grp.addItem(new DFlipFlop());
113 |
114 | grp = this.toolbar.addGroup("Integrated Circuits", true);
115 | grp.addItem(new Encoder());
116 | grp.addItem(new Decoder());
117 | grp.addItem(new SevenSegDecoder());
118 |
119 | this.customGroup = this.toolbar.addGroup("Custom Circuits");
120 |
121 | this.setGridSize(16);
122 | this.onResizeCanvas();
123 |
124 | Saving.loadFromHash();
125 | }
126 |
127 | this.startDragging = function(gateType)
128 | {
129 | mySelection.clear();
130 |
131 | if (gateType != null) {
132 | this.deselectAll();
133 |
134 | var gate = new Gate(gateType, 0, 0);
135 | gate.selected = true;
136 |
137 | mySelection.placeGate(gate);
138 | } else {
139 | var pos = this.mouseDownPos;
140 |
141 | for (var i = this.gates.length - 1; i >= 0; i--) {
142 | var gate = this.gates[i];
143 | if (!gate.selected) continue;
144 |
145 | if (myCtrlDown) {
146 | gate.selected = false;
147 | var data = gate.saveData();
148 | gate = new Gate(gate.type, gate.x, gate.y);
149 | gate.loadData(data);
150 | gate.selected = true;
151 | } else {
152 | this.removeGate(gate);
153 | }
154 |
155 | gate.x -= pos.x;
156 | gate.y -= pos.y;
157 |
158 | mySelection.placeGate(gate);
159 | }
160 |
161 | var wires = this.getAllWires();
162 | var toRemove = new Array();
163 | for (var i = 0; i < wires.length; ++ i) {
164 | var wire = wires[i];
165 | if (!wire.selected) continue;
166 |
167 | if (myCtrlDown) {
168 | wire.selected = false;
169 | } else {
170 | toRemove.push(wire);
171 | }
172 |
173 | mySelection.placeWire(wire.start.sub(pos), wire.end.sub(pos), true);
174 | }
175 |
176 | if (!myCtrlDown) {
177 | this.removeWires(toRemove);
178 | }
179 | }
180 |
181 | myIsDragging = true;
182 | }
183 |
184 | this.getDraggedPosition = function()
185 | {
186 | var snap = myGridSize / 2;
187 |
188 | for (var i = this.gates.length - 1; i >= 0; i--) {
189 | var gate = this.gates[i];
190 | if (gate.selected) {
191 | snap = myGridSize;
192 | break;
193 | }
194 | }
195 |
196 | if (mySelection.gates.length > 0) {
197 | snap = myGridSize;
198 | }
199 |
200 | return new Pos(
201 | Math.round(this.mouseX / snap) * snap,
202 | Math.round(this.mouseY / snap) * snap
203 | );
204 | }
205 |
206 | this.getSelectedRect = function()
207 | {
208 | var start = new Pos(this.mouseDownPos.x, this.mouseDownPos.y);
209 | var end = this.getDraggedPosition();
210 |
211 | if (end.x < start.x) {
212 | var temp = end.x;
213 | end.x = start.x;
214 | start.x = temp;
215 | }
216 |
217 | if (end.y < start.y) {
218 | var temp = end.y;
219 | end.y = start.y;
220 | start.y = temp;
221 | }
222 |
223 | return new Rect(start.x, start.y, end.x - start.x, end.y - start.y);
224 | }
225 |
226 | this.stopDragging = function()
227 | {
228 | myIsDragging = false;
229 |
230 | if (this.getDraggedPosition().x >= 256) {
231 | if (myCanPlace) {
232 | this.tryMerge(mySelection, this.getDraggedPosition(), true);
233 | } else {
234 | this.tryMerge(mySelection, this.mouseDownPos, true);
235 | }
236 | }
237 |
238 | mySelection.clear();
239 | }
240 |
241 | this.setMode = function(mode)
242 | {
243 | if (mode == ControlMode.deleting) {
244 | var deleted = false;
245 | for (var i = this.gates.length - 1; i >= 0; i--) {
246 | var gate = this.gates[i];
247 | if (gate.selected) {
248 | deleted = true;
249 | this.removeGate(gate);
250 | }
251 | }
252 |
253 | var wires = this.getAllWires();
254 | var toRemove = new Array();
255 | for (var i = wires.length - 1; i >= 0; i--) {
256 | var wire = wires[i];
257 | if (wire.selected) {
258 | deleted = true;
259 | toRemove.push(wire);
260 | }
261 | }
262 | this.removeWires(toRemove);
263 |
264 | if (deleted) mode = ControlMode.wiring;
265 | }
266 |
267 | this.mode = mode;
268 |
269 | myDeleteBtn.selected = mode == ControlMode.deleting;
270 | mySelectBtn.selected = mode == ControlMode.selecting;
271 | }
272 |
273 | this.startWiring = function(x, y)
274 | {
275 | var snap = myGridSize / 2;
276 |
277 | myIsWiring = true;
278 | myWireStart = new Pos(
279 | Math.round(x / snap) * snap,
280 | Math.round(y / snap) * snap
281 | );
282 | }
283 |
284 | this.stopWiring = function(x, y)
285 | {
286 | if (this.canPlaceWire(new Wire(myWireStart, this.getWireEnd()))) {
287 | this.deselectAll();
288 | this.placeWire(myWireStart, this.getWireEnd());
289 | }
290 |
291 | myIsWiring = false;
292 | }
293 |
294 | this.getWireEnd = function()
295 | {
296 | var snap = 8;
297 |
298 | var pos = new Pos(
299 | Math.round(this.mouseX / snap) * snap,
300 | Math.round(this.mouseY / snap) * snap
301 | );
302 |
303 | var diff = pos.sub(myWireStart);
304 |
305 | if (Math.abs(diff.x) >= Math.abs(diff.y)) {
306 | pos.y = myWireStart.y;
307 | } else {
308 | pos.x = myWireStart.x;
309 | }
310 |
311 | return pos;
312 | }
313 |
314 | this.mouseMove = function(x, y, e)
315 | {
316 | this.mouseX = x;
317 | this.mouseY = y;
318 |
319 | myCtrlDown = e.ctrlKey;
320 |
321 | if (this.toolbar == null) return;
322 |
323 | if (e.shiftKey) this.setMode(ControlMode.selecting);
324 | else if (this.mode == ControlMode.selecting) this.setMode(ControlMode.wiring);
325 |
326 | this.toolbar.mouseMove(x, y);
327 |
328 | if (!myIsDragging && !myIsSelecting && myCanDrag && this.mouseDownPos != null) {
329 | var diff = new Pos(x, y).sub(this.mouseDownPos);
330 | if (Math.abs(diff.x) >= 8 || Math.abs(diff.y) >= 8)
331 | this.startDragging();
332 | } else if (myIsDragging) {
333 | var pos = this.getDraggedPosition();
334 |
335 | if (myLastDragPos == null || !pos.equals(myLastDragPos)) {
336 | var env = this.clone();
337 | myCanPlace = env.tryMerge(mySelection, pos, false, true);
338 | myLastDragPos = pos;
339 | }
340 | }
341 | }
342 |
343 | this.mouseDown = function(x, y, e)
344 | {
345 | this.mouseX = x;
346 | this.mouseY = y;
347 |
348 | myCtrlDown = e.ctrlKey;
349 |
350 | if (this.toolbar == null) return;
351 |
352 | if (e.shiftKey) this.setMode(ControlMode.selecting);
353 | else if (this.mode == ControlMode.selecting) this.setMode(ControlMode.wiring);
354 |
355 | this.mouseDownPos = this.getDraggedPosition();
356 |
357 | myCanDrag = false;
358 |
359 | var canSelect = this.mode == ControlMode.selecting;
360 |
361 | if (x < 256) {
362 | this.toolbar.mouseDown(x, y);
363 | } else {
364 | var pos = new Pos(x, y);
365 |
366 | for (var i = 0; i < this.gates.length; ++ i) {
367 | var gate = this.gates[i];
368 | var rect = new Rect(gate.x + 8, gate.y + 8, gate.width - 16, gate.height - 16);
369 |
370 | if (rect.contains(pos)) {
371 | gate.mouseDown();
372 | if (this.mode == ControlMode.selecting) {
373 | gate.selected = !gate.selected;
374 | canSelect = false;
375 | } else if (this.mode == ControlMode.wiring) {
376 | if (!gate.selected) {
377 | this.deselectAll();
378 | gate.selected = true;
379 | } else {
380 | myCanDrag = true;
381 | }
382 | return;
383 | }
384 | }
385 | }
386 |
387 | var gsize = myGridSize / 2;
388 | pos.x = Math.round(pos.x / gsize) * gsize;
389 | pos.y = Math.round(pos.y / gsize) * gsize;
390 |
391 | for (var i = 0; i < this.wireGroups.length; ++ i) {
392 | var group = this.wireGroups[i];
393 | if (group.crossesPos(pos)) {
394 | var wire = group.getWireAt(pos);
395 |
396 | if (this.mode == ControlMode.selecting) {
397 | wire.selected = !wire.selected;
398 | canSelect = false;
399 | } else if (this.mode == ControlMode.wiring) {
400 | if (!wire.selected) {
401 | this.deselectAll();
402 | wire.selected = true;
403 | } else {
404 | myCanDrag = true;
405 | return;
406 | }
407 | }
408 | }
409 | }
410 |
411 | if (canSelect) {
412 | myIsSelecting = true;
413 | } else if (this.mode == ControlMode.wiring) {
414 | this.startWiring(x, y);
415 | }
416 | }
417 | }
418 |
419 | this.mouseUp = function(x, y, e)
420 | {
421 | this.mouseX = x;
422 | this.mouseY = y;
423 |
424 | myCtrlDown = e.ctrlKey;
425 |
426 | if (this.toolbar == null) return;
427 |
428 | if (e.shiftKey) this.setMode(ControlMode.selecting);
429 | else if (this.mode == ControlMode.selecting) this.setMode(ControlMode.wiring);
430 |
431 | if (myIsDragging) {
432 | this.stopDragging();
433 | } else if (myIsWiring) {
434 | this.stopWiring();
435 | } else if (myIsSelecting) {
436 | myIsSelecting = false;
437 |
438 | var rect = this.getSelectedRect();
439 |
440 | for (var i = 0; i < this.gates.length; ++ i) {
441 | var gate = this.gates[i];
442 |
443 | if (gate.getRect().intersects(rect)) {
444 | gate.selected = true;
445 | }
446 | }
447 |
448 | var wires = this.getAllWires();
449 | for (var i = 0; i < wires.length; ++ i) {
450 | var wire = wires[i];
451 |
452 | if (rect.intersectsWire(wire)) {
453 | wire.selected = true;
454 | }
455 | }
456 | } else if (x < 256) {
457 | this.toolbar.mouseUp(x, y);
458 | } else {
459 | var pos = new Pos(x, y);
460 |
461 | var deleted = false;
462 |
463 | for (var i = 0; i < this.gates.length; ++ i) {
464 | var gate = this.gates[i];
465 |
466 | if (gate.isMouseDown) {
467 | var rect = new Rect(gate.x + 8, gate.y + 8, gate.width - 16, gate.height - 16);
468 |
469 | if (rect.contains(pos)) {
470 | if (this.mode == ControlMode.deleting && !deleted) {
471 | this.removeGate(gate);
472 | deleted = true;
473 | } else {
474 | gate.click();
475 | }
476 | }
477 |
478 | gate.mouseUp();
479 | }
480 | }
481 |
482 | if (this.mode == ControlMode.deleting && !deleted) {
483 | var gsize = 8;
484 | pos.x = Math.round(pos.x / gsize) * gsize;
485 | pos.y = Math.round(pos.y / gsize) * gsize;
486 |
487 | if (this.mouseDownPos.equals(pos)) {
488 | for (var i = 0; i < this.wireGroups.length; ++ i) {
489 | var group = this.wireGroups[i];
490 | if (group.crossesPos(pos)) {
491 | var wire = group.getWireAt(pos);
492 | this.removeWire(wire);
493 | break;
494 | }
495 | }
496 | }
497 | }
498 | }
499 |
500 | this.mouseDownPos = null;
501 | }
502 |
503 | this.click = function(x, y, e)
504 | {
505 | this.mouseX = x;
506 | this.mouseY = y;
507 |
508 | myCtrlDown = e.ctrlKey;
509 |
510 | if (e.shiftKey) this.setMode(ControlMode.selecting);
511 | else if (this.mode == ControlMode.selecting) this.setMode(ControlMode.wiring);
512 |
513 | if (x < 256) {
514 | this.toolbar.click(x, y);
515 | }
516 | }
517 |
518 | this.keyDown = function(e)
519 | {
520 | if (e.keyCode == 46) this.setMode(ControlMode.deleting);
521 | if (e.keyCode == 16) this.setMode(ControlMode.selecting);
522 | if (e.keyCode == 17) myCtrlDown = true;
523 |
524 | if (e.keyCode == 83 && e.ctrlKey) {
525 | Saving.save();
526 | e.preventDefault();
527 | }
528 |
529 | if (e.keyCode == 79 && e.ctrlKey) {
530 | Saving.loadFromPrompt();
531 | e.preventDefault();
532 | }
533 | }
534 |
535 | this.keyUp = function(e)
536 | {
537 | if ((e.keyCode == 46 && this.mode == ControlMode.deleting)
538 | || (e.keyCode == 16 && this.mode == ControlMode.selecting))
539 | this.setMode(ControlMode.wiring);
540 |
541 | if (e.keyCode == 17) myCtrlDown = false;
542 | }
543 |
544 | this.getGridSize = function()
545 | {
546 | return myGridSize;
547 | }
548 |
549 | this.setGridSize = function(size)
550 | {
551 | myGridSize = size;
552 | myGridImage = document.createElement("canvas");
553 | myGridImage.width = myGridSize * 2;
554 | myGridImage.height = myGridSize * 2;
555 |
556 | var context = myGridImage.getContext("2d");
557 |
558 | context.fillStyle = "#CCCCCC";
559 | context.fillRect(0, 0, myGridSize * 2, myGridSize * 2);
560 | context.fillStyle = "#DDDDDD";
561 | context.fillRect(0, 0, myGridSize, myGridSize);
562 | context.fillRect(myGridSize, myGridSize, myGridSize, myGridSize);
563 | }
564 |
565 | this.onResizeCanvas = function()
566 | {
567 | this.canvas.width = window.innerWidth;
568 | this.canvas.height = window.innerHeight;
569 | }
570 |
571 | this.run = function()
572 | {
573 | setInterval(this.mainLoop, 1000.0 / 60.0, this);
574 | }
575 |
576 | this.mainLoop = function(self)
577 | {
578 | for (var i = 0; i < 4; ++ i) {
579 | self.step();
580 | }
581 |
582 | self.context.fillStyle = self.context.createPattern(myGridImage, "repeat");
583 | self.context.fillRect(256, 0, self.canvas.width - 256, self.canvas.height);
584 |
585 | self.render(self.context);
586 |
587 | if (myIsDragging) {
588 | var pos = self.getDraggedPosition();
589 | mySelection.render(self.context, pos, myCanPlace ? "#6666ff" : "#ff6666");
590 | } else if (myIsWiring) {
591 | var end = self.getWireEnd();
592 |
593 | self.context.strokeStyle = self.canPlaceWire(new Wire(myWireStart, self.getWireEnd()))
594 | ? "#009900" : "#990000";
595 | self.context.lineWidth = 2;
596 | self.context.beginPath();
597 | self.context.moveTo(myWireStart.x, myWireStart.y);
598 | self.context.lineTo(end.x, end.y);
599 | self.context.stroke();
600 | self.context.closePath();
601 | } else if (myIsSelecting) {
602 | var rect = self.getSelectedRect();
603 |
604 | self.context.beginPath();
605 | self.context.rect(rect.x - 1, rect.y - 1,
606 | rect.width + 2, rect.height + 2);
607 | self.context.globalAlpha = 0.25;
608 | self.context.fillStyle = "#3333ff";
609 | self.context.fill();
610 | self.context.globalAlpha = 0.5;
611 | self.context.strokeStyle = "#6666ff";
612 | self.context.stroke();
613 | self.context.closePath();
614 | self.context.globalAlpha = 1.0;
615 | }
616 |
617 | self.toolbar.render(self.context);
618 | }
619 | }
620 |
621 | logicSim = new LogicSim();
622 |
623 | window.onload = function(e)
624 | {
625 | if (!images.allImagesLoaded()) {
626 | images.onAllLoaded = function()
627 | {
628 | logicSim.initialize();
629 | logicSim.run();
630 | }
631 | } else {
632 | logicSim.initialize();
633 | logicSim.run();
634 | }
635 | }
636 |
637 | window.onmousemove = function(e)
638 | {
639 | if (e) {
640 | logicSim.mouseMove(e.pageX, e.pageY, e);
641 | } else {
642 | logicSim.mouseMove(window.event.clientX, window.event.clientY, window.event);
643 | }
644 | }
645 |
646 | window.onmousedown = function(e)
647 | {
648 | if (e) {
649 | logicSim.mouseDown(e.pageX, e.pageY, e);
650 | } else {
651 | logicSim.mouseDown(window.event.clientX, window.event.clientY, window.event);
652 | }
653 | }
654 |
655 | window.onmouseup = function(e)
656 | {
657 | if (e) {
658 | logicSim.mouseUp(e.pageX, e.pageY, e);
659 | } else {
660 | logicSim.mouseUp(window.event.clientX, window.event.clientY, window.event);
661 | }
662 | }
663 |
664 | window.onclick = function(e)
665 | {
666 | if (e) {
667 | logicSim.click(e.pageX, e.pageY, e);
668 | } else {
669 | logicSim.click(window.event.clientX, window.event.clientY, window.event);
670 | }
671 | }
672 |
673 | window.onkeydown = function(e)
674 | {
675 | logicSim.keyDown(e);
676 | }
677 |
678 | window.onkeyup = function(e)
679 | {
680 | logicSim.keyUp(e);
681 | }
682 |
683 | function onResizeCanvas()
684 | {
685 | logicSim.onResizeCanvas();
686 | }
687 |
--------------------------------------------------------------------------------
/scripts/saving.js:
--------------------------------------------------------------------------------
1 | Saving = new Object();
2 | Saving.save = function()
3 | {
4 | var obj = { ics: [], root: logicSim.save() };
5 |
6 | for (var i = 0; i < logicSim.customGroup.items.length; ++i) {
7 | var ic = logicSim.customGroup.items[i];
8 | obj.ics.push({ name: ic.name, env: ic.environment.save() });
9 | }
10 |
11 | var str = LZString.compressToBase64(JSON.stringify(obj));
12 |
13 | window.open("data:text/plain;charset=UTF-8," + str, "_blank");
14 | }
15 |
16 | Saving.loadFromHash = function()
17 | {
18 | if (window.location.hash === null || window.location.hash.length <= 1) return;
19 | Saving.load(window.location.hash.substring(1));
20 | }
21 |
22 | Saving.loadFromPrompt = function()
23 | {
24 | var str = prompt("Paste a previously copied save code with Ctrl+V.", "");
25 | if (str != null && str.length > 0) Saving.load(str);
26 | }
27 |
28 | Saving.load = function(str)
29 | {
30 | var obj = JSON.parse(LZString.decompressFromBase64(str));
31 |
32 | var ics = new Array();
33 | for (var i = 0; i < obj.ics.length; ++ i) {
34 | var ic = obj.ics[i];
35 | var env = new Environment();
36 | env.load(ic.env, ics);
37 | ics[i] = new CustomIC(ic.name, env);
38 | logicSim.customGroup.addItem(ics[i]);
39 | }
40 |
41 | logicSim.load(obj.root, ics);
42 | }
43 |
--------------------------------------------------------------------------------
/scripts/toolbar.js:
--------------------------------------------------------------------------------
1 | function Toolbar()
2 | {
3 | this.sepimage = new Object();
4 | this.sepimage.end = images.sepend;
5 | this.sepimage.mid = images.sepmid;
6 |
7 | this.arrimage = new Object();
8 | this.arrimage.down = images.arrdown;
9 | this.arrimage.up = images.arrup;
10 |
11 | this.width = 256;
12 | this.isOpen = true;
13 |
14 | this.groups = new Array();
15 |
16 | this.addGroup = function(name, hide)
17 | {
18 | var group = new ToolbarGroup(this, name);
19 | this.groups.push(group);
20 |
21 | if (hide) group.isOpen = false;
22 |
23 | return group;
24 | }
25 |
26 | this.render = function(context)
27 | {
28 | context.fillStyle = "#FFFFFF";
29 | context.fillRect(0, 0, this.width, window.innerHeight);
30 |
31 | var yPos = 0;
32 | for (var i = 0; i < this.groups.length; ++ i)
33 | {
34 | this.groups[i].y = yPos;
35 | yPos += this.groups[i].render(context);
36 | }
37 |
38 | context.fillStyle = "#000000";
39 | context.fillRect(this.width - 1, 0, 1, window.innerHeight);
40 | }
41 |
42 | this.mouseMove = function(x, y)
43 | {
44 | for (var i = 0; i < this.groups.length; ++ i)
45 | this.groups[i].mouseMove(x, y);
46 | }
47 |
48 | this.mouseDown = function(x, y)
49 | {
50 | var yPos = 0;
51 | for (var i = 0; i < this.groups.length; ++ i)
52 | {
53 | var height = this.groups[i].getInnerHeight() + 24;
54 |
55 | if (y < yPos + height)
56 | {
57 | this.groups[i].mouseDown(x, y);
58 | break;
59 | }
60 |
61 | yPos += height;
62 | }
63 | }
64 |
65 | this.mouseUp = function(x, y)
66 | {
67 | var yPos = 0;
68 | for (var i = 0; i < this.groups.length; ++ i)
69 | {
70 | var height = this.groups[i].getInnerHeight() + 24;
71 |
72 | if (y < yPos + height)
73 | {
74 | this.groups[i].mouseUp(x, y);
75 | break;
76 | }
77 |
78 | yPos += height;
79 | }
80 | }
81 |
82 | this.click = function(x, y)
83 | {
84 | var yPos = 0;
85 | for (var i = 0; i < this.groups.length; ++ i)
86 | {
87 | var height = this.groups[i].getInnerHeight() + 24;
88 |
89 | if (y < yPos + height)
90 | {
91 | this.groups[i].click(x, y);
92 | break;
93 | }
94 |
95 | yPos += height;
96 | }
97 | }
98 | }
99 |
100 | function ToolbarGroup(toolbar, name)
101 | {
102 | this.toolbar = toolbar;
103 |
104 | this.name = name;
105 | this.items = new Array();
106 | this.buttons = new Array();
107 |
108 | this.padding = 16;
109 | this.minItemWidth = 80;
110 |
111 | this.y = 0;
112 |
113 | this.isOpen = true;
114 | this.curDelta = 1.0;
115 |
116 | var self = this;
117 |
118 | this.openButton = new Button.Small(0, 0, 24);
119 | this.openButton.mouseDown = function(mouseX, mouseY)
120 | {
121 | if (self.items.length != 0)
122 | {
123 | if (self.isOpen)
124 | self.close();
125 | else
126 | self.open();
127 | }
128 | }
129 | this.buttons.push(this.openButton);
130 |
131 | this.getItemsPerRow = function()
132 | {
133 | return Math.max(Math.floor(this.toolbar.width / this.minItemWidth), 1);
134 | }
135 |
136 | this.getItemWidth = function()
137 | {
138 | return this.toolbar.width / this.getItemsPerRow();
139 | }
140 |
141 | this.getRowCount = function()
142 | {
143 | return Math.ceil(this.items.length / this.getItemsPerRow());
144 | }
145 |
146 | this.getRowHeight = function(row)
147 | {
148 | var start = this.getItemsPerRow() * row;
149 | var end = start + this.getItemsPerRow();
150 |
151 | var height = 0;
152 |
153 | for (var i = start; i < Math.min(end, this.items.length); ++i)
154 | height = Math.max(height, this.items[i].height);
155 |
156 | return height + this.padding;
157 | }
158 |
159 | this.getRowOffset = function(row)
160 | {
161 | row = Math.min(row, this.getRowCount());
162 |
163 | var height = 0;
164 | for (var i = 0; i < row; ++ i)
165 | height += this.getRowHeight(i);
166 |
167 | return height;
168 | }
169 |
170 | this.getInnerHeight = function()
171 | {
172 | var openSize = this.getRowOffset(this.getRowCount());
173 |
174 | this.curDelta += Math.max((1.0 - this.curDelta) / 4.0, 1.0 / openSize);
175 |
176 | if (this.curDelta > 1.0)
177 | this.curDelta = 1.0;
178 |
179 | var delta = this.curDelta;
180 |
181 | if (!this.isOpen)
182 | delta = 1.0 - delta;
183 |
184 | return Math.round(openSize * delta);
185 | }
186 |
187 | this.addItem = function(item)
188 | {
189 | this.items.push(item);
190 | return item;
191 | }
192 |
193 | this.addButton = function(width, contents, mouseDown)
194 | {
195 | var btn = new Button.Small(0, 0, width, contents);
196 | btn.mouseDown = mouseDown;
197 | this.buttons.push(btn);
198 | }
199 |
200 | this.open = function()
201 | {
202 | if (!this.isOpen)
203 | {
204 | this.curDelta = 0.0;
205 | this.isOpen = true;
206 | }
207 | }
208 |
209 | this.close = function()
210 | {
211 | if (this.isOpen)
212 | {
213 | this.curDelta = 0.0;
214 | this.isOpen = false;
215 | }
216 | }
217 |
218 | this.mouseMove = function(x, y)
219 | {
220 | for (var i = this.buttons.length - 1; i >= 0; i--)
221 | this.buttons[i].mouseMove(x, y);
222 | }
223 |
224 | this.mouseDown = function(x, y)
225 | {
226 | if (y <= this.y + 24) {
227 | for (var i = this.buttons.length - 1; i >= 0; i--)
228 | {
229 | var btn = this.buttons[i];
230 | if (btn == this.openButton && this.items.length == 0) continue;
231 | if (btn.isPositionOver(x, y))
232 | {
233 | btn.mouseDown(x, y)
234 | break;
235 | }
236 | }
237 | } else {
238 | var ipr = this.getItemsPerRow();
239 | var wid = this.getItemWidth();
240 | for (var i = 0; i < this.items.length; ++i)
241 | {
242 | var item = this.items[i];
243 | var row = Math.floor(i / ipr);
244 | var imgX = (i % ipr) * wid + (wid - item.width) / 2;
245 | var imgY = this.getRowOffset(row) + this.y + 24
246 | + (this.getRowHeight(row) - item.height) / 2;
247 |
248 | if (x >= imgX && y >= imgY && x < imgX + item.width && y < imgY + item.height)
249 | {
250 | if (item.isGateType)
251 | logicSim.startDragging(item);
252 | else
253 | item.mouseDown(x, y);
254 |
255 | break;
256 | }
257 | }
258 | }
259 | }
260 |
261 | this.mouseUp = function(x, y)
262 | {
263 |
264 | }
265 |
266 | this.click = function(x, y)
267 | {
268 |
269 | }
270 |
271 | this.render = function(context)
272 | {
273 | context.translate(0, this.y);
274 |
275 | context.fillStyle = context.createPattern(this.toolbar.sepimage.mid, "repeat-x");
276 | context.fillRect(1, 0, this.toolbar.width - 2, 24);
277 |
278 | context.drawImage(this.toolbar.sepimage.end, 0, 0);
279 | context.drawImage(this.toolbar.sepimage.end, this.toolbar.width - 2, 0);
280 |
281 | context.translate(0, -this.y);
282 |
283 | this.openButton.image = this.isOpen ? this.toolbar.arrimage.up : this.toolbar.arrimage.down;
284 |
285 | var btnx = this.toolbar.width;
286 | for (var i = 0; i < this.buttons.length; ++i)
287 | {
288 | var btn = this.buttons[i];
289 | if (btn == this.openButton && this.items.length == 0) continue;
290 | btn.y = this.y + 4;
291 | btnx -= btn.width + 4;
292 | btn.x = btnx;
293 | btn.render(context);
294 | }
295 |
296 | context.translate(0, this.y);
297 |
298 | context.fillStyle = "#FFFFFF";
299 | context.font = "bold 12px sans-serif";
300 | context.shadowOffsetX = 0;
301 | context.shadowOffsetY = -1;
302 | context.shadowColor = "#000000";
303 | context.fillText(this.name, 4, 16, this.toolbar.width - 8);
304 |
305 | context.shadowOffsetX = 0;
306 | context.shadowOffsetY = 0;
307 |
308 | context.translate(0, -this.y);
309 |
310 | if (this.isOpen && this.curDelta > 0.9)
311 | {
312 | var ipr = this.getItemsPerRow();
313 | var wid = this.getItemWidth();
314 | for (var i = 0; i < this.items.length; ++i)
315 | {
316 | var item = this.items[i];
317 | var row = Math.floor(i / ipr);
318 | var imgX = (i % ipr) * wid + (wid - item.width) / 2;
319 | var imgY = this.getRowOffset(row) + this.y + 24
320 | + (this.getRowHeight(row) - item.height) / 2;
321 |
322 | if (item.isGateType)
323 | item.render(context, Math.round(imgX), imgY);
324 | else
325 | {
326 | item.x = Math.round(imgX);
327 | item.y = imgY;
328 | item.render(context);
329 | }
330 | }
331 | }
332 |
333 | return 24 + this.getInnerHeight();
334 | }
335 | }
--------------------------------------------------------------------------------
/scripts/tools.js:
--------------------------------------------------------------------------------
1 | Array.prototype.contains = function(obj)
2 | {
3 | var i = this.length;
4 | while (--i >= 0)
5 | if (this[i] === obj)
6 | return true;
7 |
8 | return false;
9 | }
10 |
11 | Array.prototype.pushMany = function(arr)
12 | {
13 | for (var i = 0; i < arr.length; ++i) {
14 | this.push(arr[i]);
15 | }
16 | }
17 |
18 | Array.prototype.containsEqual = function(obj)
19 | {
20 | var i = this.length;
21 | while (--i >= 0)
22 | if (this[i].equals(obj))
23 | return true;
24 |
25 | return false;
26 | }
27 |
28 | var images = new Object();
29 | images.myToLoadCount = 0;
30 | images.onAllLoaded = function() {}
31 |
32 | images.onImageLoad = function()
33 | {
34 | --images.myToLoadCount;
35 |
36 | if(images.myToLoadCount == 0)
37 | images.onAllLoaded();
38 | }
39 |
40 | images.load = function(path)
41 | {
42 | ++images.myToLoadCount;
43 | var img = new Image();
44 | img.src = "images/" + path;
45 |
46 | img.onload = images.onImageLoad;
47 |
48 | images[path.substring(0, path.length - 4)] = img;
49 | return img;
50 | }
51 |
52 | images.allImagesLoaded = function()
53 | {
54 | return (images.myToLoadCount == 0);
55 | }
56 |
57 | images.load("and.png");
58 | images.load("arrdown.png");
59 | images.load("arrup.png");
60 | images.load("btnsmallleft.png");
61 | images.load("btnsmallleftover.png");
62 | images.load("btnsmallmid.png");
63 | images.load("btnsmallmidover.png");
64 | images.load("btnsmallright.png");
65 | images.load("btnsmallrightover.png");
66 | images.load("buffer.png");
67 | images.load("clock.png");
68 | images.load("constoff.png");
69 | images.load("conston.png");
70 | images.load("decoder.png");
71 | images.load("delete.png");
72 | images.load("delic.png");
73 | images.load("dflipflop.png");
74 | images.load("encoder.png");
75 | images.load("input.png");
76 | images.load("move.png");
77 | images.load("nand.png");
78 | images.load("newfile.png");
79 | images.load("newic.png");
80 | images.load("nor.png");
81 | images.load("not.png");
82 | images.load("open.png");
83 | images.load("or.png");
84 | images.load("outoff.png");
85 | images.load("outon.png");
86 | images.load("output.png");
87 | images.load("pushswitchaclosed.png");
88 | images.load("pushswitchaopen.png");
89 | images.load("pushswitchbclosed.png");
90 | images.load("pushswitchbopen.png");
91 | images.load("save.png");
92 | images.load("select.png");
93 | images.load("sepend.png");
94 | images.load("sepmid.png");
95 | images.load("sevsega.png");
96 | images.load("sevsegb.png");
97 | images.load("sevsegbase.png");
98 | images.load("sevsegc.png");
99 | images.load("sevsegd.png");
100 | images.load("sevsegdecoder.png");
101 | images.load("sevsegdp.png");
102 | images.load("sevsege.png");
103 | images.load("sevsegf.png");
104 | images.load("sevsegg.png");
105 | images.load("switchclosed.png");
106 | images.load("switchopen.png");
107 | images.load("xnor.png");
108 | images.load("xor.png");
109 |
110 | function Rect(x, y, width, height)
111 | {
112 | this.x = x;
113 | this.y = y;
114 |
115 | this.width = width;
116 | this.height = height;
117 |
118 | this.left = x;
119 | this.top = y;
120 | this.right = x + width;
121 | this.bottom = y + height;
122 |
123 | this.setLeft = function(value)
124 | {
125 | this.left = value;
126 | this.x = value;
127 | this.width = this.right - value;
128 | }
129 |
130 | this.setTop = function(value)
131 | {
132 | this.top = value;
133 | this.y = value;
134 | this.height = this.bottom - value;
135 | }
136 |
137 | this.setRight = function(value)
138 | {
139 | this.right = value;
140 | this.width = value - this.left;
141 | }
142 |
143 | this.setBottom = function(value)
144 | {
145 | this.bottom = value;
146 | this.height = value - this.top;
147 | }
148 |
149 | this.intersects = function(rect)
150 | {
151 | return this.left < rect.right && rect.left < this.right
152 | && this.top < rect.bottom && rect.top < this.bottom;
153 | }
154 |
155 | this.intersectsWire = function(wire, ends)
156 | {
157 | if (ends) {
158 | return wire.start.x <= this.right && wire.end.x >= this.left
159 | && wire.start.y <= this.bottom && wire.end.y >= this.top;
160 | }
161 |
162 | if (wire.isHorizontal()) {
163 | return wire.start.x < this.right && wire.end.x > this.left
164 | && wire.start.y <= this.bottom && wire.end.y >= this.top;
165 | } else {
166 | return wire.start.x <= this.right && wire.end.x >= this.left
167 | && wire.start.y < this.bottom && wire.end.y > this.top;
168 | }
169 | }
170 |
171 | this.contains = function(pos)
172 | {
173 | return pos.x >= this.left && pos.x <= this.right
174 | && pos.y >= this.top && pos.y <= this.bottom;
175 | }
176 | }
177 |
178 | function Pos(x, y)
179 | {
180 | this.x = x;
181 | this.y = y;
182 |
183 | this.add = function(pos)
184 | {
185 | return new Pos(this.x + pos.x, this.y + pos.y);
186 | }
187 |
188 | this.sub = function(pos)
189 | {
190 | return new Pos(this.x - pos.x, this.y - pos.y);
191 | }
192 |
193 | this.equals = function(pos)
194 | {
195 | return this.x == pos.x && this.y == pos.y;
196 | }
197 |
198 | this.toString = function()
199 | {
200 | return "(" + this.x + "," + this.y + ")";
201 | }
202 | }
--------------------------------------------------------------------------------
/scripts/wire.js:
--------------------------------------------------------------------------------
1 | function Wire(start, end)
2 | {
3 | var myStartConns = new Array();
4 | var myEndConns = new Array();
5 |
6 | this.group = null;
7 |
8 | this.start = new Pos(start.x, start.y);
9 | this.end = new Pos(end.x, end.y);
10 |
11 | this.selected = false;
12 |
13 | if (this.start.x > this.end.x || this.start.y > this.end.y)
14 | {
15 | var temp = this.start;
16 | this.start = this.end;
17 | this.end = temp;
18 | }
19 |
20 | this.clone = function()
21 | {
22 | return new Wire(this.start, this.end);
23 | }
24 |
25 | this.equals = function(wire)
26 | {
27 | return wire.start.equals(this.start) && wire.end.equals(this.end);
28 | }
29 |
30 | this.render = function(context, offset, selectClr)
31 | {
32 | if (this.selected)
33 | {
34 | if (selectClr == null) selectClr = "#6666FF";
35 |
36 | context.globalAlpha = 0.5;
37 | context.fillStyle = selectClr;
38 | context.fillRect(this.start.x + offset.x - 4, this.start.y + offset.y - 4,
39 | this.end.x - this.start.x + 8, this.end.y - this.start.y + 8);
40 | context.globalAlpha = 1.0;
41 | }
42 |
43 | context.strokeStyle = "#000000";
44 | context.lineWidth = 2;
45 |
46 | context.beginPath();
47 | context.moveTo(this.start.x + offset.x, this.start.y + offset.y);
48 | context.lineTo(this.end.x + offset.x, this.end.y + offset.y);
49 | context.stroke();
50 | context.closePath();
51 |
52 | context.fillStyle = "#000000";
53 |
54 | if (myStartConns.length > 1) {
55 | context.beginPath();
56 | context.arc(this.start.x + offset.x, this.start.y + offset.y, 3, 0, Math.PI * 2, true);
57 | context.fill();
58 | context.closePath();
59 | }
60 |
61 | if (myEndConns.length > 1) {
62 | context.beginPath();
63 | context.arc(this.end.x + offset.x, this.end.y + offset.y, 3, 0, Math.PI * 2, true);
64 | context.fill();
65 | context.closePath();
66 | }
67 | }
68 |
69 | this.getConnections = function()
70 | {
71 | return myStartConns.concat(myEndConns);
72 | }
73 |
74 | this.isHorizontal = function()
75 | {
76 | return this.start.y == this.end.y;
77 | }
78 |
79 | this.isVertical = function()
80 | {
81 | return this.start.x == this.end.x;
82 | }
83 |
84 | this.runsAlong = function(wire)
85 | {
86 | return (this.isHorizontal() && wire.isHorizontal()
87 | && this.start.y == wire.start.y && this.start.x <= wire.end.x
88 | && this.end.x >= wire.start.x)
89 | || (this.isVertical() && wire.isVertical()
90 | && this.start.x == wire.start.x && this.start.y <= wire.end.y
91 | && this.end.y >= wire.start.y);
92 | }
93 |
94 | this.split = function(wire)
95 | {
96 | if (this.isHorizontal()) {
97 | if (wire.start.x == this.start.x || wire.start.x == this.end.x) {
98 | return [];
99 | }
100 |
101 | var splat = new Wire(new Pos(wire.start.x, this.start.y), this.end);
102 | splat.group = this.group;
103 | splat.selected = this.selected;
104 | this.end = new Pos(wire.start.x, this.start.y);
105 |
106 | return [splat];
107 | } else {
108 | if (wire.start.y == this.start.y || wire.start.y == this.end.y) {
109 | return [];
110 | }
111 |
112 | var splat = new Wire(new Pos(this.start.x, wire.start.y), this.end);
113 | splat.group = this.group;
114 | splat.selected = this.selected;
115 | this.end = new Pos(this.start.x, wire.start.y);
116 |
117 | return [splat];
118 | }
119 | }
120 |
121 | this.merge = function(wire)
122 | {
123 | this.selected = this.selected || wire.selected;
124 |
125 | if (this.isHorizontal()) {
126 | this.start.x = Math.min(this.start.x, wire.start.x);
127 | this.end.x = Math.max(this.end.x, wire.end.x );
128 | } else {
129 | this.start.y = Math.min(this.start.y, wire.start.y);
130 | this.end.y = Math.max(this.end.y, wire.end.y );
131 | }
132 | }
133 |
134 | this.crossesPos = function(pos)
135 | {
136 | return (this.isHorizontal() && this.start.y == pos.y
137 | && this.start.x <= pos.x && this.end.x >= pos.x)
138 | || (this.isVertical() && this.start.x == pos.x
139 | && this.start.y <= pos.y && this.end.y >= pos.y);
140 | }
141 |
142 | this.intersects = function(wire)
143 | {
144 | return this.start.x <= wire.end.x && this.end.x >= wire.start.x &&
145 | this.start.y <= wire.end.y && this.end.y >= wire.start.y;
146 | }
147 |
148 | this.crosses = function(wire)
149 | {
150 | return this.start.x < wire.end.x && this.end.x > wire.start.x &&
151 | this.start.y < wire.end.y && this.end.y > wire.start.y;
152 | }
153 |
154 | this.crossPos = function(wire)
155 | {
156 | if (this.isVertical() && wire.isHorizontal()) {
157 | return new Pos(this.start.x, wire.start.y);
158 | } else {
159 | return new Pos(wire.start.x, this.start.y);
160 | }
161 | }
162 |
163 | this.canConnect = function(wire)
164 | {
165 | return !myStartConns.contains(wire) && !myEndConns.contains(wire)
166 | && this.intersects(wire) && !this.crosses(wire);
167 | }
168 |
169 | this.hasConnection = function(pos)
170 | {
171 | if (pos.equals(this.start)) {
172 | return myStartConns.length > 0;
173 | }
174 |
175 | if (pos.equals(this.end)) {
176 | return myEndConns.length > 0;
177 | }
178 |
179 | return false;
180 | }
181 |
182 | this.connect = function(wire)
183 | {
184 | if (wire == this) return;
185 |
186 | var conns = myStartConns;
187 |
188 | if (this.end.equals(wire.start) || this.end.equals(wire.end)) {
189 | conns = myEndConns;
190 | }
191 |
192 | if (!conns.contains(wire)) {
193 | conns.push(wire);
194 | }
195 | }
196 |
197 | this.disconnect = function(wire)
198 | {
199 | var index = myConnections.indexOf(wire);
200 | myConnections.splice(index, 1);
201 | }
202 |
203 | this.toString = function()
204 | {
205 | return "(" + this.start.x + "," + this.start.y + ":" + this.end.x + "," + this.end.y + ")";
206 | }
207 | }
--------------------------------------------------------------------------------
/scripts/wiregroup.js:
--------------------------------------------------------------------------------
1 | function WireGroup()
2 | {
3 | var myWires = new Array();
4 | var myBounds = null;
5 |
6 | this.input = null;
7 | this.outputs = new Array();
8 |
9 | this.isEmpty = false;
10 |
11 | this.getWires = function()
12 | {
13 | return myWires;
14 | }
15 |
16 | this.canAddWire = function(wire)
17 | {
18 | if (myBounds == null || !myBounds.intersectsWire(wire, true)) return false;
19 |
20 | for (var i = 0; i < myWires.length; ++ i) {
21 | if (myWires[i].canConnect(wire)) {
22 | return true;
23 | }
24 | }
25 |
26 | return false;
27 | }
28 |
29 | this.crossesPos = function(pos)
30 | {
31 | if (myBounds == null || !myBounds.contains(pos)) return false;
32 |
33 | for (var i = 0; i < myWires.length; ++ i) {
34 | if (myWires[i].crossesPos(pos)) {
35 | return true;
36 | }
37 | }
38 |
39 | return false;
40 | }
41 |
42 | this.getWireAt = function(pos)
43 | {
44 | if (myBounds == null || !myBounds.contains(pos)) return null;
45 |
46 | for (var i = 0; i < myWires.length; ++ i) {
47 | if (myWires[i].crossesPos(pos)) return myWires[i];
48 | }
49 |
50 | return null;
51 | }
52 |
53 | this.setInput = function(gate, output)
54 | {
55 | this.input = new Link(gate, output);
56 |
57 | for (var i = 0; i < this.outputs.length; ++ i) {
58 | var link = this.outputs[i];
59 | link.gate.linkInput(this.input.gate, this.input.socket, link.socket);
60 | }
61 | }
62 |
63 | this.removeInput = function()
64 | {
65 | this.input = null;
66 |
67 | var wires = myWires;
68 | myWires = [];
69 |
70 | for (var i = 0; i < this.outputs.length; ++ i) {
71 | var link = this.outputs[i];
72 | logicSim.removeGate(link.gate);
73 | logicSim.placeGate(link.gate);
74 | }
75 |
76 | myWires = wires;
77 | }
78 |
79 | this.addOutput = function(gate, input)
80 | {
81 | var link = new Link(gate, input);
82 |
83 | if (this.outputs.containsEqual(link)) return;
84 |
85 | if (this.input != null) {
86 | gate.linkInput(this.input.gate, this.input.socket, link.socket);
87 | }
88 |
89 | this.outputs.push(link);
90 | }
91 |
92 | this.removeOutput = function(link)
93 | {
94 | logicSim.removeGate(link.gate);
95 | logicSim.placeGate(link.gate);
96 | }
97 |
98 | this.removeAllOutputs = function()
99 | {
100 | var wires = myWires;
101 | myWires = [];
102 |
103 | for (var i = this.outputs.length - 1; i >= 0; -- i) {
104 | this.removeOutput(this.outputs[i]);
105 | }
106 |
107 | myWires = wires;
108 | }
109 |
110 | this.addWire = function(wire)
111 | {
112 | if (wire.group == this) return;
113 |
114 | if (myBounds == null) {
115 | myBounds = new Rect(wire.start.x, wire.start.y,
116 | wire.end.x - wire.start.x, wire.end.y - wire.start.y);
117 | } else {
118 | if (wire.start.x < myBounds.left) {
119 | myBounds.setLeft(wire.start.x);
120 | }
121 | if (wire.end.x > myBounds.right) {
122 | myBounds.setRight(wire.end.x);
123 | }
124 | if (wire.start.y < myBounds.top) {
125 | myBounds.setTop(wire.start.y);
126 | }
127 | if (wire.end.y > myBounds.bottom) {
128 | myBounds.setBottom(wire.end.y);
129 | }
130 | }
131 |
132 | wire.group = this;
133 |
134 | myWires.push(wire);
135 | }
136 |
137 | this.render = function(context, offset, selectClr)
138 | {
139 | for (var i = 0; i < myWires.length; ++ i) {
140 | myWires[i].render(context, offset, selectClr);
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------