diff options
Diffstat (limited to '2-the-false-awakens')
| -rw-r--r-- | 2-the-false-awakens/authors.markdown | 3 | ||||
| -rw-r--r-- | 2-the-false-awakens/entry.clean.rb | 100 | ||||
| -rw-r--r-- | 2-the-false-awakens/entry.rb | 57 | ||||
| -rw-r--r-- | 2-the-false-awakens/remarks.markdown | 248 |
4 files changed, 408 insertions, 0 deletions
diff --git a/2-the-false-awakens/authors.markdown b/2-the-false-awakens/authors.markdown new file mode 100644 index 0000000..f308e56 --- /dev/null +++ b/2-the-false-awakens/authors.markdown @@ -0,0 +1,3 @@ +* Kensuke Imamura (@nsfisis) + * nsfisis@gmail.com + * cctld: jp diff --git a/2-the-false-awakens/entry.clean.rb b/2-the-false-awakens/entry.clean.rb new file mode 100644 index 0000000..9a3ce0b --- /dev/null +++ b/2-the-false-awakens/entry.clean.rb @@ -0,0 +1,100 @@ +# A long time ago in a galaxy far, +# far away.... + + + + + + + +eval(%w{ + +def'false(p,s=[],v={}); + c=0; + while(c<p.size); + if(!(i=p[c]));false; + elsif"$"==i;s.push(s.last); + elsif"%"==i;s.pop; + elsif(28.chr)==i;s.push(s.pop,s.pop); + elsif"@"==i;s[-3],s[-2],s[-1]=s[-2],s[-1],s[-3]; + elsif"+"==i;s.push(s.pop+s.pop); + elsif"-"==i;s.push(-s.pop+s.pop); + elsif"*"==i;s.push(s.pop*s.pop); + elsif"/"==i;s.push(s.pop.then{s.pop/_1}); + elsif"_"==i;s.push(-s.pop); + elsif"&"==i;s.push(s.pop&s.pop); + elsif"|"==i;s.push(s.pop|s.pop); + elsif"~"==i;s.push(~s.pop); + elsif">"==i;s.push((s.pop<s.pop)?~0:0); + elsif"="==i;s.push((s.pop==s.pop)?~0:0); + elsif"!"==i;self.false(s.pop,s,v); + elsif"?"==i;s.pop.then{s.pop!=0&&self.false(_1,s,v)}; + elsif":"==i;v[s.pop]=s.pop; + elsif";"==i;s.push(v[s.pop]); + elsif","==i;print(s.pop.chr); + elsif"."==i;print(s.pop); + elsif/[0-9]/=~i;s.push(i.to_i); + elsif/[a-z]/=~i;s.push(i); + elsif"["==i; + q=c+=(b=1); + while(b!=0); + b+={"["=>1,"]"=>-1}[p[c]]||0; + c+=1; + end; + s.push(p[q...(c-=1)]); + elsif"#"==i; + a,b=s.pop,s.pop; + loop{; + self.false(b,s,v); + s.pop!=0&&break; + self.false(a,s,v); + }; + end; + c+=1; + end; +end; + + +class'String; + def&(other); + (self[1..]+other[1..]) + .chars + .map{(_1.upcase==_1)??1:?0} + .join + .to_i(2) + .chr; + end; + + def|(other); + (self||"")+(other||""); + end; + + def'method_missing(_); + self; + end; +end; + + +def'Object.const_missing(n); + const_set(n,n.to_s); +end; + +}.join.gsub("'"," ")) + + + + + EPISODE_VII + + THE_FALSE_AWAKENS + + + + +self.false(( + May.the.false.be.with.you; + TrUE&FaLsE|TrUe&FaLse|TrUe&FAlSe|TrUE&FalSE|TrUe&FAlSe|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUE&FAlsE|TrUe&FAlSE|TrUe&FALse| + TrUE&FaLSE|TrUe&FAlSE|TrUe&FALse|TrUE&FalSe|TrUe&FALsE|TrUe&FALse|TrUE&FAlse|TrUe&FALsE|TrUe&FALse|TrUe&FALse|TrUE&FaLse|TrUE&FAlse| + TrUe&FAlSe|TrUe&FALse|TrUE&FaLsE|TrUE&FalSe|TrUE&False|TrUE&FalSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUE&FalSe|TrUE&FaLsE| + TrUe&FAlSe|TrUe&FALse|false +)) diff --git a/2-the-false-awakens/entry.rb b/2-the-false-awakens/entry.rb new file mode 100644 index 0000000..199d42a --- /dev/null +++ b/2-the-false-awakens/entry.rb @@ -0,0 +1,57 @@ +# A long time ago in a galaxy far, +# far away.... + + + + + + + +eval(%w{def'false(p,s=[],v={});c=0;while(c<p.size);if( !(i=p[c]));false;e lsif"$"==i;s. push (s.l +ast);elsif"%"==i;s.pop;elsif(28.chr)==i;s.push(s.pop,s.p op);elsif"@"==i;s[ -3],s[-2],s[-1]=s [-2] ,s[- + 1],s [-3] ;els if"+ "==i ;s.p ush( s.po + p+s. pop) ;el sif" -"== i;s. push (-s. + pop+ s.po p); elsi f"*" ==i; s.pu sh(s + .pop *s.p op); elsi f"/" ==i; s.pu + sh(s .pop.then{s.pop/_1});e lsif "_"= =i;s.push + (-s. pop);elsif"&"==i;s.pu sh(s .pop &s.pop);el + sif" |"== i;s. push (s.p op|s .pop) + ;els if"~ "==i ;s.p ush( ~s.p op); elsi + f">" ==i; s.pu sh(( s.po p<s. pop) ?~0: + 0);e lsif "="= =i;s .pus h((s .pop ==s. + pop) ?~0: 0);elsif" !"==i;self.false(s .pop,s,v);elsif"? "==i ;s.pop.then{s.pop!=0& + &sel f.fa lse(_1, s,v)};elsif":"==i; v[s.pop]=s.po p;el sif";"==i;s.push(v[ + + +s.pop]);elsif","==i;print(s.pop.chr) ;elsif"."==i;p rint(s.pop);elsi f/[0-9]/=~i;s.push(i.to_i);elsif/[a-z]/=~i;s +.push(i);elsif"["==i;q=c+=(b=1);while(b !=0);b+={"["=>1,"] "=>-1}[p[c]]||0;c+= 1;end;s.push(p[q...(c-=1)]);elsif"#"==i;a,b=s.p + op,s .pop ;loo p{;s elf. + fals e(b ,s, v);s .pop + !=0& &br eak ;sel f.fa + lse( a,s ,v) ;};e nd;c + +=1;e nd; end ;clas s'Str + ing;d ef& (ot her); (self + [1.. ]+o the r[1. .]). + char s.m ap{ (_1. upca + se== _1) ??1 :?0} .joi + n.to _i(2 ).ch r;en d;de + f|(other);(self||"" )+(other||"");end; def'method_missing(_);self;end;end;def'Obj + ect.const_missin g(n);const_set (n,n.to_s);end}.join.gsub("'"," ")) + + + + + EPISODE_VII + + THE_FALSE_AWAKENS + + + + +self.false(( + May.the.false.be.with.you; + TrUE&FaLsE|TrUe&FaLse|TrUe&FAlSe|TrUE&FalSE|TrUe&FAlSe|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUE&FAlsE|TrUe&FAlSE|TrUe&FALse| + TrUE&FaLSE|TrUe&FAlSE|TrUe&FALse|TrUE&FalSe|TrUe&FALsE|TrUe&FALse|TrUE&FAlse|TrUe&FALsE|TrUe&FALse|TrUe&FALse|TrUE&FaLse|TrUE&FAlse| + TrUe&FAlSe|TrUe&FALse|TrUE&FaLsE|TrUE&FalSe|TrUE&False|TrUE&FalSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUE&FalSe|TrUE&FaLsE| + TrUe&FAlSe|TrUe&FALse|false +)) diff --git a/2-the-false-awakens/remarks.markdown b/2-the-false-awakens/remarks.markdown new file mode 100644 index 0000000..7f072a9 --- /dev/null +++ b/2-the-false-awakens/remarks.markdown @@ -0,0 +1,248 @@ +# Episode VII: The False Awakens + +> A long time ago in a galaxy far, +> far away.... + + + + +## Remarks + +Just run it with: + +``` +$ ruby entry.rb +``` + +It will output "TRICK 2025". + +It has been tested under the following environment: + +``` +$ ruby --version +ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux] +``` + + + +## Description + +The program consists of two parts: + +* an interpreter of a subset of [FALSE esolang](https://esolangs.org/wiki/FALSE) and +* an obfuscated FALSE source code. + +### FALSE interpreter + +The interpreter part is embeeded into an ASCII art, "TRICK 2025" shaped like the Star Wars logo. +For more readable version, see `entry.clean.rb`. + +### FALSE source code + +The FALSE source code is encoded to the following expression: + +``` + TrUE&FaLsE|TrUe&FaLse|TrUe&FAlSe|TrUE&FalSE|TrUe&FAlSe|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUE&FAlsE|TrUe&FAlSE|TrUe&FALse| + TrUE&FaLsE|TrUe&FAlSE|TrUe&FALse|TrUE&FalSe|TrUe&FALsE|TrUe&FALse|TrUE&FAlse|TrUe&FALsE|TrUe&FALse|TrUe&FALse|TrUE&FaLse|TrUE&FAlse| + TrUe&FAlSe|TrUe&FALse|TrUE&FaLsE|TrUE&FalSe|TrUE&False|TrUE&FalSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUE&FalSe|TrUE&FaLsE| + TrUe&FAlSe|TrUe&FALse|false +``` + +Decoded version: + +``` +5$*3*$$$$9+,7+,2-,8-,,48*,5202....25*, +``` + +FALSE is a simple stack-based esolang. For instance, + +* `5` pushes 5: `[5]` +* `$` duplicates the top: `[5 5]` +* `*` pushes the product: `[25]` +* `3` pushes 3: `[25 3]` +* `*` pushes the product: `[75]` +* `$$$$` duplicates the top 4 times: `[75 75 75 75 75]` +* `9` pushes 9: `[75 75 75 75 75 9]` +* `+` pushes the sum: `[75 75 75 75 84]` +* `,` writes the character: `[75 75 75 75]` (output `T`) +* `7` pushes 9: `[75 75 75 75 7]` +* `+` pushes the sum: `[75 75 75 82]` +* `,` writes the character: `[75 75 75]` (output `R`) +* ... + + +The source code is full of Star Wars references and homages. + + +``` +# A long time ago in a galaxy far, +# far away.... +``` + +This is the iconic Star Wars opening phrase. + +``` +# (inside the eval'ed code) + + while(c<p.size); + if(!(i=p[c]));false; + elsif"$"==i;s.push(s.last); + elsif"%"==i;s.pop; + ... +``` + +All comparison operations used in the program are written in the so-called "Yoda notation" (placing constants on the left hand side), referencing the Jedi Master Yoda. + + +``` + EPISODE_VII + + THE_FALSE_AWAKENS +``` + +This parodies the Star Wars Episode VII subtitle, "The Force Awakens." +"Force" refers to a supernatural power in Star Wars, but for our program, "false" has awakened instead because we used many `false`s. + + +``` + May.the.false.be.with.you; +``` + +This is a twist on one of the most famous Star Wars lines, "May the Force be with you." + + + + +## Internals + +### FALSE interpreter + +The interepreter is implemented as a method named `false`. In Ruby, you can use keywords as method names like this. It cannot be invoked directly, but you can call such a method via explicit receiver:`self.false()` + + +### Encoding the FALSE program + +The FALSE program is obfuscated like this: + +``` + TrUE&FaLsE|TrUe&FaLse|TrUe&FAlSe|TrUE&FalSE|TrUe&FAlSe|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUe&FaLse|TrUE&FAlsE|TrUe&FAlSE|TrUe&FALse| + TrUE&FaLsE|TrUe&FAlSE|TrUe&FALse|TrUE&FalSe|TrUe&FALsE|TrUe&FALse|TrUE&FAlse|TrUe&FALsE|TrUe&FALse|TrUe&FALse|TrUE&FaLse|TrUE&FAlse| + TrUe&FAlSe|TrUe&FALse|TrUE&FaLsE|TrUE&FalSe|TrUE&False|TrUE&FalSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUe&FALSe|TrUE&FalSe|TrUE&FaLsE| + TrUe&FAlSe|TrUe&FALse|false +``` + +Each segment separated by `|` represents one instruction. + +* `TrUE&FaLsE` => `5` +* `TrUe&FaLse` => `$` +* `TrUe&FAlSe` => `*` +* ... + +This is achieved by defining `Object.const_missing`, `String#&`, and `String#|`. + +First, our `const_missing `dynamically defines constants like `TrUE`: + +``` +# (inside the eval'ed code) + +def Object.const_missing(n); + const_set(n,n.to_s); +end; +``` + +With that, constant `TrUE` is resolved to string `"TrUE"`. + +Second, such strings are concatenated with `&` with special decoding: + +``` +# (inside the eval'ed code) + +class'String; + def&(other); + (self[1..]+other[1..]) + .chars + .map{(_1.upcase==_1)??1:?0} + .join + .to_i(2) + .chr; + end; +end; +``` + +For `TrUE & FaLsE`, + +``` + (self[1..]+other[1..]) # => "rUEaLsE" + .chars # => ["r","U","E","a","L","s","E"] + .map{(_1.upcase==_1)??1:?0} # => ["0","1","1","0","1","0","1"] + .join # => "0110101" + .to_i(2) # => 53 + .chr; # => "5" +``` + +Finally, each FALSE instruction is concatenated by `|` operator: + +``` +# (inside the eval'ed code) + +class'String; + def|(other); + (self||"")+(other||""); + end; +end; +``` + + +# Misc. + +``` + EPISODE_VII + + THE_FALSE_AWAKENS +``` + +This code is equivalent to this: + +``` + "EPISODE_VII" + + "THE_FALSE_AWAKENS" +``` + +It does nothing. + +``` + May.the.false.be.with.you; +``` + +`May` is resolved to string `"May"` and the rest method chain is dispatched to `String#method_missing` defined here: + +``` +# (inside the eval'ed code) + +class'String; + def'method_missing(_); + self; + end; +end; +``` + +It does nothing too. + + + + + +## Limitations + +Our FALSE interpreter does not support the following instructions: + +* `'c`: literal character "c" +* `ø`: pick +* `^`: input +* `"string"`: output "string" +* `ß`: flush the inout/output buffer. +* `{...}`: comments +* `\``: compile + +Also, only one-digit numeric literals are supported, so `123` is interpreted as pushing `1`, `2` and `3` separately. |
