Skip to content

Instantly share code, notes, and snippets.

@diekmann
Created November 3, 2019 18:26
Show Gist options
  • Save diekmann/f467c75374da34fdbac57262e4a2ba14 to your computer and use it in GitHub Desktop.
Save diekmann/f467c75374da34fdbac57262e4a2ba14 to your computer and use it in GitHub Desktop.
A DFA implemented in CSS, telling if a number is divisible by 3
<!DOCTYPE html>
<html>
<head>
<style>
body {
counter-reset: bits; /*integer value of the binary number represented by checkboxes. */
}
/* Style only: change colors of checkbox labels */
input[type="checkbox"] + label{
background-color: yellow;
}
input[type="checkbox"]:checked + label{
background-color: orange;
}
div.count-by-width {
--bit0: 0; /*Boolean*/
--bit1: 0;
--bit2: 0;
--bit3: 0;
--value: calc((var(--bit0)*1 + var(--bit1)*2 + var(--bit2)*4 + var(--bit3)*8));
background-color: red;
white-space: nowrap;
width: calc(var(--value) * 20px);
}
/* Increment clounter by the value each bit represents */
input#c0:checked {
counter-increment: bits 1;
}
input#c1:checked {
counter-increment: bits 2;
}
input#c2:checked {
counter-increment: bits 4;
}
input#c3:checked {
counter-increment: bits 8;
}
/*Bit 0*/
input#c0:checked ~ div.count-by-width{
--bit0: 1;
}
/*Bit 1*/
input#c1:checked ~ div.count-by-width{
--bit1: 1;
}
/*Bit 2*/
input#c2:checked ~ div.count-by-width{
--bit2: 1;
}
/*Bit 3*/
input#c3:checked ~ div.count-by-width{
--bit3: 1;
}
/* Display counter value */
div.value::before {
content: "value: " counter(bits) " ";
}
/* https://www.geeksforgeeks.org/check-binary-string-multiple-3-using-dfa/ */
/* Next bit will be Bit 1 */
input#next-bit-is-bit0:checked + label::before {
background-color: red;
content: "uncheck me after you did the state transition ";
}
input#next-bit-is-bit0:checked ~ input#next-bit-is-bit1 + label::before {
background-color: red;
content: "check me ";
}
/* Next bit will be Bit 2 */
input#next-bit-is-bit1:checked + label::before {
background-color: red;
content: "uncheck me after you did the state transition ";
}
input#next-bit-is-bit1:checked ~ input#next-bit-is-bit2 + label::before {
background-color: red;
content: "check me ";
}
/* Next bit will be Bit 3 */
input#next-bit-is-bit2:checked + label::before {
background-color: red;
content: "uncheck me after you did the state transition ";
}
input#next-bit-is-bit2:checked ~ input#next-bit-is-bit3 + label::before {
background-color: red;
content: "check me ";
}
/* Next bit will be Bit 4 */
input#next-bit-is-bit3:checked + label::before {
background-color: red;
content: "uncheck me after you did the state transition ";
}
input#next-bit-is-bit3:checked ~ input#next-bit-is-bit4 + label::before {
background-color: red;
content: "check me ";
}
/*
Now some state transitions, generated with python
for i in range(4):
print(f"""input#c{i}:not(:checked) ~ input#next-bit-is-bit{i}:checked ~ input#state0:checked + label::before{{
background-color: red;
content: "check me ";
}}""")
*/
/* Next Bit is 0 & we are in state 0 -> state 0 */
input#c0:not(:checked) ~ input#next-bit-is-bit0:checked ~ input#state0:checked + label::before{
background-color: red;
content: "stay here ";
}
input#c1:not(:checked) ~ input#next-bit-is-bit1:checked ~ input#state0:checked + label::before{
background-color: red;
content: "stay here ";
}
input#c2:not(:checked) ~ input#next-bit-is-bit2:checked ~ input#state0:checked + label::before{
background-color: red;
content: "stay here ";
}
input#c3:not(:checked) ~ input#next-bit-is-bit3:checked ~ input#state0:checked + label::before{
background-color: red;
content: "stay here ";
}
/* Next Bit is 1 & we are in state 0 -> state 1 */
input#c0:checked ~ input#next-bit-is-bit0:checked ~ input#state0:checked ~ input#state1 + label::before{
background-color: red;
content: "check me ";
}
input#c1:checked ~ input#next-bit-is-bit1:checked ~ input#state0:checked ~ input#state1 + label::before{
background-color: red;
content: "check me ";
}
input#c2:checked ~ input#next-bit-is-bit2:checked ~ input#state0:checked ~ input#state1 + label::before{
background-color: red;
content: "check me ";
}
input#c3:checked ~ input#next-bit-is-bit3:checked ~ input#state0:checked ~ input#state1 + label::before{
background-color: red;
content: "check me ";
}
/* Next Bit is 0 & we are in state 1 -> state 2 */
input#c0:not(:checked) ~ input#next-bit-is-bit0:checked ~ input#state1:checked ~ input#state2 + label::before{
background-color: red;
content: "check me ";
}
input#c1:not(:checked) ~ input#next-bit-is-bit1:checked ~ input#state1:checked ~ input#state2 + label::before{
background-color: red;
content: "check me ";
}
input#c2:not(:checked) ~ input#next-bit-is-bit2:checked ~ input#state1:checked ~ input#state2 + label::before{
background-color: red;
content: "check me ";
}
input#c3:not(:checked) ~ input#next-bit-is-bit3:checked ~ input#state1:checked ~ input#state2 + label::before{
background-color: red;
content: "check me ";
}
/* Next Bit is 1 & we are in state 1 -> state 0 */
input#c0:checked ~ input#next-bit-is-bit0:checked ~ input#state1:checked ~ div#state-instructions::before {
background-color: red;
content: "please move to state 0";
}
input#c1:checked ~ input#next-bit-is-bit1:checked ~ input#state1:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 0";
}
input#c2:checked ~ input#next-bit-is-bit2:checked ~ input#state1:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 0";
}
input#c3:checked ~ input#next-bit-is-bit3:checked ~ input#state1:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 0";
}
/* Next Bit is 0 & we are in state 2 -> state 1 */
input#c0:not(:checked) ~ input#next-bit-is-bit0:checked ~ input#state2:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 1";
}
input#c1:not(:checked) ~ input#next-bit-is-bit1:checked ~ input#state2:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 1";
}
input#c2:not(:checked) ~ input#next-bit-is-bit2:checked ~ input#state2:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 1";
}
input#c3:not(:checked) ~ input#next-bit-is-bit3:checked ~ input#state2:checked ~ #state-instructions::before {
background-color: red;
content: "please move to state 1";
}
/* Next Bit is 1 & we are in state 2 -> state 3 */
input#c0:checked ~ input#next-bit-is-bit0:checked ~ input#state2:checked + label::before {
background-color: red;
content: "stay here ";
}
input#c1:checked ~ input#next-bit-is-bit1:checked ~ input#state2:checked + label::before {
background-color: red;
content: "stay here ";
}
input#c2:checked ~ input#next-bit-is-bit2:checked ~ input#state2:checked + label::before {
background-color: red;
content: "stay here ";
}
input#c3:checked ~ input#next-bit-is-bit3:checked ~ input#state2:checked + label::before {
background-color: red;
content: "stay here ";
}
input#state0:checked ~ #dfa-termination::before {
background-color: green;
content: "DFA is in accepting state";
}
</style>
</head>
<body>
The following checkboxes model the bits of a register.
Please enter your number in binary.<br>
<input type="checkbox" id="c3"><label for="c3">Bit 3</label>
<input type="checkbox" id="c2"><label for="c2">Bit 2</label>
<input type="checkbox" id="c1"><label for="c1">Bit 1</label>
<input type="checkbox" id="c0"><label for="c0">Bit 0</label>
<br>
<div class="count-by-width">the width of this div corresponds the value of the register</div>
<br>
<hr>
The thing between the horizontal lines implements a DFA which tells if the number you entered is divisible by 3.<br>
You need to do manual clicking to process the input.
First, do the state transitions as described, then advance the checkboxes which point to the bit which should be processed next.
You need to make those steps atomically, don't get confused when everything changes after you did the state transition ;-).
You should do: state transition, move to bit 1; state transition, move to bit 2; state transition, move to bit 3; state transition.
<br><br>
The following checkboxes describe which Bit should be processed next.
Exactly one checkbox must be checked.
Follow the checkboxes' instructions to make the automaton point to the next bit.
Please move the state (boxes below) forward first!
<br>
<input type="checkbox" id="next-bit-is-bit0" checked><label for="next-bit-is-bit0">next bit is bit 0</label>
<input type="checkbox" id="next-bit-is-bit1"><label for="next-bit-is-bit1">next bit is bit 1</label>
<input type="checkbox" id="next-bit-is-bit2"><label for="next-bit-is-bit2">next bit is bit 2</label>
<input type="checkbox" id="next-bit-is-bit3"><label for="next-bit-is-bit3">next bit is bit 3</label>
<input type="checkbox" id="next-bit-is-bit4"><label for="next-bit-is-bit4">next bit would be bit 4 (you are done)</label>
<br><br>
The following checkboxes are the internal state of the automaton.
Exactly one checkbox must be checked. If checking a new box, uncheck the other.
Follow the checkboxes' instructions to move forward the state.<br>
<input type="checkbox" id="state0" checked><label for="state0">state0</label>
<input type="checkbox" id="state1"><label for="state1">state1</label>
<input type="checkbox" id="state2"><label for="state2">state2</label>
<div id="state-instructions">
<!--CSS does not have a selector for a previous element.
Whenever we need to make a state transition backwards, we need to ask the user. -->
</div>
<br><br>
<div id="dfa-termination"><div>
<br>
<hr>
<br>
The value of the register is shown with CSS counters in the following div:
<div class="value"> (decimal)</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment