diff options
-rw-r--r-- | amino-acid-selector.mjs | 33 | ||||
-rw-r--r-- | codon.mjs | 4 | ||||
-rw-r--r-- | genome.mjs | 1 | ||||
-rw-r--r-- | index.html | 27 | ||||
-rw-r--r-- | main.mjs | 3 | ||||
-rw-r--r-- | mobile.css | 47 | ||||
-rw-r--r-- | rules.mjs | 77 |
7 files changed, 189 insertions, 3 deletions
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 @@ -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() @@ -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 } @@ -103,6 +103,33 @@ <li>T</li> </ul> + <div id='amino-acid-selector' class='hidden'> + <p>Select the amino acid for the codon <span class='codon'>--</span></p> + <ul> + <li>Ala</li> + <li>Arg</li> + <li>Asn</li> + <li>Asp</li> + <li>Cys</li> + <li>Gln</li> + <li>Glu</li> + <li>Gly</li> + <li>His</li> + <li>Ile</li> + <li>Leu</li> + <li>Lys</li> + <li>Met</li> + <li>Phe</li> + <li>Pro</li> + <li>Ser</li> + <li>Thr</li> + <li>Trp</li> + <li>Tyr</li> + <li>Val</li> + <li>STOP</li> + </ul> + </div> + <script src='main.mjs' type='module'></script> </body> </html> @@ -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() @@ -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; @@ -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' |