{"protected":false,"mode":"f","metadata":{"name":"spinny","author":"Anya Merry :3","version":[0,0,3],"dependencies":[],"paths":{"spinny.js":"%B/spinny.js","s.spin":"/s.spin","r.spin":"/r.spin"}},"content":"{\"spinny.js\":{\"protected\":false,\"metadata\":{\"runner\":\"js\"},\"mode\":\"f\",\"content\":\"////////////////////////////////////\\n// SPINNY : A Programming Language /\\n////////////////////////////////////\\n\\n// This is the Spinny compiler and\\n// interpreter for itty.\\n// It accepts\\n// - Spinny source files (.spin)\\n// - Spinny compiled json files (.spic)\\n\\ntry {\\nasync function onRun() {\\n\\tlet cliArgs = parseCliArgs();\\n\\tlet fileobj\\n\\tlet file\\n\\n\\t// File open:\\n\\ttry {\\n\\t\\tfileobj = io.open(fs.resolve(cliArgs.filename), \\\"r\\\")\\n\\t} catch (e) {\\n\\t\\tdisplay.print(`Spinny: Error opening file or resolving path \\\\`${cliArgs.filename}'.`);\\n\\t\\tdisplay.print(`${e.name}@${e.lineNumber}-${e.columnNumber}: ${e.message}`);\\n\\t\\tio.error([22, \\\"file open failed\\\"]);\\n\\t}\\n\\ttry {\\n\\t\\tfile = fileobj.read();\\n\\t} catch (e) {\\n\\t\\tdisplay.print(`Spinny: Error reading file \\\\`${cliArgs.filename}'.`);\\n\\t\\tdisplay.print(`${e.name}@${e.lineNumber}-${e.columnNumber}: ${e.message}`);\\n\\t\\tio.error([23, \\\"file read failed\\\"]);\\n\\t}\\n\\n\\t// Spinc Checker:\\n\\tlet isSpincFile = false;\\n\\tif (file.split(\\\"\\\\n\\\").length > 1) {\\n\\t\\tconst fileSpincVersion = file.split(\\\"\\\\n\\\")[1].split(\\\"@\\\");\\n\\t\\tif (fileSpincVersion.length > 2 &&\\n\\t\\t\\tfileSpincVersion.slice(0,2).join(\\\"\\\\n\\\") === \\\"SPINC\\\\nspinny:itty\\\") {\\n\\t\\t\\t// This is a spinny source file\\n\\t\\t\\tif (fileSpincVersion[2] !== \\\"noversion\\\") {\\n\\t\\t\\t\\tlet niceversion = spileSpincVersion[2].replace(\\n\\t\\t\\t\\t\\t/[\\\\t %]/g , \\\"\\\")\\n\\t\\t\\t\\tdisplay.print(\\\"Spinny: Incorrect or unrecognized compiled spinc file\\\");\\n\\t\\t\\t\\tdisplay.print(`Spinny: version \\\\`${niceversion}'.`);\\n\\t\\t\\t\\tdisplay.print(\\\"Spinny: This version of the spinny interpreter exclusively\\\");\\n\\t\\t\\t\\tdisplay.print(\\\"Spinny: accepts compiled spinc files of version\\\");\\n\\t\\t\\t\\tdisplay.print(\\\"Spinny: `noversion'.\\\");\\n\\t\\t\\t\\tdisplay.print(\\\"Spinny: Use `—version' or `—help' for more information.\\\");\\n\\t\\t\\t\\tio.error([31, \\\"invalid spinc version\\\"]);\\n\\t\\t\\t}\\n\\t\\t\\tisSpincFile = true;\\n\\t\\t}\\n\\t}\\n\\tif (cliArgs.compileOnly && isSpincFile) {\\n\\t\\tdisplay.print(\\\"Spinny: Cannot compile a spinc file.\\\");\\n\\t\\tdisplay.print(\\\"Spinny: The file is already compiled.\\\");\\n\\t\\tio.error([32, \\\"spinc already compiled\\\"]);\\n\\t}\\n\\n\\tlet compiled\\n\\tif (!isSpincFile) {\\n\\t\\t// We must compile the file\\n\\t\\tconst parser = new spinnyParser({\\n\\t\\t\\tparsestep:cliArgs.debugStep\\n\\t\\t});\\n\\t\\tlet compiled;\\n\\t\\ttry {\\n\\t\\t\\tcompiled = await parser.compile(file)\\n\\t\\t} catch (e) {\\n\\t\\t\\tif (!(e instanceof spinnyCompileError))\\n\\t\\t\\t\\tthrow e\\n\\t\\t\\tlet debug = e.debugStack\\n\\t\\t\\tlet last = e.debugStack.slice(-1)[0]\\n\\t\\t\\tdisplay.print(\\\"Spinny: Error compiling file...\\\");\\n\\t\\t\\tdisplay.print(`Spinny: Unfinished ${last[0]} at ${last[1]}`);\\n\\t\\t\\tio.error([45, \\\"compilation failed\\\"]);\\n\\t\\t}\\n\\t\\tdisplay.print(JSON.stringify(compiled))\\n\\t\\tquit();\\n\\t}\\n\\n\\tdisplay.print(\\\"Spinny: Running and/or saving files is not currently supported.\\\");\\n\\tdisplay.print(\\\"Spinny: Dumping contents instead.\\\");\\n\\tif (isSpincFile)\\n\\t\\tdisplay.print(file.split(\\\"\\\\n\\\").slice(2).join('\\\\n'))\\n}\\n\\nfunction showHelp(){\\n\\tdisplay.print(\\n\\t\\t// . 1 . 2 . 3 . 4 . 5 . 6\\n\\t\\t// ^\\n\\t\\t\\\"This is the Spinny compiler and interpreter for itty.\\\\n\\\" +\\n\\t\\t\\\"It accepts...\\\\n\\\" +\\n\\t\\t\\\" • Spinny source files (.spin)\\\\n\\\" +\\n\\t\\t\\\" • Spinny compiled json files (.spinc)\\\\n\\\" +\\n\\t\\t\\\"\\\\n\\\" +\\n\\t\\t\\\"Syntax:\\\\n\\\" +\\n\\t\\t`\\\\t${program.name} [flags...] [—] \\\\n` +\\n\\t\\t\\\"Where:\\\\n\\\" +\\n\\t\\t\\\"\\\\t[flags...] are any combination of the flags\\\\n\\\" +\\n\\t\\t\\\"\\\\t available in the `Flags' section\\\\n\\\" +\\n\\t\\t\\\"\\\\t below.\\\\n\\\" +\\n\\t\\t\\\"\\\\t[—] Is an emdash (—) or a double dash (--)\\\\n\\\" +\\n\\t\\t\\\"\\\\t to mark where the filename is supposed\\\\n\\\" +\\n\\t\\t\\\"\\\\t to go. (Note that any time you see an\\\\n\\\" +\\n\\t\\t\\\"\\\\t em dash in this help page, you may\\\\n\\\" +\\n\\t\\t\\\"\\\\t choose to use a double dash in its\\\\n\\\" +\\n\\t\\t\\\"\\\\t place if that is your preference.)\\\\n\\\" +\\n\\t\\t\\\"\\\\t is the `.spin' or `.spinc' file to\\\\n\\\" +\\n\\t\\t\\\"\\\\t compile/run\\\\n\\\" +\\n\\t\\t\\\"Flags:\\\\n\\\" +\\n\\t\\t\\\"\\\\t—help Print this help page and exit.\\\\n\\\" +\\n\\t\\t\\\"\\\\t—version Print version and exit.\\\\n\\\" +\\n\\t\\t\\\"\\\\t—compile Compile the code to a .spinc file.\\\\n\\\" +\\n\\t\\t\\\"\\\\t The .spinc file must be specified\\\\n\\\" +\\n\\t\\t\\\"\\\\t with `—output'.\\\\n\\\" +\\n\\t\\t\\\"\\\\t—output Specifies the output file for the\\\\n\\\" +\\n\\t\\t\\\"\\\\t `—compile' flag.\\\\n\\\"\\n\\t);\\n};\\n\\nfunction showVersion(){\\n\\tdisplay.print(\\n\\t\\t// . 1 . 2 . 3 . 4 . 5 . 6\\n\\t\\t// ^\\n\\t\\t\\\"Spinny for itty\\\\n\\\" +\\n\\t\\t\\\"Version 0.0.3\\\\n\\\" +\\n\\t\\t\\\"Known spinc versions:\\\\n\\\" +\\n\\t\\t\\\" • `noversion'\\\\n\\\"\\n\\t)\\n};\\n\\nfunction parseCliArgs() {\\n\\tlet compileOnly = false;\\n\\tlet filename = null;\\n\\tlet noMoreFlags = false;\\n\\tlet nextIsOutput = false\\n\\tlet output = \\\"\\\";\\n\\tlet letterFlag = false\\n\\tlet flag = false\\n\\tlet debugStep = false\\n\\tfor (let i=0;i\\\":\\n\\t\\t\\t\\t\\tif (inside === this.INSIDE.INTER)\\n\\t\\t\\t\\t\\t\\tbreak wordLoop\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tcase \\\"\\\\n\\\":\\n\\t\\t\\t\\t\\tif (inside === this.INSIDE.FILE\\n\\t\\t\\t\\t\\t\\t|| inside == this.INSIDE.LAZY)\\n\\t\\t\\t\\t\\t\\tbreak wordLoop\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tcase \\\"\\\\\\\\\\\":\\n\\t\\t\\t\\t\\tif (this.now() == \\\"\\\\\\\\\\\" && this.peek() == \\\"\\\\n\\\") {\\n\\t\\t\\t\\t\\t\\t// Line continuation\\n\\t\\t\\t\\t\\t\\t// Go to next line\\n\\t\\t\\t\\t\\t\\tthis.next(); // skip `\\\\\\\\'\\n\\t\\t\\t\\t\\t\\tthis.next(); // skip `\\\\n'\\n\\t\\t\\t\\t\\t\\tcontinue\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t\\twords.push(await this.parseWord(inside));\\n\\t\\t}\\n\\t\\tawait this.untag()\\n\\t\\treturn words\\n\\t}\\n\\n\\tasync parseComment() {\\n\\t\\tawait this.tag(\\\"Comment\\\")\\n\\t\\tcommentLoop:\\n\\t\\twhile (1) {\\n\\t\\t\\tswitch (this.now()) {\\n\\t\\t\\t\\tcase \\\"\\\\n\\\":\\n\\t\\t\\t\\t\\tbreak commentLoop\\n\\t\\t\\t\\tcase \\\"\\\\\\\\\\\":\\n\\t\\t\\t\\t\\tif (this.peek() == \\\"\\\\n\\\")\\n\\t\\t\\t\\t\\t\\tbreak commentLoop\\n\\t\\t\\t\\tdefault:\\n\\t\\t\\t\\t\\tthis.next();\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tawait this.untag()\\n\\t}\\n\\n\\tasync parseWord(inside) {\\n\\t\\tawait this.tag(\\\"Word\\\")\\n\\t\\tlet bang = false;\\n\\t\\tlet word = {}\\n\\t\\tword[CMPVER.KEYS.BANG] = false;\\n\\t\\tif (this.now() === \\\"!\\\") {\\n\\t\\t\\tword[CMPVER.KEYS.BANG] = true;\\n\\t\\t\\tthis.next();\\n\\t\\t}\\n\\t\\tswitch (this.now()) {\\n\\t\\t\\tcase \\\"{\\\":\\n\\t\\t\\t\\tword[CMPVER.KEYS.TYPE] = CMPVER.TYPE.LAZY;\\n\\t\\t\\t\\tword[CMPVER.KEYS.LINES] = await this.parseLazy();\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tcase \\\"`\\\":\\n\\t\\t\\t\\tword[CMPVER.KEYS.TYPE] = CMPVER.TYPE.LIT;\\n\\t\\t\\t\\tword[CMPVER.KEYS.PARTS] = await this.parseLiteral();\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tdefault:\\n\\t\\t\\t\\tword[CMPVER.KEYS.TYPE] = CMPVER.TYPE.ID;\\n\\t\\t\\t\\tword[CMPVER.KEYS.PARTS] = await this.parseIdentifier(inside);\\n\\t\\t}\\n\\t\\tawait this.untag()\\n\\t\\treturn word\\n\\t}\\n\\n\\tasync parseLazy() {\\n\\t\\tawait this.tag(\\\"Lazy\\\")\\n\\t\\tthis.next(); // Skip `{'\\n\\t\\tlet lines = []\\n\\t\\twhile (this.now() !== \\\"}\\\") {\\n\\t\\t\\tlines.push(await this.parseLine(this.INSIDE.LAZY))\\n\\t\\t\\tif (this.now() === \\\"\\\\n\\\")\\n\\t\\t\\t\\t// Continue to next line like a file would\\n\\t\\t\\t\\tthis.next();\\n\\t\\t}\\n\\t\\tthis.next(); // Skip `}'\\n\\t\\tawait this.untag()\\n\\t\\treturn lines\\n\\t}\\n\\n\\tasync parseLiteral() {\\n\\t\\tawait this.tag(\\\"Literal\\\")\\n\\t\\tthis.next(); // Skip `\\\\`'\\n\\t\\tlet parts = [\\\"\\\"]\\n\\t\\twhile (this.now() !== \\\"\\\\'\\\") {\\n\\t\\t\\tswitch (this.now()) {\\n\\t\\t\\t\\tcase \\\"\\\\\\\\\\\":\\n\\t\\t\\t\\t\\tparts[parts.length-1]+=await this.parseEscape();\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tcase \\\"<\\\":\\n\\t\\t\\t\\t\\tparts.push(\\n\\t\\t\\t\\t\\t\\tawait this.parseInterpolation()\\n\\t\\t\\t\\t\\t);\\n\\t\\t\\t\\t\\tparts.push(\\\"\\\")\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tdefault:\\n\\t\\t\\t\\t\\tparts[parts.length-1]+=this.now();\\n\\t\\t\\t\\t\\tthis.next();\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tthis.next(); // Skip `\\\\''\\n\\t\\tawait this.untag();\\n\\t\\treturn parts\\n\\t}\\n\\n\\tasync parseEscape() {\\n\\t\\tawait this.tag(\\\"Escape\\\")\\n\\t\\tthis.next(); // skip `\\\\\\\\'\\n\\t\\tlet out = \\\"\\\";\\n\\t\\tswitch (this.now()) {\\n\\t\\t\\tcase \\\"<\\\":\\n\\t\\t\\t\\tthis.next(); // skip `\\\\<'\\n\\t\\t\\t\\tout = \\\"<\\\";\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"x\\\":\\n\\t\\t\\t\\tthis.next(); // skip `x'\\n\\t\\t\\t\\tout = String.fromCharCode( parseInt(\\n\\t\\t\\t\\t\\tthis.next()+this.next()\\n\\t\\t\\t\\t\\t,16));\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"u\\\":\\n\\t\\t\\t\\tthis.next(); // skip `u'\\n\\t\\t\\t\\tout = String.fromCharCode( parseInt(\\n\\t\\t\\t\\t\\tthis.next()+this.next()+this.next()+this.next()\\n\\t\\t\\t\\t\\t,16));\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"U\\\":\\n\\t\\t\\t\\tthis.next(); // skip `U'\\n\\t\\t\\t\\tout = String.fromCharCode( parseInt(\\n\\t\\t\\t\\t\\tthis.next()+this.next()+this.next()+this.next()+\\n\\t\\t\\t\\t\\tthis.next()+this.next()+this.next()+this.next()\\n\\t\\t\\t\\t\\t,16));\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"s\\\":\\n\\t\\t\\t\\tthis.next(); // skip `s'\\n\\t\\t\\t\\tout = \\\" \\\";\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"t\\\":\\n\\t\\t\\t\\tthis.next(); // skip `t'\\n\\t\\t\\t\\tout = \\\"\\\\t\\\";\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"n\\\":\\n\\t\\t\\t\\tthis.next(); // skip `n'\\n\\t\\t\\t\\tout = \\\"\\\\n\\\";\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tdefault:\\n\\t\\t\\t\\t// Just send the character:\\n\\t\\t\\t\\tout = this.now(); // record the thing after the `\\\\\\\\'\\n\\t\\t\\t\\tthis.next(); // skip over it\\n\\t\\t\\t\\tbreak\\n\\n\\t\\t}\\n\\t\\tawait this.untag();\\n\\t\\treturn out;\\n\\t}\\n\\n\\tasync parseInterpolation() {\\n\\t\\tawait this.tag(\\\"Interpolation\\\")\\n\\t\\tthis.next(); // skip `\\\\<'\\n\\t\\tlet line\\n\\t\\twhile (this.now() !== \\\">\\\") {\\n\\t\\t\\tline = await this.parseLine(this.INSIDE.INTER)\\n\\t\\t}\\n\\t\\tthis.next(); // skip `>'\\n\\t\\tawait this.untag()\\n\\t\\treturn line\\n\\t}\\n\\n\\tasync parseIdentifier(inside) {\\n\\t\\tawait this.tag(\\\"Identifier\\\")\\n\\t\\tlet parts = [\\\"\\\"]\\n\\t\\tidLoop:\\n\\t\\twhile (1) {\\n\\t\\t\\tswitch (this.now()) {\\n\\t\\t\\t\\tcase \\\"\\\\\\\\\\\":\\n\\t\\t\\t\\t\\tparts[parts.length-1]+=await this.parseEscape();\\n\\t\\t\\t\\t\\tcontinue\\n\\t\\t\\t\\tcase \\\"<\\\":\\n\\t\\t\\t\\t\\tparts.push(\\n\\t\\t\\t\\t\\t\\tawait this.parseInterpolation()\\n\\t\\t\\t\\t\\t);\\n\\t\\t\\t\\t\\tparts.push(\\\"\\\")\\n\\t\\t\\t\\t\\tcontinue\\n\\t\\t\\t\\tcase \\\"}\\\":\\n\\t\\t\\t\\t\\tif (inside === this.INSIDE.LAZY)\\n\\t\\t\\t\\t\\t\\tbreak idLoop\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tcase \\\">\\\":\\n\\t\\t\\t\\t\\tif (inside === this.INSIDE.INTER)\\n\\t\\t\\t\\t\\t\\tbreak idLoop\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tcase \\\"#\\\":\\n\\t\\t\\t\\tcase \\\" \\\":\\n\\t\\t\\t\\tcase \\\"\\\\t\\\":\\n\\t\\t\\t\\tcase \\\"\\\\n\\\":\\n\\t\\t\\t\\t\\tbreak idLoop\\n\\t\\t\\t}\\n\\t\\t\\tparts[parts.length-1]+=this.now();\\n\\t\\t\\tthis.next();\\n\\t\\t}\\n\\t\\tawait this.untag();\\n\\t\\treturn parts\\n\\t}\\n}\\n\\nconst SPIDNEY = {//spinny identifiers\\n\\t\\\"noversion\\\": {\\n\\t\\tNAME: \\\"noversion\\\",\\n\\t\\tKEYS: {\\n\\t\\t\\tTYPE: \\\"t\\\",\\n\\t\\t\\tBANG: \\\"b\\\",\\n\\t\\t\\tPARTS: \\\"p\\\",\\n\\t\\t\\tLINES: \\\"l\\\"\\n\\t\\t},\\n\\t\\tTYPE: {\\n\\t\\t\\tLIT: 0,\\n\\t\\t\\tID: 1,\\n\\t\\t\\tLAZY: 2\\n\\t\\t}\\n\\t}\\n}\\nconst CMPVER = SPIDNEY[\\\"noversion\\\"] //compileversion\\n\\n// When the program starts:\\n\\tawait onRun();\\n\\tquit();\\n} catch (e) {\\n\\tdisplay.print(`Spinny: Something has gone horribly wrong, commander.`);\\n\\tdisplay.print(`${e.name}@${e.lineNumber}-${e.columnNumber}: ${e.message}`);\\n\\tio.error([9, \\\"unknown error\\\"]);\\n}\\n\"},\"s.spin\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"out `Small ``Game\\\\'\\\\'\\\\n'\\nuse term\\n\\n# Before we begin, a few notes\\n# - All objects are strings\\n# - There are a few different kinds of objects.\\n# - variables which have a static value they always evaluate to\\n# - lazies (contained by curlies (`{' and `}')) lazilly evaluate the lines\\n# within themselves only when nessicary. They may take arguments the same\\n# way commands do\\n# - commands, which are essentially lazies behind the mask of a variable name\\n# - strings, contained by a backtick to open (``') and a single quote to close\\n# (`\\\\'').\\n# - Each line begins with any object\\n# - builtin commands are always 3 characters long\\n# - the starting object is followed by a space, then the arguments, which are\\n# space seperated objects\\n# - the arguments are passed to the first object\\n# - variables and strings ignore these arguments\\n# - commands and lazies may access these arguments with the `arg' command\\n# - interpolation, either within a variable name, command name, or string, is \\n# done with the `<...>' syntax.\\n# - The arrows, as they're called, evaluate the line inside them, then insert\\n# that value into the variable name/command name/string.\\n# - thus a lone `' on a line evaluates to the value of the variable\\n# that is named by varname.\\n# - To say that backwards, varname contains the name of a variable, and that\\n# variable has a value, and that value is what we're getting.\\n# - When a object begins with a bang (`!'), if object being evaluated sets any\\n# variables, it sets them within the current scope.\\n# - Variable and function names are stripped of bangs and spaces.\\n# - Booleans don't exist. Instead, any string that is empty (`') is truthy and\\n# all other (non-empty) strings are falsey.\\n# - Numbers are strings in the formats:\\n# - `[+\\\\-]?real(\\\\.dec)?[+\\\\-]imag(\\\\.dec)?i'\\n# - `[+\\\\-]?real(\\\\.dec)?'\\n# - `[+\\\\-]?imag(\\\\.dec)?i'\\n# - where, imag is the immaginary part, real is the real part, and the .dec is\\n# the decimal part of the one it appears to the right of.\\n# - These strings are in any base from 3 to 19.\\n# - bases 20+ are reserved since they would involve the letter i (which\\n# denotes the immaginary part)\\n# - the current base is defined by the 'base' variable, which is always in\\n# base 2.\\n# - base 2 is reserved for no good reason.\\n# - all bases lower than two are reserved because they're inconveinent to\\n# implement.\\n\\nset `score' `0'\\nset `win.maxw' {\\n\\t# ^ win.maxw is just the variable name. The dot is just a character.\\n\\t# the dot doesn't mean anything special here.\\n\\n\\t# We doin RPN :O\\n\\tsub `1' term:rows\\n\\t# `term:rows' is the name a command being run.\\n\\t# since variable names are quite permissive, this is just the name of a\\n\\t# command defined within the file `term' (imported at the top)\\n}\\nset `win.maxh' {sub `1' term:cols}\\n\\nset `guy.char' `\\\\U0001FBC5'\\nset `guy.x' `1'\\nset `guy.y' `1'\\n\\n# Unicode is supported inside quotes:\\nset `star.char' `⭐'\\n\\n# `def' defines a command\\ndef randstarpos {\\n\\tset `star.x' {\\n\\t\\t# Get the real part of the rounded number after adding 1. (\\n\\t\\t# rounding removes decimal parts but leaves the immaginary\\n\\t\\t# part):\\n\\t\\trea {rnd {add `1' {\\n\\t\\t\\tmul win.maxw rnd \\n\\t\\t\\t# ^ rnd returns a random number\\n\\t\\t\\t# from 0 to 1\\n\\t\\t}}}\\n\\t}\\n\\tset `star.y' {rea {rnd\\n\\t\\tadd `1' {mul rnd win.maxh}\\n\\t}}\\n}\\ndef w {set `guy.y' {rea {rnd {\\n\\t\\tmax `1' {sub `1' guy.y}\\n}}}}\\ndef a {set `guy.x' {rea {rnd {max `1' {sub `1' guy.x}}}}}\\ndef s {set `guy.y' {rea {rnd {min win.maxh {add `1' guy.y}}}}}\\ndef d {set `guy.x' {rea {rnd {min win.maxw {add `1' guy.x}}}}}\\n\\n!randstarpos\\ninf !{\\n#^the infinite loop command.\\n#Note that the bang is nessicary as otherwise, the lazy would always\\n#inherit the same state.\\n\\tout `\\\\x1b[;H'\\n\\t# ^writes to stdout\\n\\tout `\\\\x1b[;H'\\n\\tmap inp \\\\\\n\\t\\t`w' !w \\\\\\n\\t\\t`k' !w \\\\\\n\\t\\t`a' !a \\\\\\n\\t\\t`j' !a \\\\\\n\\t\\t`s' !s \\\\\\n\\t\\t`h' !s \\\\\\n\\t\\t`d' !d \\\\\\n\\t\\t`l' !d \\\\\\n\\t\\tdefa {}\\n\\t# ^map -- maps a value to a result\\n\\t# The arguments alternate between\\n\\t# things to match against and lazies\\n\\t# to run as a result of those matches.\\n\\t# The result is always a block that\\n\\t# will be ccl'd if the match is found.\\n\\t# The last thing to match against is\\n\\t# always assumed to be the default.\\n\\t# It is convention to make the last\\n\\t# matching argument `defa'.\\n\\t# `inp' gets a single char from stdin.\\n\\n\\tifs {\\n\\t\\teql `' `'\\n\\t\\t# ^ eql will return `f' if they're\\n\\t\\t# not equal and `' if they're equal.\\n\\t\\teql `' `'\\n\\t\\t# Note that since output is combined, this block is effectively\\n\\t\\t# an and operator. The actual and operator is better tho. It\\n\\t\\t# provides short-circuting.\\n\\t} then !{\\n\\t\\t!randstarpos\\n\\t\\tset score {add `1' score}\\n\\t\\tout `\\\\x1b[2J\\\\x1b[HScore: '\\n\\t}\\n}\\n\\n\"},\"r.spin\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"out `Small ``Game\\\\'\\\\'\\\\n'\\nuse term\\n\\nset `score' `0'\\nset `win.maxw' {\\n\\t# ^ win.maxw is just the variable name. The dot is just a character.\\n\\t# the dot doesn't mean anything special here.\\n\\n\\t# We doin RPN :O\\n\\tsub `1' \\\\\\n\\t# `term:rows' is the name a command being run. \\\\\\n\\t# since variable names are quite permissive, this is just the name of a \\\\\\n\\t# command defined within the file `term' (imported at the top) \\\\\\n\\t# \\\\\\n\\t# Also note that a \\\\ at the end of a line, even after a comment \\\\\\n\\t# continues a line. meaning, term:rows will be the seconc argument \\\\\\n\\t# of the subtraction above. \\\\\\n\\tterm:rows \\n}\\nset `win.maxh' {sub `1' term:cols}\\n\\nset `guy.char' `\\\\U0001FBC5'\\nset `guy.x' `1'\\nset `guy.y' `1'\\n\\n# Unicode is supported inside quotes:\\nset `star.char' `⭐'\\n\\n# also non-ascii is allowed in identifiers:\\nset `\\\\x1b' `hello'\\n# and escapes are allowed in the middle of identifiers:\\nout \\\\x1b # << outputs hello\\n# and interpolation can be done on its own:\\nout <`\\\\x1b'> # << also outputs hello\\n# and ofc, you could use ^[ in the raw code:\\nout \\u001b # << bad idea, but yes, it still writes hello.\\n# and then we'll undefine it for your sanity:\\ndel `\\\\x1b'\\n\\n# `def' defines a command\\ndef randstarpos {\\n\\tset `star.x' {\\n\\t\\t# Get the real part of the rounded number after adding 1. (\\n\\t\\t# rounding removes decimal parts but leaves the immaginary\\n\\t\\t# part):\\n\\t\\trea {rnd {add `1' {\\n\\t\\t\\tmul win.maxw rnd \\n\\t\\t\\t# ^ rnd returns a random number\\n\\t\\t\\t# from 0 to 1\\n\\t\\t}}}\\n\\t}\\n\\tset `star.y' {rea {rnd\\n\\t\\tadd `1' {mul rnd win.maxh}\\n\\t}}\\n}\\ndef w {set `guy.y' {rea {rnd {\\n\\t\\tmax `1' {sub `1' guy.y}\\n}}}}\\ndef a {set `guy.x' {rea {rnd {max `1' {sub `1' guy.x}}}}}\\ndef s {set `guy.y' {rea {rnd {min win.maxh {add `1' guy.y}}}}}\\ndef d {set `guy.x' {rea {rnd {min win.maxw {add `1' guy.x}}}}}\\n\\n!randstarpos\\ninf !{\\n#^the infinite loop command.\\n#Note that the bang is nessicary as otherwise, the lazy would always\\n#inherit the same state.\\n\\tout `\\\\x1b[;H'\\n\\t# ^writes to stdout\\n\\tout `\\\\x1b[;H'\\n\\tmap inp \\\\\\n\\t\\t`w' !w \\\\\\n\\t\\t`k' !w \\\\\\n\\t\\t`a' !a \\\\\\n\\t\\t`j' !a \\\\\\n\\t\\t`s' !s \\\\\\n\\t\\t`h' !s \\\\\\n\\t\\t`d' !d \\\\\\n\\t\\t`l' !d \\\\\\n\\t\\tdefa {}\\n\\t# ^map -- maps a value to a result\\n\\t# The arguments alternate between\\n\\t# things to match against and lazies\\n\\t# to run as a result of those matches.\\n\\t# The result is always a block that\\n\\t# will be ccl'd if the match is found.\\n\\t# The last thing to match against is\\n\\t# always assumed to be the default.\\n\\t# It is convention to make the last\\n\\t# matching argument `defa'.\\n\\t# `inp' gets a single char from stdin.\\n\\n\\tifs {\\n\\t\\teql `' `'\\n\\t\\t# ^ eql will return `f' if they're\\n\\t\\t# not equal and `' if they're equal.\\n\\t\\teql `' `'\\n\\t\\t# Note that since output is combined, this block is effectively\\n\\t\\t# an and operator. The actual and operator is better tho. It\\n\\t\\t# provides short-circuting.\\n\\t} then !{\\n\\t\\t!randstarpos\\n\\t\\tset score {add `1' score}\\n\\t\\tout `\\\\x1b[2J\\\\x1b[HScore: '\\n\\t}\\n}\\n\\n\"}}"}