Brainfuck Printer
For each input string of printable ASCII (0x20-0x7e), output a brainfuck program which produces that string. At the end of your program, append a #
followed by the brainfuck program that your code outputs when given the input string Hello, World!
. For example, if your program is
abc
and it outputs
123
when given Hello, World!
as an input, then your final submission should be
abc#123
(You don’t need a trailing newline on your submission, even if the output of your program contains one)
Judge
(async function*(context: Context): Challenge { // Split on last # const [program, helloWorldCode] = context.code.split(/#(?=[^#]*$)/); yield (await context.runCode(program, "Hello, World!")).assertEquals(helloWorldCode).setName("\"Hello, World!\" output appended"); const evalBF = (bfCode:string):string => { const tape = new Array(0x8000).fill(0); let ptr = 0; let output = ``; for(let codeIdx = 0; codeIdx < bfCode.length; codeIdx++) { let command = bfCode.charAt(codeIdx); let jumpDirection = 0; if(command==`+`) tape[ptr]++; if(command==`-`) tape[ptr]--; if(command==`>`) ptr = ptr+1 & 0x7fff; if(command==`<`) ptr = ptr-1 & 0x7fff; if(command==`.`) output += String.fromCharCode(tape[ptr] & 0xff); if(command==`[` && !(tape[ptr]&0xff)) jumpDirection = 1; if(command==`]` && (tape[ptr]&0xff)) jumpDirection = -1; for(let balance = jumpDirection;balance;) { command = bfCode.charAt(codeIdx += jumpDirection); balance += command==`[` ? 1 : command==`]` ? -1 : 0; } } return output; } // Runner adapted from runTestCases async function*runBFCases<T = string>( testCases: [string, T][], overrideOptions: Partial<TestCasesOptions<T>> = {} ): AsyncIterableIterator<TestCase> { const options: TestCasesOptions<T> = { inputSeperator: "\n", outputSeperator: "\n", numberOfRuns: 2, shuffle: true, compareFunction: (a, b) => eqIgnoreTrailingWhitespace(a, "" + b), ...overrideOptions, }; function shuffleAndDeal<T>( testCases: T[], options: { shuffle: boolean; numberOfRuns: number } ): T[][] { if (options.shuffle) { shuffle(testCases); } // Ensure the runs are uneven // This is mostly to prevent people from hardcoding the length of the input const cardsPerHand = testCases.length / (options.numberOfRuns + 1); const hands = [testCases.slice(0, Math.ceil(cardsPerHand * 2))]; for (let i = cardsPerHand * 2; i < testCases.length; i += cardsPerHand) { const hand = testCases.slice(Math.ceil(i), Math.ceil(i + cardsPerHand) + 1); if (hand.length != 0) { hands.push(hand); } } return hands; }; const hands = shuffleAndDeal(testCases, options); // TODO: When running code becomes thread safe, this should run in paralel for (const hand of hands) { const input = hand.map((i) => i[0]).join(options.inputSeperator); yield (await context.runCode(program, input)).assert((d) => { const evaluated = d.trimEnd().split(options.outputSeperator).map(evalBF); const cases = [ ...zipLongest( d.trimEnd().split(options.outputSeperator).map(evalBF), hand.map((i) => i[1]) ), ].map(([a, b]) => ({ output: a, expected: b, equal: a != undefined && options.compareFunction(a, b), })); return new TestCase( undefined, cases.every((i) => i.equal) ? "Pass" : "Fail", { Diff: { input: input, output: evaluated.join(options.outputSeperator), expected: cases .map((i) => (i.equal ? i.output : i.expected)) .join(options.outputSeperator), }, } ); }); } } yield *runBFCases([ "Hello, World!", "Byte Heist is a site where you can test your coding skills by solving challenges in as few bytes as possible.", "The 8 valid brainfuck commands are: `+`,`-`,`>`,`<`,`[`,`]`,`.`, and `,`.", "a", " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", "[>q1h`2@Xv 95Be:-Fsj73py(P!T Bayk{{Wpy|L|$ 7*kLwE|", "eL34NfeOL454KdeJ44JOdefePK55gQ67ShfTL787KegJ77JTeghfUK88iV9:XjgYL:;:KfiJ::JYfij", "J,xU #={lM#+[`iwt9cRxdz[ACiNRok~H\\6I[|72KHo]k IN9jsB:WtoUq3%c|r>:QAb\":>-hYH\" k", "i0sAVNQ Ik!EV5/E&^Ym_DJfyD<$/JkG,-kN,AQ=CT[K+L\"n^^z=", "&^5B5BF&6b%^7B&*N7H76n876 n907HM*M9[.)>][)>.0O[{>]>{I9.0,u-m8" ].map(s=>[s,s] as [string,string])); // Finally, the challenge is passed if no test cases failed return context.noFailures(); })
Example Code
input = require("fs").readFileSync(0) + ""; for (const line of input.split("\n")) { console.log( [...line].map(char => "[-]" + "+".repeat(char.charCodeAt(0)) + ".").join("") ); }#[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.[-]+++++++++++++++++++++++++++++++++.