1997 lines
54 KiB
JavaScript
1997 lines
54 KiB
JavaScript
// CircuitCore: adds circuits to sandboxels, logicgates.js is required
|
|
|
|
if (!enabledMods.includes("mods/betterSettings.js")) { enabledMods.unshift("mods/betterSettings.js"); localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); window.location.reload() };
|
|
if (!enabledMods.includes("mods/logicgates.js")) { enabledMods.unshift("mods/logicgates.js"); localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); window.location.reload() };
|
|
var lightmapEnabled = enabledMods.includes("mods/lightmap.js") || enabledMods.includes("mods/fast_lightmap.js");
|
|
|
|
var cc_settingsTab = new SettingsTab("CircuitCore");
|
|
var cc_setting1 = new Setting("If true then circuits will emit heat", "mem_fill", settingType.BOOLEAN, false, defaultValue=true);
|
|
//var cc_setting2 = new Setting("Example Setting 2", "element", settingType.TEXT, false, "2");
|
|
cc_settingsTab.registerSettings("OverHeating", cc_setting1);
|
|
//cc_settingsTab.registerSettings("Setting 2", cc_setting2);
|
|
settingsManager.registerTab(cc_settingsTab);
|
|
|
|
var colorPalette_4bit = [
|
|
"#101820", "#37175F", "#5F1717", "#6F175F",
|
|
"#005F00", "#1563BF", "#7F401A", "#525252",
|
|
"#8F8F8F", "#EE8822", "#FF3027", "#FF47FF",
|
|
"#58E618", "#27FFDF", "#FFFF27", "#FFFFFF"
|
|
];
|
|
|
|
function hueLerp(value) {
|
|
// Clamp the value between -50 and 400
|
|
if (value < -50) value = -50;
|
|
if (value > 400) value = 400;
|
|
|
|
let r, g, b;
|
|
|
|
if (value <= 300) {
|
|
// Interpolate between blue and red
|
|
let t = (value + 50) / 350; // Normalize value from -50 to 300 to a 0-1 range
|
|
r = Math.round(255 * t);
|
|
g = 0;
|
|
b = Math.round(255 * (1 - t));
|
|
} else {
|
|
// Interpolate between red and white
|
|
let t = (value - 300) / 100; // Normalize value from 300 to 400 to a 0-1 range
|
|
r = 255;
|
|
g = Math.round(255 * t);
|
|
b = Math.round(255 * t);
|
|
}
|
|
|
|
// Convert RGB values to a hex string
|
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
|
|
}
|
|
|
|
function cc_rgbToArray(colorString) {
|
|
if (typeof colorString !== 'string') {
|
|
console.error('Invalid colorString:', colorString);
|
|
return null;
|
|
}
|
|
|
|
if (colorString.startsWith('rgb')) {
|
|
return colorString.slice(4, -1).split(',').map(val => parseInt(val.trim()));
|
|
} else if (colorString.startsWith('#')) {
|
|
let hex = colorString.slice(1);
|
|
|
|
// Handle shorthand hex (e.g., #03F)
|
|
if (hex.length === 3) {
|
|
hex = hex.split('').map(char => char + char).join('');
|
|
}
|
|
|
|
if (hex.length !== 6) {
|
|
console.error('Invalid hex color:', colorString);
|
|
return null;
|
|
}
|
|
|
|
const r = parseInt(hex.slice(0, 2), 16);
|
|
const g = parseInt(hex.slice(2, 4), 16);
|
|
const b = parseInt(hex.slice(4, 6), 16);
|
|
|
|
return [r, g, b];
|
|
} else {
|
|
console.error('Invalid color format:', colorString);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function cc_arrayToRgbString(rgbArray) {
|
|
return `rgb(${rgbArray.join(', ')})`;
|
|
}
|
|
|
|
function cc_scaleList(numbers, scale) {
|
|
return numbers.map(number => number * scale);
|
|
}
|
|
|
|
function binaryArrayToNumber(binaryArray) {
|
|
return binaryArray.reduce((acc, bit, index) => acc + bit * Math.pow(2, (binaryArray.length - 1) - index), 0);
|
|
}
|
|
|
|
function hexToPixelGrid(hex) {
|
|
var hexDigitStrings = [
|
|
"111101101101111", // 0
|
|
"001001001001001", // 1
|
|
"111001111100111", // 2
|
|
"111001111001111", // 3
|
|
"101101111001001", // 4
|
|
"111100111001111", // 5
|
|
"111100111101111", // 6
|
|
"111001001001001", // 7
|
|
"111101111101111", // 8
|
|
"111101111001111", // 9
|
|
"111101111101101", // A
|
|
"100100111101111", // B
|
|
"111100100100111", // C
|
|
"001001111101111", // D
|
|
"111100111100111", // E
|
|
"111100111100100" // F
|
|
];
|
|
|
|
if (hex < 0 || hex > 15 || isNaN(hex)) {
|
|
console.log("inputted value: ", hex);
|
|
throw new Error("Input must be a valid 1-digit hexadecimal number.");
|
|
}
|
|
|
|
const binaryString = hexDigitStrings[hex];
|
|
const hexDigitArray = [];
|
|
for (let i = 0; i < 5; i++) {
|
|
hexDigitArray.push(binaryString.slice(i * 3, i * 3 + 3).split('').map(Number));
|
|
}
|
|
return hexDigitArray;
|
|
}
|
|
|
|
// Function to rotate a coordinate around the origin
|
|
function rotateCoordinate(x, y, angle) {
|
|
var radians = angle * (Math.PI / 180);
|
|
var cos = Math.cos(radians);
|
|
var sin = Math.sin(radians);
|
|
|
|
var nx = Math.round(x * cos - y * sin);
|
|
var ny = Math.round(x * sin + y * cos);
|
|
|
|
return [nx, ny];
|
|
}
|
|
|
|
// Initialize the circuit with optional rotation
|
|
function initializeCircuit(pixel, pins, w, h, center=true, rotation=circuitRotation, callback=()=>{}) {
|
|
if (pixel.hasGenerated) {return;}
|
|
|
|
if (!center) {rotation = 0;} // non-centered circuits don't support rotation yet
|
|
pixel.circuitRotation = rotation;
|
|
|
|
createCircuitFrame(pixel, w, h, center, rotation);
|
|
createPins(pixel, pins, rotation);
|
|
callback(pixel, pins, w, h);
|
|
|
|
pixel.hasGenerated = true;
|
|
}
|
|
|
|
function createCircuitFrame(pixel, width_, height_, center=true, rotation=0) {
|
|
var halfHeight = Math.floor(height_ / 2);
|
|
var halfWidth = Math.floor(width_ / 2);
|
|
|
|
var a = -halfHeight;
|
|
var b = halfHeight;
|
|
var c = -halfWidth;
|
|
var d = halfWidth;
|
|
|
|
if (!center) {
|
|
a = 0;
|
|
b = height_ - 1;
|
|
c = 0;
|
|
d = width_ - 1;
|
|
}
|
|
|
|
for (var y = a; y <= b; y++) {
|
|
for (var x = c; x <= d; x++) {
|
|
var [rx, ry] = rotateCoordinate(x, y, rotation);
|
|
var px = pixel.x + rx;
|
|
var py = pixel.y + ry;
|
|
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
|
|
|
|
// Create the pixel
|
|
if (!pixelMap[px] || pixelMap[px][py] === undefined) {
|
|
createPixel("circuit_material", px, py);
|
|
}
|
|
|
|
// Set the core position property
|
|
if (pixelMap[px] && pixelMap[px][py] && pixelMap[px][py].element === "circuit_material") {
|
|
pixelMap[px][py].corePosition = { x: pixel.x, y: pixel.y };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function createPins(pixel, pins, rotation=0) {
|
|
for (var i = 0; i < pins.length; i++) {
|
|
var [rx, ry] = rotateCoordinate(pins[i][0], pins[i][1], rotation);
|
|
var px = pixel.x + rx;
|
|
var py = pixel.y + ry;
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
|
|
|
|
if (!pixelMap[px] || pixelMap[px][py] == undefined) {
|
|
var pinType = pins[i][2] ? "input_pin" : "output_pin";
|
|
createPixel(pinType, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
function checkPin(pixel, pins, index, rotation=pixel.circuitRotation) {
|
|
var [rx, ry] = rotateCoordinate(pins[index][0], pins[index][1], rotation);
|
|
var px = pixel.x + rx;
|
|
var py = pixel.y + ry;
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {return;}
|
|
|
|
return pixelMap[px][py] && pixelMap[px][py].active;
|
|
}
|
|
|
|
function setPin(pixel, pins, index, value, rotation=pixel.circuitRotation) {
|
|
var [rx, ry] = rotateCoordinate(pins[index][0], pins[index][1], rotation);
|
|
var px = pixel.x + rx;
|
|
var py = pixel.y + ry;
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {return;}
|
|
|
|
if (pixelMap[px][py] && pixelMap[px][py].element == "output_pin") {
|
|
pixelMap[px][py].active = value;
|
|
}
|
|
}
|
|
|
|
// Circuits
|
|
elements.four_bit_selector_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// First 4-bit input (A)
|
|
[-7, -2, true], // A0
|
|
[-5, -2, true], // A1
|
|
[-3, -2, true], // A2
|
|
[-1, -2, true], // A3
|
|
|
|
// Second 4-bit input (B)
|
|
[1, -2, true], // B0
|
|
[3, -2, true], // B1
|
|
[5, -2, true], // B2
|
|
[7, -2, true], // B3
|
|
|
|
// Selection pin (Sel)
|
|
[9, 0, true], // Selection (Sel)
|
|
|
|
// Output (O)
|
|
[-3, 2, false], // O0 (centered)
|
|
[-1, 2, false], // O1 (centered)
|
|
[1, 2, false], // O2 (centered)
|
|
[3, 2, false], // O3 (centered)
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 17, 3);
|
|
|
|
// Read inputs
|
|
var A = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var B = [
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5),
|
|
checkPin(pixel, pins, 6),
|
|
checkPin(pixel, pins, 7)
|
|
];
|
|
|
|
var Sel = checkPin(pixel, pins, 8); // Selection pin
|
|
|
|
// Select between A and B based on Sel
|
|
var output = Sel ? B : A;
|
|
|
|
// Output the selected 4-bit value
|
|
setPin(pixel, pins, 9, output[0]); // O0
|
|
setPin(pixel, pins, 10, output[1]); // O1
|
|
setPin(pixel, pins, 11, output[2]); // O2
|
|
setPin(pixel, pins, 12, output[3]); // O3
|
|
}
|
|
};
|
|
|
|
elements.four_bit_enabler_circuit = {
|
|
centered: true,
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-3, -2, true], // D0
|
|
[-1, -2, true], // D1
|
|
[1, -2, true], // D2
|
|
[3, -2, true], // D3
|
|
|
|
// Enable input (E)
|
|
[5, 0, true], // Enable (E)
|
|
|
|
// Enable mirror (E2)
|
|
[-5, 0, false],
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 2, false], // Q0
|
|
[-1, 2, false], // Q1
|
|
[1, 2, false], // Q2
|
|
[3, 2, false] // Q3
|
|
];
|
|
|
|
var elementData = elements[pixel.element];
|
|
initializeCircuit(pixel, pins, 9, 3, elementData.centered);
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var C = checkPin(pixel, pins, 4); // Control input
|
|
setPin(pixel, pins, 5, C);
|
|
|
|
// Previous state initialization
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
}
|
|
|
|
// Update latch state based on control input
|
|
if (C) {
|
|
pixel._state = [D[0], D[1], D[2], D[3]]; // Update latch state with data inputs
|
|
} else {
|
|
pixel._state = [false, false, false, false];
|
|
}
|
|
|
|
// Output the latch state
|
|
setPin(pixel, pins, 6, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 7, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 8, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 9, pixel._state[3]); // Q3
|
|
}
|
|
};
|
|
|
|
elements.randomizer = {
|
|
color: "#FFCCFF",
|
|
cc_stableTick: function(pixel) {
|
|
for (var i = 0; i < adjacentCoords.length; i++) {
|
|
var coord = adjacentCoords[i];
|
|
var x = pixel.x + coord[0];
|
|
var y = pixel.y + coord[1];
|
|
if (!isEmpty(x, y, true)) {
|
|
if (pixelMap[x][y].element == "logic_wire") {
|
|
if (Math.random() < 0.5){
|
|
pixelMap[x][y].lstate = 2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
|
|
} else {
|
|
pixelMap[x][y].lstate = -2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
elements.four_bit_randomizer_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Clock input
|
|
[0, -2, true], // Clock
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 2, false], // Q0
|
|
[-1, 2, false], // Q1
|
|
[1, 2, false], // Q2
|
|
[3, 2, false] // Q3
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 3);
|
|
|
|
// Read clock input
|
|
var clock = checkPin(pixel, pins, 0);
|
|
|
|
// Initialize the state if not already done
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
pixel.prevClock = false;
|
|
}
|
|
|
|
// Detect the positive edge on the clock pin
|
|
if (clock && !pixel.prevClock) {
|
|
// Generate a new 4-bit random number
|
|
var randomValue = Math.floor(Math.random() * 16);
|
|
|
|
// Update the state with the new random value
|
|
pixel._state = [
|
|
(randomValue & 1) !== 0,
|
|
(randomValue & 2) !== 0,
|
|
(randomValue & 4) !== 0,
|
|
(randomValue & 8) !== 0
|
|
];
|
|
}
|
|
|
|
// Output the current state
|
|
setPin(pixel, pins, 1, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 2, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 3, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 4, pixel._state[3]); // Q3
|
|
|
|
// Update previous state of clock input
|
|
pixel.prevClock = clock;
|
|
}
|
|
};
|
|
|
|
var tempVar = 0;
|
|
elements.temperature_sensor = {
|
|
behavior: behaviors.WALL,
|
|
onSelect: function() {
|
|
var answertemp = Number(prompt("Set your target temperature:",(tempVar||undefined)));
|
|
if (!answertemp) { return }
|
|
tempVar = answertemp;
|
|
},
|
|
hoverStat: function(pixel) {
|
|
return `TargetTmp: {pixel.targetTemp}`;
|
|
},
|
|
cc_stableTick: function(pixel) {
|
|
if (pixel.start === pixelTicks){
|
|
pixel.targetTemp = tempVar;
|
|
}
|
|
|
|
pixel.color = hueLerp(pixel.targetTemp);
|
|
|
|
pixel.active = pixel.temp >= pixel.targetTemp;
|
|
var neighbors = getNeighbors(pixel);
|
|
for (var i = 0;i < neighbors.length;i++) {
|
|
var neighbor = neighbors[i];
|
|
|
|
// Check if it's a wire
|
|
if (elements[neighbor.element].conduct > 0 && pixel.active) {
|
|
neighbor.charge = 1;
|
|
}
|
|
|
|
// Check if it's a logic wire (logicgates.js)
|
|
if (neighbor.lstate != undefined) {
|
|
if (pixel.active) {
|
|
neighbor.lstate = 2;
|
|
neighbor.color = pixelColorPick(neighbor, "#ffe49c");
|
|
} else {
|
|
neighbor.lstate = -2;
|
|
neighbor.color = pixelColorPick(neighbor, "#3d4d2c");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*elements.ROM_circuit = {
|
|
previewSize: false,
|
|
cc_stableTick: function(pixel) {
|
|
var romWidth = 16;
|
|
var romHeight = 16;
|
|
|
|
var pins = [
|
|
// Address inputs (D0-D7)
|
|
[-1, 1, true], // D0
|
|
[-1, 3, true], // D1
|
|
[-1, 5, true], // D2
|
|
[-1, 7, true], // D3
|
|
[-1, 9, true], // D4
|
|
[-1, 11, true], // D5
|
|
[-1, 13, true], // D6
|
|
[-1, 15, true], // D7
|
|
|
|
// ROM output
|
|
[romWidth + 2, 1, false],
|
|
[romWidth + 2, 3, false],
|
|
[romWidth + 2, 5, false],
|
|
[romWidth + 2, 7, false],
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, romWidth + 2, romHeight + 2, false, pixel.circuitRotation, addDisplayCallback);
|
|
|
|
// if (!pixel.romData) {pixel.romData = new Array(64).fill(0);}
|
|
if (!pixel.romData) {
|
|
pixel.romData = Array.from({length: romWidth * romHeight}, () => Array.from({length: 4}, () => Math.floor(Math.random() * 2)));
|
|
}
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3),
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5),
|
|
checkPin(pixel, pins, 6),
|
|
checkPin(pixel, pins, 7)
|
|
];
|
|
|
|
var address = binaryArrayToNumber(D);
|
|
if (isNaN(address)) {return;}
|
|
|
|
// Draw the ROM data
|
|
for (var y = 1; y <= romWidth; y++) {
|
|
for (var x = 1; x <= romHeight; x++) {
|
|
var px = pixel.x + x;
|
|
var py = pixel.y + y;
|
|
var cellAddress = ((y - 1) * romWidth) + x - 1;
|
|
var cellData = pixel.romData[cellAddress];
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
|
|
|
|
if (pixelMap[px][py] && pixelMap[px][py].element == "displayPixel") {
|
|
// if (address == cellAddress) {}
|
|
pixelMap[px][py].color = colorPalette_4bit[binaryArrayToNumber(cellData)];
|
|
}
|
|
}
|
|
}
|
|
|
|
var output = pixel.romData[address];
|
|
|
|
setPin(pixel, pins, 8, output[0]);
|
|
setPin(pixel, pins, 9, output[1]);
|
|
setPin(pixel, pins, 10, output[2]);
|
|
setPin(pixel, pins, 11, output[3]);
|
|
}
|
|
};*/
|
|
|
|
function general_encoder(inputBits) {
|
|
return function(pixel) {
|
|
var pins = [];
|
|
var outputBits = Math.ceil(Math.log2(inputBits));
|
|
var circuitWidth = (inputBits * 2) + 1;
|
|
var circuitHeight = (outputBits * 2) + 1;
|
|
|
|
// Define input pins
|
|
for (var i = 0; i < inputBits; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) - 1 - (2 * i), outputBits + 1, true]);
|
|
}
|
|
|
|
// Define output pins
|
|
for (var i = 0; i < outputBits; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) + 1, outputBits - 1 - (2 * i), false]); // Right outputs
|
|
}
|
|
|
|
// Mirrored outputs
|
|
for (var i = 0; i < outputBits; i++) {
|
|
pins.push([-Math.floor(circuitWidth / 2) - 1, outputBits - 1 - (2 * i), false]); // Left outputs
|
|
}
|
|
|
|
initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
|
|
|
|
// Determine which input is active (priority encoder)
|
|
var activeInput = -1;
|
|
for (var i = inputBits - 1; i >= 0; i--) {
|
|
if (checkPin(pixel, pins, i)) {
|
|
activeInput = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set output values based on active input
|
|
for (var i = 0; i < outputBits; i++) {
|
|
var outputValue = activeInput >= 0 ? ((activeInput >> i) & 1) : false;
|
|
setPin(pixel, pins, inputBits + i, outputValue); // Right outputs
|
|
setPin(pixel, pins, inputBits + outputBits + i, outputValue); // Left outputs
|
|
}
|
|
};
|
|
}
|
|
|
|
// Define a 2-to-1 encoder using the general_encoder function
|
|
elements.two_to_one_encoder_circuit = {
|
|
cc_stableTick: general_encoder(2)
|
|
};
|
|
|
|
// Define a 4-to-2 encoder using the general_encoder function
|
|
elements.four_to_two_encoder_circuit = {
|
|
cc_stableTick: general_encoder(4)
|
|
};
|
|
|
|
// Define an 8-to-3 encoder using the general_encoder function
|
|
elements.eight_to_three_encoder_circuit = {
|
|
cc_stableTick: general_encoder(8)
|
|
};
|
|
|
|
// Define a 16-to-4 encoder using the general_encoder function
|
|
elements.sixteen_to_four_encoder_circuit = {
|
|
cc_stableTick: general_encoder(16)
|
|
};
|
|
|
|
function general_demultiplexer(selectorBits) {
|
|
return function(pixel) {
|
|
var pins = [];
|
|
var outputCount = Math.pow(2, selectorBits);
|
|
var circuitWidth = 3;
|
|
var circuitHeight = (outputCount * 2) + 1;
|
|
|
|
// Define the input pin
|
|
pins.push([0, Math.floor(circuitHeight / 2) + 1, true]);
|
|
|
|
// Define selector pins
|
|
for (var i = 0; i < selectorBits; i++) {
|
|
pins.push([-2, (Math.floor(circuitHeight / 2) - 1) - (2 * i), true]);
|
|
}
|
|
|
|
// Define output pins
|
|
for (var i = 0; i < outputCount; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) + 1, Math.floor(circuitHeight / 2) - 1 - (2 * i), false]);
|
|
}
|
|
|
|
initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
|
|
|
|
// Read input and selector values
|
|
var input = checkPin(pixel, pins, 0);
|
|
var selector = 0;
|
|
for (var i = 0; i < selectorBits; i++) {
|
|
if (checkPin(pixel, pins, 1 + i)) {
|
|
selector += Math.pow(2, i);
|
|
}
|
|
}
|
|
|
|
// Set output values based on selector
|
|
for (var i = 0; i < outputCount; i++) {
|
|
setPin(pixel, pins, 1 + selectorBits + i, i === selector ? input : false);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Define a 1-to-2 demultiplexer using the general_demultiplexer function
|
|
elements.one_to_two_demultiplexer_circuit = {
|
|
cc_stableTick: general_demultiplexer(1)
|
|
};
|
|
|
|
// Define a 1-to-4 demultiplexer using the general_demultiplexer function
|
|
elements.one_to_four_demultiplexer_circuit = {
|
|
cc_stableTick: general_demultiplexer(2)
|
|
};
|
|
|
|
// Define a 1-to-8 demultiplexer using the general_demultiplexer function
|
|
elements.one_to_eight_demultiplexer_circuit = {
|
|
cc_stableTick: general_demultiplexer(3)
|
|
};
|
|
|
|
// Define a 1-to-16 demultiplexer using the general_demultiplexer function
|
|
elements.one_to_sixteen_demultiplexer_circuit = {
|
|
cc_stableTick: general_demultiplexer(4)
|
|
};
|
|
|
|
function general_decoder(inputBits) {
|
|
return function(pixel) {
|
|
var pins = [];
|
|
var outputCount = Math.pow(2, inputBits);
|
|
var circuitWidth = (inputBits * 2) + 1;
|
|
var circuitHeight = (outputCount * 2) + 1;
|
|
|
|
// Define input pins
|
|
for (var i = 0; i < inputBits; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) - 1 - (2 * i), outputCount + 1, true]);
|
|
}
|
|
|
|
// Define output pins
|
|
for (var i = 0; i < outputCount; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) + 1, outputCount - 1 - (2 * i), false]); // Right outputs
|
|
}
|
|
|
|
for (var i = 0; i < outputCount; i++) {
|
|
pins.push([-Math.floor(circuitWidth / 2) - 1, outputCount - 1 - (2 * i), false]); // Left outputs
|
|
}
|
|
|
|
initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
|
|
|
|
// Read input values
|
|
var input = 0;
|
|
for (var i = 0; i < inputBits; i++) {
|
|
if (checkPin(pixel, pins, i)) {
|
|
input += Math.pow(2, i);
|
|
}
|
|
}
|
|
|
|
// Set output values
|
|
for (var i = 0; i < outputCount; i++) {
|
|
var outputValue = (i === input);
|
|
setPin(pixel, pins, inputBits + i, outputValue); // Right outputs
|
|
setPin(pixel, pins, inputBits + outputCount + i, outputValue); // Left outputs
|
|
}
|
|
};
|
|
}
|
|
|
|
elements.one_to_two_decoder_circuit = {
|
|
cc_stableTick: general_decoder(1)
|
|
};
|
|
|
|
elements.two_to_four_decoder_circuit = {
|
|
cc_stableTick: general_decoder(2)
|
|
};
|
|
|
|
elements.three_to_eight_decoder_circuit = {
|
|
cc_stableTick: general_decoder(3)
|
|
};
|
|
|
|
elements.four_to_sixteen_decoder_circuit = {
|
|
cc_stableTick: general_decoder(4)
|
|
};
|
|
|
|
function general_multiplexer(inputLines) {
|
|
return function(pixel) {
|
|
var pins = [];
|
|
var selectorBits = Math.ceil(Math.log2(inputLines));
|
|
var circuitWidth = (selectorBits * 2) + 1;
|
|
var circuitHeight = (inputLines * 2) + 1;
|
|
|
|
// Define selector pins
|
|
for (var i = 0; i < selectorBits; i++) {
|
|
pins.push([Math.floor(circuitWidth / 2) - 1 - (2 * i), inputLines + 1, true]);
|
|
}
|
|
|
|
// Define input data pins
|
|
for (var i = 0; i < inputLines; i++) {
|
|
pins.push([-Math.floor(circuitWidth / 2) - 1, inputLines - 1 - (2 * i), true]);
|
|
}
|
|
|
|
// Define output pin
|
|
pins.push([Math.floor(circuitWidth / 2) + 1, 0, false]);
|
|
|
|
initializeCircuit(pixel, pins, circuitWidth, circuitHeight);
|
|
|
|
// Read selector input
|
|
var selector = 0;
|
|
for (var i = 0; i < selectorBits; i++) {
|
|
if (checkPin(pixel, pins, i)) {
|
|
selector += Math.pow(2, i);
|
|
}
|
|
}
|
|
|
|
setPin(pixel, pins, selectorBits + inputLines, checkPin(pixel, pins, selector + selectorBits)); // Output pin
|
|
};
|
|
}
|
|
|
|
// Define a 2-input multiplexer using the general_multiplexer function
|
|
elements.two_to_one_multiplexer_circuit = {
|
|
cc_stableTick: general_multiplexer(2)
|
|
};
|
|
|
|
// Define a 4-input multiplexer using the general_multiplexer function
|
|
elements.four_to_one_multiplexer_circuit = {
|
|
cc_stableTick: general_multiplexer(4)
|
|
};
|
|
|
|
// Define an 8-input multiplexer using the general_multiplexer function
|
|
elements.eight_to_one_multiplexer_circuit = {
|
|
cc_stableTick: general_multiplexer(8)
|
|
};
|
|
|
|
// Define an 8-input multiplexer using the general_multiplexer function
|
|
elements.sixteen_to_one_multiplexer_circuit = {
|
|
cc_stableTick: general_multiplexer(16)
|
|
};
|
|
|
|
elements.four_bit_PISO_shift_register_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[3, -3, true], // D3
|
|
[1, -3, true], // D2
|
|
[-1, -3, true], // D1
|
|
[-3, -3, true], // D0
|
|
|
|
// Control input (Load/Shift Enable)
|
|
[-5, -1, true], // Load/Shift Enable
|
|
|
|
// Clock input
|
|
[-5, 1, true], // Clock
|
|
|
|
// Serial output
|
|
[5, -1, false], // Serial Out (Q)
|
|
[5, 1, false] // Transmission Flag
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 5);
|
|
|
|
// Read data inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
// Read control and clock inputs
|
|
var loadShiftEnable = checkPin(pixel, pins, 4);
|
|
var clock = checkPin(pixel, pins, 5);
|
|
|
|
// Initialize the state if not already done
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
pixel.bitIndex = 0;
|
|
pixel.prevLoadShiftEnable = false;
|
|
pixel.prevClock = false;
|
|
}
|
|
|
|
// Detect the positive edge on the control pin
|
|
if (loadShiftEnable && !pixel.prevLoadShiftEnable) {
|
|
// Load the data into the register on the first positive edge
|
|
pixel._state = [D[0], D[1], D[2], D[3]];
|
|
pixel.bitIndex = 0;
|
|
}
|
|
|
|
// Detect the positive edge on the clock pin
|
|
if (clock && !pixel.prevClock) {
|
|
if (pixel.bitIndex < 4) {
|
|
// Shift the register and output the next bit
|
|
var serialOut = pixel._state[0];
|
|
for (var i = 0; i < 3; i++) {
|
|
pixel._state[i] = pixel._state[i + 1];
|
|
}
|
|
pixel._state[3] = false; // Clear the last bit after shifting
|
|
|
|
// Output the serial value
|
|
setPin(pixel, pins, 6, serialOut);
|
|
|
|
// Update bit index
|
|
pixel.bitIndex++;
|
|
}
|
|
}
|
|
|
|
// Set the transmission flag
|
|
var transmitting = pixel.bitIndex < 4 && loadShiftEnable;
|
|
setPin(pixel, pins, 7, transmitting);
|
|
|
|
// Update previous state of control and clock inputs
|
|
pixel.prevLoadShiftEnable = loadShiftEnable;
|
|
pixel.prevClock = clock;
|
|
}
|
|
};
|
|
|
|
elements.four_bit_SIPO_shift_register_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Serial input (Data In)
|
|
[-2, -3, true], // Data In
|
|
|
|
// Clock input
|
|
[-2, -1, true], // Clock
|
|
|
|
// Parallel outputs (Q0-Q3)
|
|
[2, 3, false], // Q3
|
|
[2, 1, false], // Q2
|
|
[2, -1, false], // Q1
|
|
[2, -3, false] // Q0
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 3, 9);
|
|
|
|
// Read serial and clock input
|
|
var serialIn = checkPin(pixel, pins, 0);
|
|
var clock = checkPin(pixel, pins, 1);
|
|
|
|
// Initialize the state if not already done
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
pixel.prevClock = false;
|
|
}
|
|
|
|
// Detect the positive edge on the clock pin
|
|
if (clock && !pixel.prevClock) {
|
|
pixel._state = [serialIn, pixel._state[0], pixel._state[1], pixel._state[2]];
|
|
}
|
|
|
|
// Output the parallel values
|
|
for (var i = 0; i < 4; i++) {
|
|
setPin(pixel, pins, 2 + i, pixel._state[i]);
|
|
}
|
|
|
|
// Update previous state of control and clock inputs
|
|
pixel.prevClock = clock;
|
|
}
|
|
};
|
|
|
|
elements.four_bit_program_counter_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-3, -3, true], // D0
|
|
[-1, -3, true], // D1
|
|
[1, -3, true], // D2
|
|
[3, -3, true], // D3
|
|
|
|
// Control inputs (Increment, Write Enable)
|
|
[5, -1, true], // Increment
|
|
[5, 1, true], // Write Enable
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 3, false], // Q0
|
|
[-1, 3, false], // Q1
|
|
[1, 3, false], // Q2
|
|
[3, 3, false], // Q3
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 5);
|
|
|
|
// Read data inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
// Read control inputs
|
|
var Increment = checkPin(pixel, pins, 4);
|
|
var WriteEnable = checkPin(pixel, pins, 5);
|
|
|
|
// Initialize the state if not already done
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
pixel.prevIncrement = false; // Previous state of Increment pin
|
|
}
|
|
|
|
// Convert the state to a 4-bit binary number
|
|
var stateValue = binaryArrayToNumber(pixel._state);
|
|
|
|
// Detect the positive edge on the Increment pin
|
|
if (Increment && !pixel.prevIncrement) {
|
|
stateValue = (stateValue + 1) % 16; // Ensure the value wraps around at 4 bits
|
|
}
|
|
|
|
// Update the register state if WriteEnable is active
|
|
if (WriteEnable) {
|
|
stateValue = binaryArrayToNumber(D); // Load data inputs into state
|
|
}
|
|
|
|
// Update the state
|
|
pixel._state = [
|
|
(stateValue & 8) !== 0,
|
|
(stateValue & 4) !== 0,
|
|
(stateValue & 2) !== 0,
|
|
(stateValue & 1) !== 0
|
|
];
|
|
|
|
// Output the register state
|
|
setPin(pixel, pins, 6, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 7, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 8, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 9, pixel._state[3]); // Q3
|
|
|
|
// Update previous state of Increment pin
|
|
pixel.prevIncrement = Increment;
|
|
}
|
|
};
|
|
|
|
elements.four_bit_register_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-3, -3, true], // D0
|
|
[-1, -3, true], // D1
|
|
[1, -3, true], // D2
|
|
[3, -3, true], // D3
|
|
|
|
// Control inputs (Enable, Write Enable)
|
|
[5, -1, true], // Enable
|
|
[5, 1, true], // Write Enable
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 3, false], // Q0
|
|
[-1, 3, false], // Q1
|
|
[1, 3, false], // Q2
|
|
[3, 3, false], // Q3
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 5);
|
|
|
|
// Read data inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
// Read control inputs
|
|
var Enable = checkPin(pixel, pins, 4);
|
|
var WriteEnable = checkPin(pixel, pins, 5);
|
|
|
|
// Initialize the state if not already done
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
}
|
|
|
|
// Update the register state if WriteEnable is active
|
|
if (WriteEnable && Enable) {
|
|
pixel._state = [D[0], D[1], D[2], D[3]];
|
|
}
|
|
|
|
// Output the register state if Enable is active
|
|
if (Enable) {
|
|
setPin(pixel, pins, 6, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 7, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 8, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 9, pixel._state[3]); // Q3
|
|
} else {
|
|
// Disable outputs if Enable is not active
|
|
setPin(pixel, pins, 6, false); // Q0
|
|
setPin(pixel, pins, 7, false); // Q1
|
|
setPin(pixel, pins, 8, false); // Q2
|
|
setPin(pixel, pins, 9, false); // Q3
|
|
}
|
|
}
|
|
};
|
|
|
|
elements.SR_latch_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
[0, -2, true], // Input: Set
|
|
[0, 2, true], // Input: Reset
|
|
[2, 0, false], // Output
|
|
[-2, 0, false] // Output
|
|
];
|
|
initializeCircuit(pixel, pins, 3, 3);
|
|
|
|
if (checkPin(pixel, pins, 0)) {pixel._state = true;} // Set
|
|
if (checkPin(pixel, pins, 1)) {pixel._state = false;} // Reset
|
|
|
|
setPin(pixel, pins, 2, pixel._state);
|
|
setPin(pixel, pins, 3, pixel._state);
|
|
}
|
|
};
|
|
|
|
elements.T_flip_flop_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
[0, -2, true], // Input: Toggle (T)
|
|
[2, 0, false], // Output (Q)
|
|
[-2, 0, false] // Output (not Q) - Optional
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 3, 3);
|
|
|
|
// Check the current state of the Toggle (T) input
|
|
var T = checkPin(pixel, pins, 0);
|
|
|
|
// Initialize the previous state of T if not already done
|
|
if (pixel.prevT === undefined) {
|
|
pixel.prevT = false;
|
|
}
|
|
|
|
// Detect the positive edge
|
|
if (T && !pixel.prevT) {
|
|
pixel._state = !pixel._state; // Toggle state on positive edge
|
|
}
|
|
|
|
// Update the previous state of T
|
|
pixel.prevT = T;
|
|
|
|
setPin(pixel, pins, 1, pixel._state);
|
|
setPin(pixel, pins, 2, pixel._state);
|
|
}
|
|
};
|
|
|
|
elements.D_latch_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
[0, -2, true], // Input: Data
|
|
[2, 0, true], // Input: Enable
|
|
[0, 2, false], // Output
|
|
[-2, 0, false] // Output
|
|
];
|
|
initializeCircuit(pixel, pins, 3, 3);
|
|
|
|
var D = checkPin(pixel, pins, 0); // Data input
|
|
var E = checkPin(pixel, pins, 1); // Enable input
|
|
|
|
if (E) {
|
|
pixel._state = D; // Q follows D when E is active
|
|
}
|
|
|
|
setPin(pixel, pins, 2, pixel._state);
|
|
setPin(pixel, pins, 3, pixel._state);
|
|
}
|
|
};
|
|
|
|
elements.D_flip_flop_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
[0, -2, true], // Input: Data
|
|
[2, 0, true], // Input: Enable
|
|
[0, 2, false], // Output
|
|
[-2, 0, false] // Output
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 3, 3);
|
|
|
|
// Read inputs
|
|
var D = checkPin(pixel, pins, 0); // Data input
|
|
var C = checkPin(pixel, pins, 1); // Control input
|
|
|
|
// Initialize previous state of control input if not already done
|
|
if (pixel.prevC === undefined) {
|
|
pixel.prevC = false;
|
|
}
|
|
|
|
// Previous state initialization
|
|
if (pixel._state === undefined) {
|
|
pixel._state = false;
|
|
}
|
|
|
|
// Update flip-flop state on positive edge of control input
|
|
if (C && !pixel.prevC) {
|
|
pixel._state = D; // Q follows D on positive edge of C
|
|
}
|
|
|
|
// Update the previous state of control input
|
|
pixel.prevC = C;
|
|
|
|
// Output the flip-flop state
|
|
setPin(pixel, pins, 2, pixel._state);
|
|
setPin(pixel, pins, 3, pixel._state);
|
|
}
|
|
};
|
|
|
|
elements.four_bit_D_latch_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-3, -2, true], // D0
|
|
[-1, -2, true], // D1
|
|
[1, -2, true], // D2
|
|
[3, -2, true], // D3
|
|
|
|
// Control input (C)
|
|
[5, 0, true], // Control (C)
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 2, false], // Q0
|
|
[-1, 2, false], // Q1
|
|
[1, 2, false], // Q2
|
|
[3, 2, false] // Q3
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 3);
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var C = checkPin(pixel, pins, 4); // Control input
|
|
|
|
// Previous state initialization
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
}
|
|
|
|
// Update latch state based on control input
|
|
if (C) {
|
|
pixel._state = [D[0], D[1], D[2], D[3]]; // Update latch state with data inputs
|
|
}
|
|
|
|
// Output the latch state
|
|
setPin(pixel, pins, 5, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 6, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 7, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 8, pixel._state[3]); // Q3
|
|
}
|
|
};
|
|
|
|
elements.four_bit_D_flip_flop_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-3, -2, true], // D0
|
|
[-1, -2, true], // D1
|
|
[1, -2, true], // D2
|
|
[3, -2, true], // D3
|
|
|
|
// Control input (C)
|
|
[5, 0, true], // Control (C)
|
|
|
|
// Outputs (Q0-Q3)
|
|
[-3, 2, false], // Q0
|
|
[-1, 2, false], // Q1
|
|
[1, 2, false], // Q2
|
|
[3, 2, false] // Q3
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 3);
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var C = checkPin(pixel, pins, 4); // Control input
|
|
|
|
// Initialize previous state of control input if not already done
|
|
if (pixel.prevC === undefined) {
|
|
pixel.prevC = false;
|
|
}
|
|
|
|
// Previous state initialization
|
|
if (pixel._state === undefined) {
|
|
pixel._state = [false, false, false, false];
|
|
}
|
|
|
|
// Update flip-flop state on positive edge of control input
|
|
if (C && !pixel.prevC) {
|
|
pixel._state = [D[0], D[1], D[2], D[3]]; // Update flip-flop state with data inputs
|
|
}
|
|
|
|
// Update the previous state of control input
|
|
pixel.prevC = C;
|
|
|
|
// Output the flip-flop state
|
|
setPin(pixel, pins, 5, pixel._state[0]); // Q0
|
|
setPin(pixel, pins, 6, pixel._state[1]); // Q1
|
|
setPin(pixel, pins, 7, pixel._state[2]); // Q2
|
|
setPin(pixel, pins, 8, pixel._state[3]); // Q3
|
|
}
|
|
};
|
|
|
|
elements.four_bit_incrementer_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// 4-bit number inputs (N0-N3)
|
|
[3, -2, true], // N3
|
|
[1, -2, true], // N2
|
|
[-1, -2, true], // N1
|
|
[-3, -2, true], // N0
|
|
|
|
// Increment control input (INC)
|
|
[-5, 0, true], // Increment (INC)
|
|
|
|
// Outputs (Q0-Q3)
|
|
[3, 2, false], // Q3
|
|
[1, 2, false], // Q2
|
|
[-1, 2, false], // Q1
|
|
[-3, 2, false], // Q0
|
|
|
|
// Carry out
|
|
[5, 0, false] // Carry out (COUT)
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 3);
|
|
|
|
// Read inputs
|
|
var N = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var INC = checkPin(pixel, pins, 4); // Increment control input
|
|
|
|
// Calculate the incremented value when control is active
|
|
var carry = 0;
|
|
var result = [];
|
|
|
|
if (INC) {
|
|
carry = 1; // Start with a carry of 1 to increment by 1
|
|
}
|
|
|
|
for (var i = 0; i < 4; i++) {
|
|
var sum = N[i] + carry;
|
|
result[i] = sum % 2; // Current bit sum
|
|
carry = Math.floor(sum / 2); // Carry for next bit
|
|
}
|
|
|
|
// Output the incremented value and carry out
|
|
setPin(pixel, pins, 5, result[0]); // Q0
|
|
setPin(pixel, pins, 6, result[1]); // Q1
|
|
setPin(pixel, pins, 7, result[2]); // Q2
|
|
setPin(pixel, pins, 8, result[3]); // Q3
|
|
setPin(pixel, pins, 9, carry); // Carry out (COUT)
|
|
}
|
|
};
|
|
|
|
elements.four_bit_adder_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// First 4-bit number (A)
|
|
[-1, -2, true], // A3
|
|
[-3, -2, true], // A2
|
|
[-5, -2, true], // A1
|
|
[-7, -2, true], // A0
|
|
|
|
// Second 4-bit number (B)
|
|
[7, -2, true], // B3
|
|
[5, -2, true], // B2
|
|
[3, -2, true], // B1
|
|
[1, -2, true], // B0
|
|
|
|
// Carry-in (C_in)
|
|
[9, 0, true], // Carry-in (C_in)
|
|
|
|
// Output sum (S)
|
|
[-1, 2, false], // S3
|
|
[-3, 2, false], // S2
|
|
[-5, 2, false], // S1
|
|
[-7, 2, false], // S0
|
|
[1, 2, false], // Carry Out (C4)
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 17, 3);
|
|
|
|
// Read inputs
|
|
var A = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var B = [
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5),
|
|
checkPin(pixel, pins, 6),
|
|
checkPin(pixel, pins, 7)
|
|
];
|
|
|
|
var C_in = checkPin(pixel, pins, 8); // Carry-in
|
|
|
|
// Calculate the sum and carry
|
|
var sum = [];
|
|
var carry = C_in;
|
|
|
|
for (var i = 0; i < 4; i++) {
|
|
var bitSum = A[i] + B[i] + carry;
|
|
sum[i] = bitSum % 2; // Current bit sum
|
|
carry = Math.floor(bitSum / 2); // Carry for next bit
|
|
}
|
|
|
|
// Output the sum
|
|
setPin(pixel, pins, 9, sum[0]); // S0
|
|
setPin(pixel, pins, 10, sum[1]); // S1
|
|
setPin(pixel, pins, 11, sum[2]); // S2
|
|
setPin(pixel, pins, 12, sum[3]); // S3
|
|
setPin(pixel, pins, 13, carry); // Carry Out (C4)
|
|
}
|
|
};
|
|
|
|
elements.four_bit_subtractor_circuit = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// First 4-bit number (A)
|
|
[-1, -2, true], // A3
|
|
[-3, -2, true], // A2
|
|
[-5, -2, true], // A1
|
|
[-7, -2, true], // A0
|
|
|
|
// Second 4-bit number (B)
|
|
[7, -2, true], // B3
|
|
[5, -2, true], // B2
|
|
[3, -2, true], // B1
|
|
[1, -2, true], // B0
|
|
|
|
// Borrow-in (B_in)
|
|
[9, 0, true], // Borrow-in (B_in)
|
|
|
|
// Output difference (D)
|
|
[-1, 2, false], // D3
|
|
[-3, 2, false], // D2
|
|
[-5, 2, false], // D1
|
|
[-7, 2, false], // D0
|
|
[1, 2, false], // Borrow Out (B4)
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 17, 3);
|
|
|
|
// Read inputs
|
|
var A = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var B = [
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5),
|
|
checkPin(pixel, pins, 6),
|
|
checkPin(pixel, pins, 7)
|
|
];
|
|
|
|
var B_in = checkPin(pixel, pins, 8); // Borrow-in
|
|
|
|
// Calculate the difference and borrow
|
|
var difference = [];
|
|
var borrow = B_in;
|
|
|
|
for (var i = 0; i < 4; i++) {
|
|
var bitDifference = A[i] - B[i] - borrow;
|
|
difference[i] = (bitDifference + 2) % 2; // Current bit difference
|
|
borrow = bitDifference < 0 ? 1 : 0; // Borrow for next bit
|
|
}
|
|
|
|
// Output the difference
|
|
setPin(pixel, pins, 9, difference[0]); // D0
|
|
setPin(pixel, pins, 10, difference[1]); // D1
|
|
setPin(pixel, pins, 11, difference[2]); // D2
|
|
setPin(pixel, pins, 12, difference[3]); // D3
|
|
setPin(pixel, pins, 13, borrow); // Borrow Out (B4)
|
|
}
|
|
};
|
|
|
|
function general_clock(speed, s2) {
|
|
return function(pixel){
|
|
for (var i = 0; i < adjacentCoords.length; i++) {
|
|
var coord = adjacentCoords[i];
|
|
var x = pixel.x+coord[0];
|
|
var y = pixel.y+coord[1];
|
|
if (!isEmpty(x,y,true)) {
|
|
if (pixelMap[x][y].element == "logic_wire"){
|
|
if (pixelTicks % speed < s2){
|
|
pixelMap[x][y].lstate = 2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
|
|
} else {
|
|
pixelMap[x][y].lstate = -2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
elements.slow_clock = {
|
|
color: "#BB66BB",
|
|
cc_stableTick: general_clock(64, 32),
|
|
}
|
|
|
|
elements.medium_clock = {
|
|
color: "#DD88DD",
|
|
cc_stableTick: general_clock(32, 16),
|
|
}
|
|
|
|
elements.fast_clock = {
|
|
color: "#FFAAFF",
|
|
cc_stableTick: general_clock(16, 8),
|
|
}
|
|
|
|
elements.very_fast_clock = {
|
|
color: "#FFCCFF",
|
|
cc_stableTick: general_clock(8, 4),
|
|
}
|
|
|
|
elements.custom_RGB_led = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// RGB values
|
|
[-2, -1, true], // R0
|
|
[-2, 1, true], // R1
|
|
[1, -2, true], // G0
|
|
[-1, -2, true], // G1
|
|
[2, -1, true], // B0
|
|
[2, 1, true], // B1
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 3, 3);
|
|
|
|
// Read inputs
|
|
var l = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3),
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5)
|
|
];
|
|
|
|
var color = { color: cc_scaleList([(l[0] * 2) + l[1], (l[2] * 2) + l[3], (l[4] * 2) + l[5]], (255 / 3) * 10) };
|
|
if (color.color.some(value => isNaN(value))) {return;}
|
|
|
|
if (lightmapEnabled && color.color[0] && color.color[1], color.color[2]) {
|
|
lightmap[Math.floor(pixel.y / lightmapScale)][Math.floor(pixel.x / lightmapScale)] = color;
|
|
}
|
|
var scaledColor = cc_scaleList(color.color, 0.1);
|
|
|
|
// pixelMap[pixel.x][pixel.y].color = scaledColor;
|
|
for (let dx = -1; dx <= 1; dx++) {
|
|
for (let dy = -1; dy <= 1; dy++) {
|
|
var nx = pixel.x + dx;
|
|
var ny = pixel.y + dy;
|
|
|
|
if (pixelMap[nx] && pixelMap[nx][ny]) {
|
|
var n = ((2 - (Math.abs(dx) + Math.abs(dy))) + 4) / 6;
|
|
pixelMap[nx][ny].color = cc_arrayToRgbString(cc_scaleList(scaledColor, n));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var addDisplayCallback = function(pixel, pins, w, h) {
|
|
for (var y = 1; y < h - 1; y++) {
|
|
for (var x = 1; x < w - 1; x++) {
|
|
var px = pixel.x + x;
|
|
var py = pixel.y + y;
|
|
if (!(0 <= px && px < width && 0 <= py && py < height)) {continue;}
|
|
|
|
deletePixel(px, py);
|
|
createPixel("displayPixel", px, py);
|
|
pixelMap[px][py].color = "rgb(16, 24, 32)";
|
|
}
|
|
}
|
|
}
|
|
|
|
elements.simple_seven_segment_display = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-1, 7, true],
|
|
[-1, 5, true],
|
|
[-1, 3, true],
|
|
[-1, 1, true],
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 5, 9, false, pixel.circuitRotation, addDisplayCallback);
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3)
|
|
];
|
|
|
|
var hexNumber = (D[3] * 8) + (D[2] * 4) + (D[1] * 2) + (D[0] * 1);
|
|
if (isNaN(hexNumber)) {return;}
|
|
|
|
// Draw the number
|
|
var hexGrid = hexToPixelGrid(hexNumber);
|
|
for (var y = 2; y <= 6; y++) {
|
|
for (var x = 1; x <= 3; x++) {
|
|
var px = pixel.x + x;
|
|
var py = pixel.y + y;
|
|
|
|
if (pixelMap[px][py] && pixelMap[px][py].element == "displayPixel") {
|
|
if (hexGrid[y - 2][x - 1]) {
|
|
pixelMap[px][py].color = "rgb(16, 230, 120)";
|
|
} else {
|
|
pixelMap[px][py].color = "rgb(16, 24, 32)";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
elements.simple_double_seven_segment_display = {
|
|
cc_stableTick: function(pixel) {
|
|
var pins = [
|
|
// Data inputs (D0-D3)
|
|
[-1, 7, true],
|
|
[-1, 5, true],
|
|
[-1, 3, true],
|
|
[-1, 1, true],
|
|
|
|
[7, -1, true],
|
|
[5, -1, true],
|
|
[3, -1, true],
|
|
[1, -1, true],
|
|
];
|
|
|
|
initializeCircuit(pixel, pins, 9, 9, false, pixel.circuitRotation, addDisplayCallback);
|
|
|
|
// Read inputs
|
|
var D = [
|
|
checkPin(pixel, pins, 0),
|
|
checkPin(pixel, pins, 1),
|
|
checkPin(pixel, pins, 2),
|
|
checkPin(pixel, pins, 3),
|
|
checkPin(pixel, pins, 4),
|
|
checkPin(pixel, pins, 5),
|
|
checkPin(pixel, pins, 6),
|
|
checkPin(pixel, pins, 7)
|
|
];
|
|
|
|
var hexNumber = (D[3] * 8) + (D[2] * 4) + (D[1] * 2) + (D[0] * 1);
|
|
var hexNumber2 = (D[7] * 8) + (D[6] * 4) + (D[5] * 2) + (D[4] * 1);
|
|
if (isNaN(hexNumber) || isNaN(hexNumber2)) {return;}
|
|
|
|
// Draw the number
|
|
var hexGrid = hexToPixelGrid(hexNumber);
|
|
for (var y = 2; y <= 6; y++) {
|
|
for (var x = 1; x <= 3; x++) {
|
|
var px = pixel.x + x;
|
|
var py = pixel.y + y;
|
|
|
|
if (pixelMap[px][py] && pixelMap[px][py].element == "displayPixel") {
|
|
if (hexGrid[y - 2][x - 1]) {
|
|
pixelMap[px][py].color = "rgb(16, 230, 120)";
|
|
} else {
|
|
pixelMap[px][py].color = "rgb(16, 24, 32)";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var hexGrid2 = hexToPixelGrid(hexNumber2);
|
|
for (var y = 2; y <= 6; y++) {
|
|
for (var x = 5; x <= 7; x++) {
|
|
var px = pixel.x + x;
|
|
var py = pixel.y + y;
|
|
|
|
if (pixelMap[px][py] && pixelMap[px][py].element == "displayPixel") {
|
|
if (hexGrid2[y - 2][x - 5]) {
|
|
pixelMap[px][py].color = "rgb(16, 230, 120)";
|
|
} else {
|
|
pixelMap[px][py].color = "rgb(16, 24, 32)";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function malfunction_chip(pixel) {
|
|
var emptySpaces = [];
|
|
|
|
// Search in a 5x5 neighborhood for empty spaces
|
|
for (var dy = -2; dy <= 2; dy++) {
|
|
for (var dx = -2; dx <= 2; dx++) {
|
|
var neighborX = pixel.x + dx;
|
|
var neighborY = pixel.y + dy;
|
|
if (pixelMap[neighborX] && pixelMap[neighborX][neighborY] === undefined) {
|
|
emptySpaces.push({ x: neighborX, y: neighborY });
|
|
}
|
|
}
|
|
}
|
|
|
|
if (emptySpaces.length > 0) {
|
|
// Randomly select one of the empty spaces
|
|
var randomSpace = emptySpaces[Math.floor(Math.random() * emptySpaces.length)];
|
|
|
|
// Determine what to spawn based on probability
|
|
var rand = Math.random();
|
|
if (rand < 0.7) {
|
|
createPixel("electric", randomSpace.x, randomSpace.y);
|
|
} else if (rand < 0.99) {
|
|
createPixel("fire", randomSpace.x, randomSpace.y);
|
|
} else {
|
|
createPixel("explosion", randomSpace.x, randomSpace.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
elements.displayPixel = {
|
|
color: "#000000",
|
|
category: "logic",
|
|
state: "solid",
|
|
behavior: behaviors.WALL,
|
|
tick: function(pixel) {
|
|
if (pixel.start == pixelTicks) {
|
|
pixel.color = "rgb(16, 24, 32)";
|
|
}
|
|
|
|
if (lightmapEnabled && pixel.color) {
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
lightmap[y][x] = { color: scaleList(rgbToArray(pixel.color), 0.2) };
|
|
}
|
|
}
|
|
};
|
|
|
|
elements.circuit_material = {
|
|
color: "#444444",
|
|
category: "logic",
|
|
state: "solid",
|
|
behavior: behaviors.WALL,
|
|
hoverStat: function(pixel) {
|
|
return `Circuit: ${pixel.corePosition}`;
|
|
},
|
|
cc_stableTick: function(pixel) {
|
|
// Make it that extreme temperatures can stop the chip from working (for realism)
|
|
if (Math.random() < 0.003 && cc_setting1.value) { // Chance to check for temperature or nearby particles
|
|
// Check temperature
|
|
if (pixel.temp > 120) {
|
|
// Replace the circuit core with lead if overheating
|
|
if (pixel.corePosition && Math.random() < (0.00015) * (pixel.temp - 120)) {
|
|
var corePos = pixel.corePosition;
|
|
if (pixelMap[corePos.x] && pixelMap[corePos.x][corePos.y]) {
|
|
deletePixel(corePos.x, corePos.y);
|
|
createPixel("lead", corePos.x, corePos.y);
|
|
}
|
|
}
|
|
|
|
// Randomly trigger malfunction if overheating
|
|
if (Math.random() < 0.001 * (pixel.temp - 120)) {
|
|
malfunction_chip(pixel);
|
|
}
|
|
|
|
// Break the circuit material itself if overheating
|
|
if (Math.random() < 0.001 * (pixel.temp - 120)) {
|
|
var px = pixel.x;
|
|
var py = pixel.y;
|
|
deletePixel(px, py);
|
|
if (Math.random() < 0.5) {createPixel("lead", px, py);}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
elements.input_pin = {
|
|
color: "#DDAA33",
|
|
category: "logic",
|
|
state: "solid",
|
|
active: false,
|
|
stateHigh: "lead",
|
|
tempHigh: 570,
|
|
behavior: behaviors.WALL,
|
|
cc_stableTick: function(pixel) {
|
|
pixel.active = false;
|
|
var neighbors = getNeighbors(pixel);
|
|
for (var i = 0;i < neighbors.length;i++) {
|
|
var neighbor = neighbors[i];
|
|
|
|
if (neighbor.charge > 0 || neighbor.lstate == 2 || neighbor.active) {
|
|
pixel.active = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
elements.output_pin = {
|
|
color: "#AAAAAA",
|
|
category: "logic",
|
|
state: "solid",
|
|
active: false,
|
|
stateHigh: "lead",
|
|
tempHigh: 570,
|
|
behavior: behaviors.WALL,
|
|
cc_stableTick: function(pixel) {
|
|
var neighbors = getNeighbors(pixel);
|
|
for (var i = 0;i < neighbors.length;i++) {
|
|
var neighbor = neighbors[i];
|
|
|
|
// Check if it's a wire
|
|
if (elements[neighbor.element].conduct > 0 && pixel.active) {
|
|
neighbor.charge = 1;
|
|
}
|
|
|
|
// Check if it's a logic wire (logicgates.js)
|
|
if (neighbor.lstate != undefined) {
|
|
if (pixel.active) {
|
|
neighbor.lstate = 2;
|
|
neighbor.color = pixelColorPick(neighbor, "#ffe49c");
|
|
} else {
|
|
neighbor.lstate = -2;
|
|
neighbor.color = pixelColorPick(neighbor, "#3d4d2c");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
elements.logic_corrupt = {
|
|
color: "#DD33DD",
|
|
category: "logic",
|
|
tool: function(pixel) {
|
|
if (pixel.element == "logic_wire") {
|
|
if (Math.random() < 0.01) {
|
|
if (Math.random() < 0.5) {
|
|
pixel.lstate = 2;
|
|
pixel.color = pixelColorPick(pixel, "#ffe49c");
|
|
} else {
|
|
pixel.lstate = -2;
|
|
pixel.color = pixelColorPick(pixel, "#3d4d2c");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
excludeRandom: true,
|
|
}
|
|
|
|
elements.logic_corrupter_machine = {
|
|
color: "#DD33DD",
|
|
category: "logic",
|
|
cc_stableTick: function(pixel) {
|
|
var radius = 10
|
|
for (var y = pixel.y - radius; y < pixel.y + radius; y++) {
|
|
for (var x = pixel.x - radius; x < pixel.x + radius; x++) {
|
|
if (!isEmpty(x, y, true)) {
|
|
if (pixelMap[x][y].element == "logic_wire" && Math.random() < Math.min(Math.max((pixel.temp + 273) / 473, 0), 1) * 0.005) {
|
|
if (Math.random() < 0.5) {
|
|
pixelMap[x][y].lstate = 2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#ffe49c")
|
|
} else {
|
|
pixelMap[x][y].lstate = -2
|
|
pixelMap[x][y].color = pixelColorPick(pixelMap[x][y], "#3d4d2c")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
// Create a new anchor element
|
|
var tutorialLink = document.createElement("a");
|
|
|
|
// Set the link's text content
|
|
tutorialLink.textContent = "CircuitCore Tutorial";
|
|
|
|
// Set the link's href attribute to point to the tutorial
|
|
tutorialLink.href = "https://redbirdly.github.io/circuitcore_tutorial.html";
|
|
|
|
// Set the link to open in a new tab
|
|
tutorialLink.target = "_blank";
|
|
|
|
// Style the link (optional)
|
|
tutorialLink.style.color = "#33FF66"; // Set the color of the link
|
|
tutorialLink.style.fontSize = "14px"; // Set the font size
|
|
|
|
// Append the link to the body of the webpage
|
|
document.body.appendChild(tutorialLink);
|
|
|
|
// cc_ is circuit core prefix
|
|
const cc_BROWN = "#773317";
|
|
const cc_RED = "#DD3322";
|
|
const cc_ORANGE = "#DD8833";
|
|
const cc_YELLOW = "#DDCC44";
|
|
const cc_LIME = "#77DD44";
|
|
const cc_GREEN = "#33BB44";
|
|
const cc_BLUE = "#224499";
|
|
const cc_LIGHT_BLUE = "#77CCFF";
|
|
const cc_LAVENDER = "#AA88EE";
|
|
//const cc_PINK = "#DD88DD";
|
|
const cc_WHITE = "#DDDDDD";
|
|
|
|
var circuits = [
|
|
// Misc and I/O: brown
|
|
{ circuit: elements.four_bit_selector_circuit, color: cc_BROWN, size: [17, 3, true] },
|
|
{ circuit: elements.four_bit_enabler_circuit, color: cc_BROWN, size: [9, 3, true] },
|
|
{ circuit: elements.randomizer, color: cc_BROWN },
|
|
{ circuit: elements.four_bit_randomizer_circuit, color: cc_BROWN, size: [9, 3, true] },
|
|
{ circuit: elements.temperature_sensor, color: cc_BROWN },
|
|
// ROM/RAM: red
|
|
// { circuit: elements.ROM_circuit, color: cc_RED, size: [18, 18, false] },
|
|
// Encoders and de-multiplexers: orange
|
|
{ circuit: elements.two_to_one_encoder_circuit, color: cc_ORANGE, size: [5, 3, true] },
|
|
{ circuit: elements.four_to_two_encoder_circuit, color: cc_ORANGE, size: [9, 5, true] },
|
|
{ circuit: elements.eight_to_three_encoder_circuit, color: cc_ORANGE, size: [17, 7, true] },
|
|
{ circuit: elements.sixteen_to_four_encoder_circuit, color: cc_ORANGE, size: [33, 9, true] },
|
|
|
|
{ circuit: elements.one_to_two_demultiplexer_circuit, color: cc_ORANGE, size: [3, 5, true] },
|
|
{ circuit: elements.one_to_four_demultiplexer_circuit, color: cc_ORANGE, size: [3, 9, true] },
|
|
{ circuit: elements.one_to_eight_demultiplexer_circuit, color: cc_ORANGE, size: [3, 17, true] },
|
|
{ circuit: elements.one_to_sixteen_demultiplexer_circuit, color: cc_ORANGE, size: [3, 33, true] },
|
|
// Decoders and multiplexers: yellow
|
|
{ circuit: elements.one_to_two_decoder_circuit, color: cc_YELLOW, size: [3, 5, true] },
|
|
{ circuit: elements.two_to_four_decoder_circuit, color: cc_YELLOW, size: [5, 9, true] },
|
|
{ circuit: elements.three_to_eight_decoder_circuit, color: cc_YELLOW, size: [7, 17, true] },
|
|
{ circuit: elements.four_to_sixteen_decoder_circuit, color: cc_YELLOW, size: [9, 33, true] },
|
|
|
|
{ circuit: elements.two_to_one_multiplexer_circuit, color: cc_YELLOW, size: [3, 5, true] },
|
|
{ circuit: elements.four_to_one_multiplexer_circuit, color: cc_YELLOW, size: [5, 9, true] },
|
|
{ circuit: elements.eight_to_one_multiplexer_circuit, color: cc_YELLOW, size: [7, 17, true] },
|
|
{ circuit: elements.sixteen_to_one_multiplexer_circuit, color: cc_YELLOW, size: [9, 33, true] },
|
|
// Program counter and shift registers: lime
|
|
{ circuit: elements.four_bit_PISO_shift_register_circuit, color: cc_LIME, size: [9, 5, true] },
|
|
{ circuit: elements.four_bit_SIPO_shift_register_circuit, color: cc_LIME, size: [3, 9, true] },
|
|
{ circuit: elements.four_bit_program_counter_circuit, color: cc_LIME, size: [9, 5, true] },
|
|
// Registers: green
|
|
{ circuit: elements.four_bit_register_circuit, color: cc_GREEN, size: [9, 5, true] },
|
|
// Latches and flip flops: light blue
|
|
{ circuit: elements.SR_latch_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
|
|
{ circuit: elements.T_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
|
|
{ circuit: elements.D_latch_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
|
|
{ circuit: elements.D_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [3, 3, true] },
|
|
{ circuit: elements.four_bit_D_latch_circuit, color: cc_LIGHT_BLUE, size: [9, 3, true] },
|
|
{ circuit: elements.four_bit_D_flip_flop_circuit, color: cc_LIGHT_BLUE, size: [9, 3, true] },
|
|
// Addition/subtraction arithmetic: blue
|
|
{ circuit: elements.four_bit_adder_circuit, color: cc_BLUE, size: [17, 3, true] },
|
|
{ circuit: elements.four_bit_subtractor_circuit, color: cc_BLUE, size: [17, 3, true] },
|
|
{ circuit: elements.four_bit_incrementer_circuit, color: cc_BLUE, size: [9, 3, true] },
|
|
// Complex circuits: lavender
|
|
// Clocks: pink
|
|
{ circuit: elements.slow_clock },
|
|
{ circuit: elements.medium_clock },
|
|
{ circuit: elements.fast_clock },
|
|
{ circuit: elements.very_fast_clock },
|
|
// Displays/visual circuits: white
|
|
{ circuit: elements.simple_seven_segment_display, color: cc_WHITE, size: [5, 9, false] },
|
|
{ circuit: elements.simple_double_seven_segment_display, color: cc_WHITE, size: [9, 9, false] },
|
|
{ circuit: elements.custom_RGB_led, color: cc_WHITE, size: [3, 3, true] },
|
|
];
|
|
|
|
circuits.forEach(circuitInfo => {
|
|
if (circuitInfo.color) {circuitInfo.circuit.color = circuitInfo.color;}
|
|
circuitInfo.circuit.category = "logic";
|
|
circuitInfo.circuit.maxSize = 1;
|
|
circuitInfo.circuit.behavior = behaviors.WALL;
|
|
circuitInfo.circuit.state = "solid";
|
|
circuitInfo.circuit.isCircuitCore = true;
|
|
circuitInfo.circuit.previewSize = circuitInfo.size;
|
|
|
|
// Exclude circuits without a frame
|
|
if (circuitInfo.size) {
|
|
var previousCircuitTick = circuitInfo.circuit.cc_stableTick;
|
|
circuitInfo.circuit.cc_stableTick = function(pixel) {
|
|
previousCircuitTick(pixel);
|
|
|
|
// Don't constantly check
|
|
if (Math.random() < 0.1) {
|
|
// If there aren't 4 neighboring circuit_material elements then remove the circuit's core
|
|
var neighbors = getNeighbors(pixel);
|
|
var circuitMaterialCount = 0;
|
|
for (var i = 0;i < neighbors.length;i++) {
|
|
if (neighbors[i].element == "circuit_material") {
|
|
circuitMaterialCount++;
|
|
}
|
|
}
|
|
|
|
if (circuitMaterialCount < 2) {
|
|
deletePixel(pixel.x, pixel.y);
|
|
}
|
|
|
|
// Check if circuit overheating is enabled
|
|
if (cc_setting1.value) {
|
|
pixel.temp += Math.random(0.5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var circuitRotation = 0;
|
|
document.addEventListener('keydown', function(event) {
|
|
if (event.key === 'ArrowUp') {
|
|
circuitRotation = (circuitRotation + 90) % 360;
|
|
logMessage('CircuitRotation changed to ' + circuitRotation);
|
|
}
|
|
});
|
|
|
|
function drawCircuitExtras(ctx) {
|
|
if (elements[currentElement].isCircuitCore && elements[currentElement].previewSize) {
|
|
var circuitWidth = elements[currentElement].previewSize[0];
|
|
var circuitHeight = elements[currentElement].previewSize[1];
|
|
var centered = elements[currentElement].previewSize[2];
|
|
var rotation = circuitRotation;
|
|
|
|
var startX = 0;
|
|
var startY = 0;
|
|
var endX = circuitWidth - 1;
|
|
var endY = circuitHeight - 1;
|
|
|
|
if (centered) {
|
|
startX = -Math.floor(circuitWidth / 2);
|
|
startY = -Math.floor(circuitHeight / 2);
|
|
endX = Math.floor(circuitWidth / 2);
|
|
endY = Math.floor(circuitHeight / 2);
|
|
}
|
|
|
|
for (var y = startY; y <= endY; y++) {
|
|
for (var x = startX; x <= endX; x++) {
|
|
// if (!(0 <= x && x < width && 0 <= y && y < height)) {continue;}
|
|
|
|
var [rx, ry] = rotateCoordinate(x, y, rotation);
|
|
var px = mousePos.x + rx;
|
|
var py = mousePos.y + ry;
|
|
|
|
ctx.fillStyle = "rgba(255, 255, 255, 0.1)";
|
|
if ((rotation != 0 && !centered) || (0 <= px && px < width && 0 <= py && py < height) && pixelMap[px][py]) {
|
|
ctx.fillStyle = "rgba(255, 0, 0, 0.3)";
|
|
}
|
|
|
|
ctx.fillRect(px * pixelSize, py * pixelSize, pixelSize, pixelSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function runLogicTick() {
|
|
if (paused) {return;}
|
|
for (var j = 0;j < 1;j++) {
|
|
for (var i = 0;i < currentPixels.length;i++) {
|
|
var pixel = currentPixels[i];
|
|
if (elements[pixel.element].category == "logic") {
|
|
if (elements[pixel.element].cc_stableTick) {
|
|
elements[pixel.element].cc_stableTick(pixel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function stabilizeLogicGates() {
|
|
var logicgatesElements = ["output","logic_wire","not_gate","and_gate","xor_gate","or_gate","nand_gate","nor_gate","nxor_gate","E2L_lever","E2L_button","L2E_constant","logic_shock","logic_unshock"]
|
|
|
|
for (var i = 0;i < logicgatesElements.length;i++) {
|
|
elements[logicgatesElements[i]].cc_stableTick = elements[logicgatesElements[i]].tick;
|
|
elements[logicgatesElements[i]].tick = null;
|
|
}
|
|
}
|
|
|
|
renderPostPixel(drawCircuitExtras);
|
|
runEveryTick(runLogicTick);
|
|
runAfterLoad(stabilizeLogicGates);
|