Created
December 26, 2020 16:24
Moanfuck implementation in js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// moanfuck implementation in JavaScript | |
// Use as: interpret(<mf code>) | |
// or: interpret(convert(<bf code>)) if you want to try using bf code. | |
// logs to the console. | |
// borrowed from https://github.com/trekhleb/javascript-algorithms/blob/master/src/algorithms/string/levenshtein-distance/levenshteinDistance.js | |
function levenshteinDistance(a, b) { | |
// Create empty edit distance matrix for all possible modifications of | |
// substrings of a to substrings of b. | |
const distanceMatrix = Array(b.length + 1).fill(null).map(() => Array(a.length + 1).fill(null)); | |
// Fill the first row of the matrix. | |
// If this is first row then we're transforming empty string to a. | |
// In this case the number of transformations equals to size of a substring. | |
for (let i = 0; i <= a.length; i += 1) { | |
distanceMatrix[0][i] = i; | |
} | |
// Fill the first column of the matrix. | |
// If this is first column then we're transforming empty string to b. | |
// In this case the number of transformations equals to size of b substring. | |
for (let j = 0; j <= b.length; j += 1) { | |
distanceMatrix[j][0] = j; | |
} | |
for (let j = 1; j <= b.length; j += 1) { | |
for (let i = 1; i <= a.length; i += 1) { | |
const indicator = a[i - 1] === b[j - 1] ? 0 : 1; | |
distanceMatrix[j][i] = Math.min( | |
distanceMatrix[j][i - 1] + 1, // deletion | |
distanceMatrix[j - 1][i] + 1, // insertion | |
distanceMatrix[j - 1][i - 1] + indicator, // substitution | |
); | |
} | |
} | |
return distanceMatrix[b.length][a.length]; | |
} | |
// 0 + AH | |
// 1 - OH | |
// 2 > YES | |
// 3 < FUCK | |
// 4 , MORE | |
// 5 . YEAH | |
// 6 [ AHH | |
// 7 ] OOH | |
// 8 # BABY (debug breakpoint) | |
function interpret(code, input) { | |
var instructions = ["AH", "OH", "YES", "FUCK", "MORE", "YEAH", "AHH", "OOH", "BABY"]; | |
var cell = 0; | |
var output = ""; | |
var inputpos = 0; | |
var data = []; | |
var loop = []; | |
var next = 0; | |
var closest = function (a) { | |
var dist = instructions.map(x => levenshteinDistance(x, a)); | |
return dist.indexOf(Math.min(...dist)); | |
}; | |
var fCode = code.toUpperCase().split(" ").map(x => closest(x)) | |
while (next < fCode.length) { | |
switch (fCode[next]) { | |
case 0: | |
if (~loop[0]) { | |
data[cell] = (data[cell] || 0) + 1; | |
} | |
break; | |
case 1: | |
if (~loop[0]) { | |
data[cell] = (data[cell] || 0) - 1; | |
} | |
break; | |
case 2: | |
if (~loop[0]) { | |
cell++; | |
} | |
break; | |
case 3: | |
if (~loop[0]) { | |
cell--; | |
} | |
break; | |
case 4: | |
if (~loop[0]) { | |
data[cell] = input.charCodeAt(inputpos); | |
inputpos++; | |
} | |
break; | |
case 5: | |
if (~loop[0]) { | |
output = output + String.fromCharCode(data[cell]); | |
} | |
break; | |
case 6: | |
loop.unshift(data[cell] ? next : -1); | |
break; | |
case 7: | |
if (~loop[0] && data[cell]) { | |
next = loop[0]; | |
} else { | |
loop.shift(); | |
} | |
break; | |
case 8: | |
console.log("Current state:", data) | |
break; | |
default: | |
console.log("idk what the hell you did but you got this message"); | |
} | |
next++; | |
} | |
console.log(output) | |
} | |
function convert(code) { | |
var instructions = ["AH", "OH", "YES", "FUCK", "MORE", "YEAH", "AHH", "OOH", "BABY"]; | |
var bf = "+-><,.[]#"; | |
var c = code.split(''); | |
var newC = c.map(x => instructions[bf.indexOf(x)]).join(" "); | |
console.log(newC); | |
return newC; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment