|
110 | 110 | <body data-bs-theme='dark' class='bg-body text-body'> |
111 | 111 | <div class='container my-4 p-4 rounded-3 bg-body-tertiary'> |
112 | 112 | <div class='row g-3 align-items-stretch'> |
113 | | - <div class='col-12 col-lg-6'> |
| 113 | + <div class='col-12 col-lg-5'> |
114 | 114 | <label for='oracle-code' class='form-label display-6 fw-light text-body-emphasis' |
115 | 115 | style='font-size: 1.2rem;'>Arbitrary Oracle Function</label> |
116 | 116 | <div class='btn-group rounded-top w-100' style='overflow-x: auto'> |
|
196 | 196 | <span style='font-size: 1.5rem;'>←</span> |
197 | 197 | </button> |
198 | 198 | </div> |
199 | | - <div class='col-12 col-lg-5'> |
| 199 | + <div class='col-12 col-lg-6'> |
200 | 200 | <label for='output-code' class='form-label display-6 fw-light text-body-emphasis' |
201 | 201 | style='font-size: 1.2rem;'>Minimal Logic (Quine-McCluskey)</label> |
202 | 202 | <div class='btn-group rounded-top w-100' style='overflow-x: auto'> |
|
217 | 217 | <label class='btn btn-sm btn-secondary' for='outputTruthTable' |
218 | 218 | onclick='showOutputTab("table")'>Truth Table</label> |
219 | 219 |
|
220 | | - <input type='radio' class='btn-check' name='outputOptions' id='outputSATInstance' |
| 220 | + <input type='radio' class='btn-check' name='outputOptions' id='outputSAT' |
221 | 221 | autocomplete='off'> |
222 | | - <label class='btn btn-sm btn-secondary' for='outputSATInstance' onclick='showOutputTab("sat")'>SAT |
| 222 | + <label class='btn btn-sm btn-secondary' for='outputSAT' onclick='showOutputTab("sat")'>SAT |
223 | 223 | Instance</label> |
224 | 224 | </div> |
225 | 225 | <div class='my-2 d-flex align-items-center' style='gap: 0.5rem;'> |
|
388 | 388 |
|
389 | 389 | // CNF is true, DNF is false |
390 | 390 | const isCNF = document.getElementById('formCnfCheckbox').checked; |
391 | | - let expression, satExpression, kmapObject; |
| 391 | + let output, kmapObject, outputs = ['expr', 'sat']; |
| 392 | + |
| 393 | + if (document.getElementById('outputKMap').checked) outputs.push('kmap'); |
392 | 394 |
|
393 | 395 | if (isCNF) { |
394 | | - ({ expr: expression, sat: satExpression, kmap: kmapObject } = QuineMcCluskey.solveCNF(variableNames, window.oracle, ['expr', 'sat', 'kmap'])); |
| 396 | + output = QuineMcCluskey.solveCNF(variableNames, window.oracle, outputs); |
395 | 397 | } else { |
396 | | - ({ expr: expression, sat: satExpression, kmap: kmapObject } = QuineMcCluskey.solveDNF(variableNames, window.oracle, ['expr', 'sat', 'kmap'])); |
| 398 | + output = QuineMcCluskey.solveDNF(variableNames, window.oracle, outputs); |
397 | 399 | } |
398 | 400 |
|
399 | | - renderExpressionTextbox(expression); |
400 | | - circuitExpression = expression.replace(/&&/g, '&').replace(/\|\|/g, '|'); |
401 | | - kmapData = kmapObject; |
402 | | - outputSat.setValue(satExpression); |
403 | | - |
404 | | - // Collect used vars from expression |
405 | | - const identifierRegex = /\b[A-Za-z_][A-Za-z0-9_]*\b/g; |
406 | | - const used = new Set(); |
407 | | - let match; |
408 | | - while ((match = identifierRegex.exec(expression)) !== null) { |
409 | | - const name = match[0]; |
410 | | - // Filter to original vars (skip literals) |
411 | | - if (variableNames.includes(name) && name !== 'true' && name !== 'false') { |
412 | | - used.add(name); |
413 | | - } |
| 401 | + // Assign Karnaugh map and SAT output |
| 402 | + if (output && output.kmap) kmapData = output.kmap; |
| 403 | + if (output && output.sat) { |
| 404 | + if (typeof outputSat !== 'undefined' && outputSat) outputSat.setValue(output.sat); |
414 | 405 | } |
415 | | - // Only keep used variable names |
416 | | - const maintainVars = document.getElementById('maintainVarsCheckbox').checked; |
417 | | - if (maintainVars) { |
418 | | - usedVariableNames = variableNames.slice(); |
| 406 | + |
| 407 | + if (output && output.expr) { |
| 408 | + const expression = output.expr; |
| 409 | + renderExpressionTextbox(expression); |
| 410 | + circuitExpression = expression.replace(/&&/g, '&').replace(/\|\|/g, '|'); |
| 411 | + |
| 412 | + // Fetch used variables from expression |
| 413 | + const identifierRegex = /\b[A-Za-z_][A-Za-z0-9_]*\b/g; |
| 414 | + const used = new Set(); |
| 415 | + let match; |
| 416 | + while ((match = identifierRegex.exec(expression)) !== null) { |
| 417 | + const name = match[0]; |
| 418 | + // Filter to original vars (skip literals) |
| 419 | + if (variableNames.includes(name) && name !== 'true' && name !== 'false') { |
| 420 | + used.add(name); |
| 421 | + } |
| 422 | + } |
| 423 | + // Only keep used variable names |
| 424 | + const maintainVars = document.getElementById('maintainVarsCheckbox').checked; |
| 425 | + if (maintainVars) { |
| 426 | + usedVariableNames = variableNames.slice(); |
| 427 | + } else { |
| 428 | + usedVariableNames = variableNames.filter(v => used.has(v)); |
| 429 | + } |
| 430 | + const funcArgs = usedVariableNames.join(','); |
| 431 | + const funcBody = 'return ' + expression + ';'; |
| 432 | + const finalFunction = 'function oracle(' + funcArgs + ') {\n ' + funcBody + '\n}'; |
| 433 | + if (typeof outputCode !== 'undefined' && outputCode) { |
| 434 | + outputCode.setValue(finalFunction); |
| 435 | + } |
| 436 | + console.log(finalFunction); |
419 | 437 | } else { |
420 | | - usedVariableNames = variableNames.filter(v => used.has(v)); |
| 438 | + // No expression generated |
| 439 | + circuitExpression = ''; |
| 440 | + usedVariableNames = []; |
| 441 | + if (typeof outputCode !== 'undefined' && outputCode) { |
| 442 | + outputCode.setValue('// No expression generated'); |
| 443 | + } |
421 | 444 | } |
422 | | - const funcArgs = usedVariableNames.join(','); |
423 | | - const funcBody = 'return ' + expression + ';'; |
424 | | - const finalFunction = 'function oracle(' + funcArgs + ') {\n ' + funcBody + '\n}'; |
425 | | - outputCode.setValue(finalFunction); |
426 | | - console.log(finalFunction); |
427 | 445 |
|
428 | 446 | outputTableNeedsUpdate = true; |
429 | 447 | if (document.getElementById('outputTruthTable').checked) { |
430 | | - setupOutputTable(); |
| 448 | + if (output && output.expr) { |
| 449 | + setupOutputTable(); |
| 450 | + } |
431 | 451 | } |
432 | 452 | if (document.getElementById('outputKMap').checked) { |
433 | | - renderKarnaughMapTable(); |
| 453 | + if (kmapData) { |
| 454 | + renderKarnaughMapTable(); |
| 455 | + } |
434 | 456 | } |
435 | 457 | if (document.getElementById('outputCircuit').checked) { |
436 | | - renderLogicCircuit(); |
| 458 | + if (circuitExpression && circuitExpression.length) { |
| 459 | + renderLogicCircuit(); |
| 460 | + } |
437 | 461 | } |
438 | 462 |
|
439 | 463 | document.getElementById('runButton').disabled = document.getElementById('autoRunCheckbox').checked; |
440 | | - document.getElementById('copyButton').disabled = false; |
| 464 | + document.getElementById('copyButton').disabled = !(output && output.expr); |
441 | 465 |
|
442 | 466 | const errorIndicator = document.getElementById('errorIndicator'); |
443 | 467 | if (errorIndicator) { |
|
503 | 527 | } |
504 | 528 | if (tab === 'kmap') { |
505 | 529 | document.getElementById('outputTab-kmap').style.display = ''; |
506 | | - renderKarnaughMapTable(); |
| 530 | + if (document.getElementById('autoRunCheckbox').checked) { |
| 531 | + run(); |
| 532 | + } |
507 | 533 | } else { |
508 | 534 | document.getElementById('outputTab-kmap').style.display = 'none'; |
509 | 535 | } |
|
856 | 882 | function renderKarnaughMapTable() { |
857 | 883 | const table = document.getElementById('karnaughMapTable'); |
858 | 884 | if (!table) return; |
| 885 | + if (!kmapData) return; |
859 | 886 | const { vars, kmap, groups = [] } = kmapData; |
860 | 887 | const { layout: { rowVars, colVars, rowGrayLabels, colGrayLabels }, values } = kmap; |
861 | 888 |
|
|
0 commit comments