multi bit math
This commit is contained in:
parent
0251dd52d9
commit
12db01963f
7
src/assets/4decoder.svg
Normal file
7
src/assets/4decoder.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M800 0H0V800H800V0Z" fill="#DB00FF"/>
|
||||||
|
<path d="M386.932 308H517L448.214 400L517 492H386.932C386.932 492 306.265 492 305.014 400C303.763 308 386.932 308 386.932 308Z" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M555.089 435.379H477M555.089 365.621H477H555.089ZM572 333H493.911H572ZM572 468H493.911H572Z" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M555.089 435.379H477M555.089 365.621H477H555.089ZM572 333H493.911H572ZM572 468H493.911H572Z" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M555 435.379H476.5M306.5 396.234H228H306.5ZM572 333H493.5H572ZM572 468H493.5H572Z" stroke="white" stroke-width="10"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 718 B |
7
src/assets/4encoder.svg
Normal file
7
src/assets/4encoder.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="800" height="800" fill="#DB00FF"/>
|
||||||
|
<path d="M424.682 308H294L363.11 400L294 492H424.682C424.682 492 505.729 492 506.986 400C508.243 308 424.682 308 424.682 308Z" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M256 365.5H334.5M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M256 365.5H334.5M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
|
||||||
|
<path d="M504.5 396H583M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 633 B |
|
@ -1,18 +1,22 @@
|
||||||
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
|
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
|
||||||
import { SimulationError } from '../../errors/classes/SimulationError'
|
import { PinState } from '../../simulation/classes/Pin'
|
||||||
import { fromSimulationState } from '../../saving/helpers/fromState'
|
|
||||||
|
|
||||||
export interface Context {
|
export interface Context {
|
||||||
memory: Record<string, unknown>
|
|
||||||
getProperty: (name: string) => unknown
|
getProperty: (name: string) => unknown
|
||||||
setProperty: (name: string, value: unknown) => void
|
setProperty: (name: string, value: unknown) => void
|
||||||
get: (index: number) => boolean
|
get: (index: number) => PinState
|
||||||
set: (index: number, state: boolean) => void
|
set: (index: number, state: PinState) => void
|
||||||
|
getBinary: (index: number) => number
|
||||||
|
setBinary: (index: number, value: number, bits: number) => void
|
||||||
|
invertBinary: (value: number) => number
|
||||||
color: (color: string) => void
|
color: (color: string) => void
|
||||||
innerText: (value: string) => void
|
innerText: (value: string) => void
|
||||||
update: () => void
|
update: () => void
|
||||||
|
toLength: (value: number | PinState, length: number) => string
|
||||||
|
maxLength: number
|
||||||
enviroment: SimulationEnv
|
enviroment: SimulationEnv
|
||||||
colors: Record<string, string>
|
colors: Record<string, string>
|
||||||
|
memory: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InitialisationContext {
|
export interface InitialisationContext {
|
||||||
|
|
30
src/modules/colors/helpers/fromHex.ts
Normal file
30
src/modules/colors/helpers/fromHex.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* Gets the 3 chunks frmo a hex color string
|
||||||
|
*
|
||||||
|
* @param color The color string
|
||||||
|
*/
|
||||||
|
export const fromHexColorString = (color: string) => {
|
||||||
|
const actual = color.slice(1)
|
||||||
|
|
||||||
|
const chunks = [
|
||||||
|
actual.substr(0, 2),
|
||||||
|
actual.substr(2, 2),
|
||||||
|
actual.substr(4, 2)
|
||||||
|
]
|
||||||
|
|
||||||
|
const numbers = chunks.map(chunk => parseInt(chunk, 16))
|
||||||
|
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds a color from its chunks
|
||||||
|
*/
|
||||||
|
export const fromChunks = (chunks: number[]) => {
|
||||||
|
return `#${chunks.reduce((acc, curr) => {
|
||||||
|
const stringified = curr.toString(16)
|
||||||
|
return (
|
||||||
|
acc + (stringified.length === 1 ? `0${stringified}` : stringified)
|
||||||
|
)
|
||||||
|
}, '')}`
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ const LogicGatePage = () => {
|
||||||
<div className="gate-grid">
|
<div className="gate-grid">
|
||||||
{gates
|
{gates
|
||||||
.map(getTemplateSafely)
|
.map(getTemplateSafely)
|
||||||
|
.sort((a, b) => a.category - b.category)
|
||||||
.filter(template => {
|
.filter(template => {
|
||||||
return (
|
return (
|
||||||
renderer.simulation.mode === 'project' ||
|
renderer.simulation.mode === 'project' ||
|
||||||
|
|
|
@ -14,6 +14,8 @@ import xnorTemplate from './templates/xnor'
|
||||||
import xorTemplate from './templates/xor'
|
import xorTemplate from './templates/xor'
|
||||||
import halfAdderTemplate from './templates/halfAdder'
|
import halfAdderTemplate from './templates/halfAdder'
|
||||||
import fullAdderTemplate from './templates/fullAdder'
|
import fullAdderTemplate from './templates/fullAdder'
|
||||||
|
import _4bitEncoderTemplate from './templates/4bitEncoder'
|
||||||
|
import _4bitDecoderTemplate from './templates/4bitDecoder'
|
||||||
|
|
||||||
export const defaultSimulationName = 'default'
|
export const defaultSimulationName = 'default'
|
||||||
export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
||||||
|
@ -30,7 +32,9 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
||||||
xnorTemplate,
|
xnorTemplate,
|
||||||
xorTemplate,
|
xorTemplate,
|
||||||
halfAdderTemplate,
|
halfAdderTemplate,
|
||||||
fullAdderTemplate
|
fullAdderTemplate,
|
||||||
|
_4bitEncoderTemplate,
|
||||||
|
_4bitDecoderTemplate
|
||||||
// commentTemplate
|
// commentTemplate
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
4
src/modules/saving/data/4BitScale.ts
Normal file
4
src/modules/saving/data/4BitScale.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* The actual scale for the 4-bit encoder / decoder
|
||||||
|
*/
|
||||||
|
export const _4BitScale = [150, 150]
|
8
src/modules/saving/data/categories.ts
Normal file
8
src/modules/saving/data/categories.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export const categories = {
|
||||||
|
basic: 0,
|
||||||
|
io: 3,
|
||||||
|
math: 1,
|
||||||
|
time: 2,
|
||||||
|
advancedIo: 4,
|
||||||
|
compressing: 5
|
||||||
|
}
|
10
src/modules/saving/helpers/adderActivation.ts
Normal file
10
src/modules/saving/helpers/adderActivation.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export const adderActivation = (full: boolean) => `
|
||||||
|
const a = context.getBinary(0)
|
||||||
|
const b = context.getBinary(1)
|
||||||
|
${full ? `const c = context.getBinary(2)` : ''}
|
||||||
|
|
||||||
|
const sum = a + b + ${full ? `c` : '0'}
|
||||||
|
|
||||||
|
context.setBinary(0, sum)
|
||||||
|
context.setBinary(1, sum >> context.maxLength)
|
||||||
|
`
|
|
@ -9,6 +9,10 @@ import { Camera } from '../../simulationRenderer/classes/Camera'
|
||||||
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
|
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
|
||||||
import { Wire } from '../../simulation/classes/Wire'
|
import { Wire } from '../../simulation/classes/Wire'
|
||||||
import { templateStore } from '../stores/templateStore'
|
import { templateStore } from '../stores/templateStore'
|
||||||
|
import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight'
|
||||||
|
import { getRendererSafely } from '../../logic-gates/helpers/getRendererSafely'
|
||||||
|
import { rendererSubject } from '../../core/subjects/rendererSubject'
|
||||||
|
import { filter, take } from 'rxjs/operators'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains methods for transforming saved state into the respective class instances
|
* Contains methods for transforming saved state into the respective class instances
|
||||||
|
@ -38,10 +42,34 @@ export const fromSimulationState = (
|
||||||
gateState.id,
|
gateState.id,
|
||||||
gateState.props
|
gateState.props
|
||||||
)
|
)
|
||||||
|
|
||||||
gate.transform = fromTransformState(gateState.transform)
|
gate.transform = fromTransformState(gateState.transform)
|
||||||
|
|
||||||
|
const fixWrongHeight = () => {
|
||||||
|
gate.transform.height = calculateGateHeight(
|
||||||
|
getRendererSafely(),
|
||||||
|
gate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fixWrongHeight()
|
||||||
|
} catch {
|
||||||
|
// retry if an error occured
|
||||||
|
rendererSubject
|
||||||
|
.pipe(
|
||||||
|
filter(x => !!x),
|
||||||
|
take(1)
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
if (gate) {
|
||||||
|
fixWrongHeight()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
simulation.push(gate)
|
simulation.push(gate)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const wireState of state.wires) {
|
for (const wireState of state.wires) {
|
||||||
const startGateNode = simulation.gates.get(wireState.from.id)
|
const startGateNode = simulation.gates.get(wireState.from.id)
|
||||||
|
|
40
src/modules/saving/templates/4bitDecoder.ts
Normal file
40
src/modules/saving/templates/4bitDecoder.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
import { _4BitScale } from '../data/4BitScale'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template of the _4bitDecoder gate
|
||||||
|
*/
|
||||||
|
const _4bitDecoderTemplate: PartialTemplate = {
|
||||||
|
metadata: {
|
||||||
|
name: `4 bit decoder`
|
||||||
|
},
|
||||||
|
category: categories.compressing,
|
||||||
|
code: {
|
||||||
|
activation: `
|
||||||
|
const input = context.get(0)
|
||||||
|
|
||||||
|
const set = (index) => {
|
||||||
|
context.set(3 - index, input[index] || '0')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const index of [0,1,2,3]){
|
||||||
|
set(index)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
type: 'image',
|
||||||
|
fill: require('../../../assets/4decoder')
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
scale: _4BitScale
|
||||||
|
},
|
||||||
|
pins: {
|
||||||
|
outputs: {
|
||||||
|
count: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default _4bitDecoderTemplate
|
39
src/modules/saving/templates/4bitEncoder.ts
Normal file
39
src/modules/saving/templates/4bitEncoder.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
import { _4BitScale } from '../data/4BitScale'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template of the _4bitEncoder gate
|
||||||
|
*/
|
||||||
|
const _4bitEncoderTemplate: PartialTemplate = {
|
||||||
|
metadata: {
|
||||||
|
name: `4 bit encoder`
|
||||||
|
},
|
||||||
|
category: categories.compressing,
|
||||||
|
code: {
|
||||||
|
activation: `
|
||||||
|
const get = (num) => {
|
||||||
|
const value = context.get(num)
|
||||||
|
return value[value.length - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = get(3) + get(2) + get(1) + get(0)
|
||||||
|
|
||||||
|
context.set(0, total)
|
||||||
|
`
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
type: 'image',
|
||||||
|
fill: require('../../../assets/4encoder')
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
scale: _4BitScale
|
||||||
|
},
|
||||||
|
pins: {
|
||||||
|
inputs: {
|
||||||
|
count: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default _4bitEncoderTemplate
|
|
@ -12,7 +12,12 @@ const andTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/and')
|
fill: require('../../../assets/and')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `context.set(0, context.get(0) && context.get(1))`
|
activation: `
|
||||||
|
const a = context.getBinary(0)
|
||||||
|
const b = context.getBinary(1)
|
||||||
|
const c = a & b
|
||||||
|
|
||||||
|
context.setBinary(0, c)`
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the button gate
|
* The template of the button gate
|
||||||
|
@ -27,7 +28,7 @@ const buttonTemplate: PartialTemplate = {
|
||||||
activation: `
|
activation: `
|
||||||
const state = context.getProperty('active')
|
const state = context.getProperty('active')
|
||||||
|
|
||||||
context.set(0, state)
|
context.set(0, Number(state).toString(2))
|
||||||
context.color(!state ? context.colors.main : context.colors.pressed)
|
context.color(!state ? context.colors.main : context.colors.pressed)
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
|
@ -50,7 +51,8 @@ const buttonTemplate: PartialTemplate = {
|
||||||
needsUpdate: true
|
needsUpdate: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
category: categories.io
|
||||||
}
|
}
|
||||||
|
|
||||||
export default buttonTemplate
|
export default buttonTemplate
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
import { adderActivation } from '../helpers/adderActivation'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the fullAdder gate
|
* The template of the fullAdder gate
|
||||||
|
@ -12,12 +14,7 @@ const fullAdderTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/full-adder')
|
fill: require('../../../assets/full-adder')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `
|
activation: adderActivation(true)
|
||||||
const result = context.get(0) + context.get(1) + context.get(2)
|
|
||||||
|
|
||||||
context.set(0, result & 1)
|
|
||||||
context.set(1, result >> 1)
|
|
||||||
`
|
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
@ -26,7 +23,8 @@ const fullAdderTemplate: PartialTemplate = {
|
||||||
outputs: {
|
outputs: {
|
||||||
count: 2
|
count: 2
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
category: categories.math
|
||||||
}
|
}
|
||||||
|
|
||||||
export default fullAdderTemplate
|
export default fullAdderTemplate
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
import { adderActivation } from '../helpers/adderActivation'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the halfAdder gate
|
* The template of the halfAdder gate
|
||||||
|
@ -12,12 +14,7 @@ const halfAdderTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/half-adder')
|
fill: require('../../../assets/half-adder')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `
|
activation: adderActivation(false)
|
||||||
const result = context.get(0) + context.get(1)
|
|
||||||
|
|
||||||
context.set(0, result & 1)
|
|
||||||
context.set(1, result >> 1)
|
|
||||||
`
|
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
@ -26,7 +23,8 @@ const halfAdderTemplate: PartialTemplate = {
|
||||||
outputs: {
|
outputs: {
|
||||||
count: 2
|
count: 2
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
category: categories.math
|
||||||
}
|
}
|
||||||
|
|
||||||
export default halfAdderTemplate
|
export default halfAdderTemplate
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the light gate
|
* The template of the light gate
|
||||||
|
@ -23,7 +24,7 @@ const lightTemplate: PartialTemplate = {
|
||||||
activation: `
|
activation: `
|
||||||
const { main, active } = context.colors
|
const { main, active } = context.colors
|
||||||
|
|
||||||
context.color(context.get(0) ? active : main)
|
context.color(parseInt(context.get(0),2) ? active : main)
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
integration: {
|
integration: {
|
||||||
|
@ -34,7 +35,8 @@ const lightTemplate: PartialTemplate = {
|
||||||
outputs: {
|
outputs: {
|
||||||
count: 0
|
count: 0
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
category: categories.io
|
||||||
}
|
}
|
||||||
|
|
||||||
export default lightTemplate
|
export default lightTemplate
|
||||||
|
|
|
@ -12,7 +12,12 @@ const nandTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/nand')
|
fill: require('../../../assets/nand')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `context.set(0, !context.get(0) || !context.get(1))`
|
activation: `
|
||||||
|
const a = context.getBinary(0)
|
||||||
|
const b = context.getBinary(1)
|
||||||
|
const c = context.invertBinary(a & b)
|
||||||
|
|
||||||
|
context.setBinary(0, c)`
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -12,7 +12,13 @@ const norTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/nor')
|
fill: require('../../../assets/nor')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `context.set(0, !(context.get(0) || context.get(1)))`
|
activation: `
|
||||||
|
const a = context.getBinary(0)
|
||||||
|
const b = context.getBinary(1)
|
||||||
|
const c = context.invertBinary(a | b)
|
||||||
|
|
||||||
|
context.setBinary(0, c)
|
||||||
|
`
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -12,7 +12,13 @@ const notTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/not')
|
fill: require('../../../assets/not')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `context.set(0, !context.get(0))`
|
activation: `
|
||||||
|
context.setBinary(0,
|
||||||
|
context.invertBinary(
|
||||||
|
context.getBinary(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`
|
||||||
},
|
},
|
||||||
info: ['https://en.wikipedia.org/wiki/Inverter_(logic_gate)']
|
info: ['https://en.wikipedia.org/wiki/Inverter_(logic_gate)']
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,12 @@ const orTemplate: PartialTemplate = {
|
||||||
fill: require('../../../assets/or')
|
fill: require('../../../assets/or')
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `context.set(0, context.get(0) || context.get(1))`
|
activation: `
|
||||||
|
const a = context.getBinary(0)
|
||||||
|
const b = context.getBinary(1)
|
||||||
|
|
||||||
|
context.setBinary(0, a | b)
|
||||||
|
`
|
||||||
},
|
},
|
||||||
pins: {
|
pins: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
import { delayProperties } from '../data/delayProperties'
|
import { delayProperties } from '../data/delayProperties'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the parallelDelayer gate
|
* The template of the parallelDelayer gate
|
||||||
|
@ -24,7 +25,8 @@ const parallelDelayerTemplate: PartialTemplate = {
|
||||||
})
|
})
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
properties: delayProperties
|
properties: delayProperties,
|
||||||
|
category: categories.time
|
||||||
}
|
}
|
||||||
|
|
||||||
export default parallelDelayerTemplate
|
export default parallelDelayerTemplate
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the rgbLight gate
|
* The template of the rgbLight gate
|
||||||
|
@ -43,7 +44,8 @@ const rgbLightTemplate: PartialTemplate = {
|
||||||
inputs: {
|
inputs: {
|
||||||
count: 3
|
count: 3
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
category: categories.advancedIo
|
||||||
}
|
}
|
||||||
|
|
||||||
export default rgbLightTemplate
|
export default rgbLightTemplate
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { PartialTemplate } from '../types/PartialTemplate'
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
import { delayProperties } from '../data/delayProperties'
|
import { delayProperties } from '../data/delayProperties'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template of the sequentialDelayer gate
|
* The template of the sequentialDelayer gate
|
||||||
|
@ -25,7 +26,8 @@ const sequentialDelayerTemplate: PartialTemplate = {
|
||||||
`,
|
`,
|
||||||
async: true
|
async: true
|
||||||
},
|
},
|
||||||
properties: delayProperties
|
properties: delayProperties,
|
||||||
|
category: categories.time
|
||||||
}
|
}
|
||||||
|
|
||||||
export default sequentialDelayerTemplate
|
export default sequentialDelayerTemplate
|
||||||
|
|
|
@ -13,11 +13,11 @@ const xnorTemplate: PartialTemplate = {
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `
|
activation: `
|
||||||
const a = context.get(0)
|
const a = context.getBinary(0)
|
||||||
const b = context.get(1)
|
const b = context.getBinary(1)
|
||||||
const c = (a && b) || !(a || b)
|
const c = context.invertBinary(a ^ b)
|
||||||
|
|
||||||
context.set(0, c)`
|
context.setBinary(0, c)`
|
||||||
},
|
},
|
||||||
info: ['https://en.wikipedia.org/wiki/XNOR_gate'],
|
info: ['https://en.wikipedia.org/wiki/XNOR_gate'],
|
||||||
pins: {
|
pins: {
|
||||||
|
|
|
@ -13,11 +13,10 @@ const xorTemplate: PartialTemplate = {
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
activation: `
|
activation: `
|
||||||
const a = context.get(0)
|
const a = context.getBinary(0)
|
||||||
const b = context.get(1)
|
const b = context.getBinary(1)
|
||||||
const c = (a || b) && (!a || !b)
|
|
||||||
|
|
||||||
context.set(0, c)`
|
context.setBinary(0, a ^ b)`
|
||||||
},
|
},
|
||||||
info: ['https://en.wikipedia.org/wiki/XOR_gate'],
|
info: ['https://en.wikipedia.org/wiki/XOR_gate'],
|
||||||
pins: {
|
pins: {
|
||||||
|
|
|
@ -360,13 +360,49 @@ export class Gate {
|
||||||
* Generates the activation context
|
* Generates the activation context
|
||||||
*/
|
*/
|
||||||
public getContext(): Context {
|
public getContext(): Context {
|
||||||
|
const maxLength = Math.max(
|
||||||
|
...this._pins.inputs.map(pin => pin.state.value.length)
|
||||||
|
)
|
||||||
|
|
||||||
|
const toLength = (
|
||||||
|
original: string | number,
|
||||||
|
length: number = maxLength
|
||||||
|
) => {
|
||||||
|
const value = original.toString(2)
|
||||||
|
|
||||||
|
if (value.length === length) {
|
||||||
|
return value
|
||||||
|
} else if (value.length > length) {
|
||||||
|
const difference = value.length - length
|
||||||
|
|
||||||
|
return value.substr(difference)
|
||||||
|
} else {
|
||||||
|
return `${'0'.repeat(length - value.length)}${value}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get: (index: number) => {
|
get: (index: number) => {
|
||||||
return this._pins.inputs[index].state.value
|
return this._pins.inputs[index].state.value
|
||||||
},
|
},
|
||||||
set: (index: number, state: boolean = false) => {
|
set: (index: number, state) => {
|
||||||
return this._pins.outputs[index].state.next(state)
|
return this._pins.outputs[index].state.next(state)
|
||||||
},
|
},
|
||||||
|
getBinary: (index: number) => {
|
||||||
|
return parseInt(this._pins.inputs[index].state.value, 2)
|
||||||
|
},
|
||||||
|
setBinary: (
|
||||||
|
index: number,
|
||||||
|
value: number,
|
||||||
|
bits: number = maxLength
|
||||||
|
) => {
|
||||||
|
return this._pins.outputs[index].state.next(
|
||||||
|
toLength(value.toString(2), bits)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
invertBinary: (value: number) => {
|
||||||
|
return value ^ ((1 << maxLength) - 1)
|
||||||
|
},
|
||||||
color: (color: string) => {
|
color: (color: string) => {
|
||||||
if (this.template.material.type === 'color') {
|
if (this.template.material.type === 'color') {
|
||||||
this.template.material.fill = color
|
this.template.material.fill = color
|
||||||
|
@ -384,6 +420,8 @@ export class Gate {
|
||||||
update: () => {
|
update: () => {
|
||||||
this.update()
|
this.update()
|
||||||
},
|
},
|
||||||
|
toLength,
|
||||||
|
maxLength,
|
||||||
enviroment: this.env,
|
enviroment: this.env,
|
||||||
memory: this.memory,
|
memory: this.memory,
|
||||||
colors: {
|
colors: {
|
||||||
|
@ -430,6 +468,6 @@ export class Gate {
|
||||||
private static generatePins(options: PinCount, type: number, gate: Gate) {
|
private static generatePins(options: PinCount, type: number, gate: Gate) {
|
||||||
return [...Array(options.count)]
|
return [...Array(options.count)]
|
||||||
.fill(true)
|
.fill(true)
|
||||||
.map(() => new Pin(type, gate))
|
.map((v, index) => new Pin(type, gate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { SubscriptionData } from '../types/SubscriptionData'
|
||||||
import { BehaviorSubject } from 'rxjs'
|
import { BehaviorSubject } from 'rxjs'
|
||||||
import { Gate } from './Gate'
|
import { Gate } from './Gate'
|
||||||
|
|
||||||
|
export type PinState = string
|
||||||
|
|
||||||
/* Types:
|
/* Types:
|
||||||
|
|
||||||
First bit = input
|
First bit = input
|
||||||
|
@ -9,7 +11,7 @@ Second bit = output
|
||||||
|
|
||||||
*/
|
*/
|
||||||
export class Pin {
|
export class Pin {
|
||||||
public state = new BehaviorSubject(false)
|
public state = new BehaviorSubject<PinState>('0')
|
||||||
public pairs = new Set<Pin>()
|
public pairs = new Set<Pin>()
|
||||||
|
|
||||||
private subscriptions: SubscriptionData<Pin>[] = []
|
private subscriptions: SubscriptionData<Pin>[] = []
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { GateTemplate } from './types/GateTemplate'
|
import { GateTemplate } from './types/GateTemplate'
|
||||||
|
import { categories } from '../saving/data/categories'
|
||||||
|
|
||||||
export const DefaultGateTemplate: GateTemplate = {
|
export const DefaultGateTemplate: GateTemplate = {
|
||||||
metadata: {
|
metadata: {
|
||||||
|
@ -57,5 +58,6 @@ export const DefaultGateTemplate: GateTemplate = {
|
||||||
innerText: {
|
innerText: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
color: 'white'
|
color: 'white'
|
||||||
}
|
},
|
||||||
|
category: categories.basic
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { toast } from 'react-toastify'
|
||||||
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
import { GateInitter } from '../../simulationRenderer/types/GateInitter'
|
import { GateInitter } from '../../simulationRenderer/types/GateInitter'
|
||||||
|
import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a gate to a renderer
|
* Adds a gate to a renderer
|
||||||
|
@ -43,6 +44,7 @@ export const addGate = (
|
||||||
const offset = multiply([scalarOffset, scalarOffset], renderer.spawnCount)
|
const offset = multiply([scalarOffset, scalarOffset], renderer.spawnCount)
|
||||||
|
|
||||||
gate.transform.position = add(origin, offset)
|
gate.transform.position = add(origin, offset)
|
||||||
|
gate.transform.height = calculateGateHeight(renderer, gate)
|
||||||
|
|
||||||
renderer.simulation.push(gate)
|
renderer.simulation.push(gate)
|
||||||
renderer.spawnCount++
|
renderer.spawnCount++
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { GateTemplate } from '../types/GateTemplate'
|
||||||
import { debounceTime, throttleTime } from 'rxjs/operators'
|
import { debounceTime, throttleTime } from 'rxjs/operators'
|
||||||
import { MonoTypeOperatorFunction, pipe } from 'rxjs'
|
import { MonoTypeOperatorFunction, pipe } from 'rxjs'
|
||||||
|
|
||||||
export type TimePipe = MonoTypeOperatorFunction<boolean>
|
export type TimePipe = MonoTypeOperatorFunction<string>
|
||||||
|
|
||||||
export const getGateTimePipes = (template: GateTemplate) => {
|
export const getGateTimePipes = (template: GateTemplate) => {
|
||||||
const pipes: TimePipe[] = []
|
const pipes: TimePipe[] = []
|
||||||
|
|
|
@ -79,4 +79,5 @@ export interface GateTemplate {
|
||||||
color: string
|
color: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
}
|
}
|
||||||
|
category: number // for better sorting
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ export const defaultSimulationRendererOptions: SimulationRendererOptions = {
|
||||||
pinStrokeColor: '#888888',
|
pinStrokeColor: '#888888',
|
||||||
pinStrokeWidth: 3,
|
pinStrokeWidth: 3,
|
||||||
pinFill: {
|
pinFill: {
|
||||||
open: 'rgb(255,216,20)',
|
open: '#ffff22',
|
||||||
closed: 'rgb(90,90,90)'
|
closed: '#555555'
|
||||||
},
|
},
|
||||||
gateStroke: {
|
gateStroke: {
|
||||||
active: 'yellow',
|
active: 'yellow',
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Gate } from '../../simulation/classes/Gate'
|
||||||
|
import { SimulationRenderer } from '../classes/SimulationRenderer'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the correct height for a gate
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to get the pin-radius of
|
||||||
|
* @param gate The gate to get the height of
|
||||||
|
*/
|
||||||
|
export const calculateGateHeight = (
|
||||||
|
renderer: SimulationRenderer,
|
||||||
|
gate: Gate
|
||||||
|
) => {
|
||||||
|
return Math.max(
|
||||||
|
gate.transform.scale[1],
|
||||||
|
Math.max(gate._pins.outputs.length, gate._pins.inputs.length) *
|
||||||
|
4 *
|
||||||
|
renderer.options.gates.pinRadius
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,15 +1,29 @@
|
||||||
import { Pin } from '../../simulation/classes/Pin'
|
import { Pin } from '../../simulation/classes/Pin'
|
||||||
import { SimulationRenderer } from '../classes/SimulationRenderer'
|
import { SimulationRenderer } from '../classes/SimulationRenderer'
|
||||||
|
import { fromHexColorString, fromChunks } from '../../colors/helpers/fromHex'
|
||||||
|
|
||||||
export const pinFill = (renderer: SimulationRenderer, pin: Pin) => {
|
export const pinFill = (renderer: SimulationRenderer, pin: Pin) => {
|
||||||
let color = 'rgba(0,0,0,0)'
|
let color = 'rgba(0,0,0,0)'
|
||||||
|
|
||||||
if (pin.pairs.size) {
|
if (pin.pairs.size) {
|
||||||
if (pin.state.value) {
|
const { open, closed } = renderer.options.gates.pinFill
|
||||||
color = renderer.options.gates.pinFill.open
|
const digits = Array.from(pin.state.value).map(Number)
|
||||||
} else {
|
|
||||||
color = renderer.options.gates.pinFill.closed
|
const colors = digits.map(digit => (digit ? open : closed))
|
||||||
}
|
const chunked = colors.map(fromHexColorString)
|
||||||
|
|
||||||
|
const summed = [0, 1, 2]
|
||||||
|
.map(key =>
|
||||||
|
chunked
|
||||||
|
.flat()
|
||||||
|
.filter((v, index) => index % 3 === key)
|
||||||
|
.reduce((acc, curr) => acc + curr, 0)
|
||||||
|
)
|
||||||
|
.map(value => Math.floor(value / digits.length))
|
||||||
|
|
||||||
|
color = fromChunks(summed)
|
||||||
|
|
||||||
|
// console.log(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
return color
|
return color
|
||||||
|
|
|
@ -32,12 +32,12 @@ export const renderGate = (
|
||||||
|
|
||||||
ctx.save()
|
ctx.save()
|
||||||
|
|
||||||
const r = useTransform(ctx, gate.transform)
|
const relativeTransform = useTransform(ctx, gate.transform)
|
||||||
const renderingParameters = [
|
const renderingParameters = [
|
||||||
r.x,
|
relativeTransform.x,
|
||||||
r.y,
|
relativeTransform.y,
|
||||||
r.width,
|
relativeTransform.width,
|
||||||
r.height,
|
relativeTransform.height,
|
||||||
gate.template.shape.rounded ? gate.template.shape.radius : 0
|
gate.template.shape.rounded ? gate.template.shape.radius : 0
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue