From 0a703e8f463dfadcf102e0b553d798b8046b03ee Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Fri, 19 Feb 2021 12:42:11 -0500 Subject: Add amino acid selection after mutation. --- amino-acid-selector.mjs | 33 +++++++++++++++++++++ codon.mjs | 4 +++ genome.mjs | 1 + index.html | 27 +++++++++++++++++ main.mjs | 3 +- mobile.css | 47 ++++++++++++++++++++++++++++++ rules.mjs | 77 +++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 amino-acid-selector.mjs diff --git a/amino-acid-selector.mjs b/amino-acid-selector.mjs new file mode 100644 index 0000000..fe71098 --- /dev/null +++ b/amino-acid-selector.mjs @@ -0,0 +1,33 @@ +class AminoAcidSelector { + constructor(elt) { + this.elt = elt + for (const elt of this.elt.querySelectorAll('li')) { + elt.addEventListener('click', this.select.bind(this)) + } + } + + attach() { + this.elt.classList.remove('hidden') + } + + detach() { + this.elt.classList.add('hidden') + } + + get onItemSelected() { + if (this._onItemSelected !== undefined) { + return this._onItemSelected + } + return () => {} + } + + set onItemSelected(fn) { + this._onItemSelected = fn + } + + select(evt) { + this.onItemSelected(evt.currentTarget.innerText) + } +} + +export default AminoAcidSelector diff --git a/codon.mjs b/codon.mjs index 612e4ac..6163883 100644 --- a/codon.mjs +++ b/codon.mjs @@ -25,6 +25,10 @@ class Codon { return this._elt } + get value() { + return this.bases.map(b => b.value).join('') + } + lock() { this.bases.forEach(n => n.lock()) this.aminoAcid.lock() diff --git a/genome.mjs b/genome.mjs index 49cae0f..432a59b 100644 --- a/genome.mjs +++ b/genome.mjs @@ -81,6 +81,7 @@ class Genome { for (const c of this.codons) { for (const b of c.bases) { if (b === this._selectedNucleotide) { + this.selectedCodon = c this.onNucleotideSelectionChanged(this._selectedNucleotide, i) return } diff --git a/index.html b/index.html index cb6137f..0661091 100644 --- a/index.html +++ b/index.html @@ -103,6 +103,33 @@
  • T
  • + + diff --git a/main.mjs b/main.mjs index aed3c1a..1af1c56 100644 --- a/main.mjs +++ b/main.mjs @@ -3,6 +3,7 @@ import Rules from './rules.mjs' function init() { const genomeList = document.querySelector('#genome-history') const die = document.querySelector('#die') + const aminoAcidSelector = document.querySelector('#amino-acid-selector') const nucleotideSelector = document.querySelector('#nucleotide-selector') const instructions = document.querySelector('#instructions') const cloneButton = document.querySelector('#clone') @@ -10,7 +11,7 @@ function init() { const printButton = document.querySelector('#print') const errors = document.querySelector('#errors') - const rules = new Rules(die, instructions, genomeList, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) + const rules = new Rules(die, instructions, genomeList, aminoAcidSelector, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) } init() diff --git a/mobile.css b/mobile.css index 0f7f87b..6d2d5a9 100644 --- a/mobile.css +++ b/mobile.css @@ -112,6 +112,53 @@ body { background-color: orange; } +#amino-acid-selector { + position: fixed; + left: 50%; + top: 50%; + width: 50%; + transform: translate(-50%, -50%); + + background-color: ivory; + border: 1px solid black; + cursor: pointer; +} + +#amino-acid-selector p { + margin: 0; + padding: 10px; + + border-bottom: 1px dashed black; +} + +#amino-acid-selector .codon { + font-weight: bold; +} + +#amino-acid-selector ul { + display: flex; + flex-wrap: wrap; + + margin: 0; + padding: 10px; + + list-style-type: none; + white-space: nowrap; +} + +#amino-acid-selector li { + display: flex-inline; + + height: 3ex; + width: 3em; + + text-align: center; +} + +#amino-acid-selector li:hover { + background-color: orange; +} + .genome .nucleotide.selected, .genome:not(.locked) .nucleotide.selected:hover { background-color: red; diff --git a/rules.mjs b/rules.mjs index 8f038bc..58b794f 100644 --- a/rules.mjs +++ b/rules.mjs @@ -1,4 +1,6 @@ import { randomItem, ordinalSuffix } from './utils.mjs' +import AminoAcid from './amino-acid.mjs' +import AminoAcidSelector from './amino-acid-selector.mjs' import Genome from './genome.mjs' import Nucleotide from './nucleotide.mjs' import Die from './die.mjs' @@ -184,7 +186,67 @@ class PerformMutation { return } - this.selectedNucleotide.value = base + this.rules.next(new SelectAminoAcid(this.rules)) + } +} + +class SelectAminoAcid { + constructor(rules) { + this.rules = rules + + this.id ='amino-acid-select' + } + + enter() { + const selector = this.rules.aminoAcidSelector + this.codon = this.rules.currentGenome.selectedCodon.value + this.expected = AminoAcid.codonMap[this.codon] + let x = selector.elt.querySelector('#amino-acid-selector .codon').innerHTML = + this.codon + + selector.onItemSelected = this.handleItemSelected.bind(this) + selector.attach(this.selectedNucleotide) + + this.rules.aminoAcidSelector.attach() + } + + exit() { + this.rules.aminoAcidSelector.detach() + } + + validSelection(aminoAcid) { + console.debug('aa:', this.expected) + return aminoAcid == this.expected + } + + handleItemSelected(aminoAcid) { + console.debug('selected', aminoAcid) + if (!this.validSelection(aminoAcid)) { + this.rules.error.innerHTML = + `The codon ${this.codon} does not code for ${aminoAcid}` + this.rules.next(new ShowError(this.rules, this)) + return + } + this.rules.next(new MarkAsLethal(this.rules)) + } +} + +class MarkAsLethal { + constructor(rules) { + this.rules = rules + + this.id = 'mark-as-lethal' + } + + enter() { + // Enable lethal/non-lethal selector. + + // Attach validator to selector and change state if possible. + } + + exit() { + // Disable lethal/non-lethal selector. + this.rules.iterations-- if (this.rules.isLastIteration) { this.rules.next(new DoNothing(this.rules)) @@ -241,10 +303,11 @@ class ShowError { } class Rules { - constructor(die, instructions, genomeList, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) { + constructor(die, instructions, genomeList, aminoAcidSelector, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) { this.die = new Die(die) this.instructions = instructions this.genomeList = new GenomeList(genomeList) + this.aminoAcidSelector = new AminoAcidSelector(aminoAcidSelector) this.nucleotideSelector = new NucleotideSelector(nucleotideSelector) this.cloneButton = cloneButton this.remainingIterations = remainingIterations @@ -259,6 +322,8 @@ class Rules { this._debugStartAtRollForMutation() } else if (false) { this._debugStartAtPerformMutation(4) + } else if (true) { + this._debugStartAtSelectAminoAcid() } else if (false) { this._debugStartWithError() } else { @@ -301,6 +366,14 @@ class Rules { this.currentGenome.selectedNucleotide = nucleotide } + _debugStartAtSelectAminoAcid() { + this.currentState = new SelectAminoAcid(this) + this.die.value = 15 + const nucleotide = this.currentGenome.nucleotides[15] + nucleotide.value = 'A' + this.currentGenome.selectedNucleotide = nucleotide + } + _debugStartWithError() { this.currentState = new ShowError(this, new CloneNucleotide(this)) this.error.innerHTML = 'test an error' -- cgit v1.2.3