167
\$\begingroup\$

A truth-machine (credits goes to this guy for coming up with it) is a very simple program designed to demonstrate the I/O and control flow of a language. Here's what a truth-machine does:

  • Gets a number (either 0 or 1) from STDIN.

  • If that number is 0, print out 0 and terminate.

  • If that number is 1, print out 1 forever.

Challenge

Write a truth-machine as described above in your language of choice. The truth-machine must be a full program that follows these rules:

  • take input from STDIN or an acceptable alternative
    • If your language cannot take input from STDIN, it may take input from a hardcoded variable or suitable equivalent in the program
  • must output to STDOUT or an acceptable alternative
    • If your language is incapable of outputting the characters 0 or 1, byte or unary I/O is acceptable.
  • when the input is 1, it must continually print 1s and only stop if the program is killed or runs out of memory
  • the output must only be either a 0 followed by either one or no newline or space, or infinite 1s with each 1 followed by either one or no newline or space. No other output can be generated, except constant output of your language's interpreter that cannot be suppressed (such as a greeting, ANSI color codes or indentation). Your usage of newlines or spaces must be consistent: for example, if you choose to output 1 with a newline after it all 1s must have a newline after them.

  • if and only if your language cannot possibly terminate on an input of 0 it is acceptable for the code to enter an infinite loop in which nothing is outputted.

Since this is a catalog, languages created after this challenge are allowed to compete. Note that there must be an interpreter so the submission can be tested. It is allowed (and even encouraged) to write this interpreter yourself for a previously unimplemented language. Other than that, all the standard rules of must be obeyed. Submissions in most languages will be scored in bytes in an appropriate preexisting encoding (usually UTF-8).

Catalog

The Stack Snippet at the bottom of this post generates the catalog from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

<style>body { text-align: left !important} #answer-list { padding: 10px; width: 290px; float: left; } #language-list { padding: 10px; width: 320px; float: left; } table thead { font-weight: bold; } table td { padding: 5px; }</style><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table><script>var QUESTION_ID = 62732; var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe"; var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk"; var OVERRIDE_USER = 12012; var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page; function answersUrl(index) { return "https://api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER; } function commentUrl(index, answers) { return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER; } function getAnswers() { jQuery.ajax({ url: answersUrl(answer_page++), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { answers.push.apply(answers, data.items); answers_hash = []; answer_ids = []; data.items.forEach(function(a) { a.comments = []; var id = +a.share_link.match(/\d+/); answer_ids.push(id); answers_hash[id] = a; }); if (!data.has_more) more_answers = false; comment_page = 1; getComments(); } }); } function getComments() { jQuery.ajax({ url: commentUrl(comment_page++, answer_ids), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { data.items.forEach(function(c) { if (c.owner.user_id === OVERRIDE_USER) answers_hash[c.post_id].comments.push(c); }); if (data.has_more) getComments(); else if (more_answers) getAnswers(); else process(); } }); } getAnswers(); var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/; var OVERRIDE_REG = /^Override\s*header:\s*/i; function getAuthorName(a) { return a.owner.display_name; } function process() { var valid = []; answers.forEach(function(a) { var body = a.body; a.comments.forEach(function(c) { if(OVERRIDE_REG.test(c.body)) body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>'; }); var match = body.match(SCORE_REG); if (match) valid.push({ user: getAuthorName(a), size: +match[2], language: match[1], link: a.share_link, }); else console.log(body); }); valid.sort(function (a, b) { var aB = a.size, bB = b.size; return aB - bB }); var languages = {}; var place = 1; var lastSize = null; var lastPlace = 1; valid.forEach(function (a) { if (a.size != lastSize) lastPlace = place; lastSize = a.size; ++place; var answer = jQuery("#answer-template").html(); answer = answer.replace("{{PLACE}}", lastPlace + ".") .replace("{{NAME}}", a.user) .replace("{{LANGUAGE}}", a.language) .replace("{{SIZE}}", a.size) .replace("{{LINK}}", a.link); answer = jQuery(answer); jQuery("#answers").append(answer); var lang = a.language; lang = jQuery('<a>'+lang+'</a>').text(); languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang.toLowerCase(), user: a.user, size: a.size, link: a.link}; }); var langs = []; for (var lang in languages) if (languages.hasOwnProperty(lang)) langs.push(languages[lang]); langs.sort(function (a, b) { if (a.lang_raw > b.lang_raw) return 1; if (a.lang_raw < b.lang_raw) return -1; return 0; }); for (var i = 0; i < langs.length; ++i) { var language = jQuery("#language-template").html(); var lang = langs[i]; language = language.replace("{{LANGUAGE}}", lang.lang) .replace("{{NAME}}", lang.user) .replace("{{SIZE}}", lang.size) .replace("{{LINK}}", lang.link); language = jQuery(language); jQuery("#languages").append(language); } }</script>

\$\endgroup\$
18
  • 3
    \$\begingroup\$ Assuming any behaviour is fine for all invalid inputs? \$\endgroup\$
    – Cruncher
    Nov 3, 2015 at 17:33
  • 3
    \$\begingroup\$ @Cruncher Yes, the only inputs you should expect to get are 0 and 1. \$\endgroup\$ Nov 3, 2015 at 17:38
  • 5
    \$\begingroup\$ Catalog is borked. \$\endgroup\$ Nov 6, 2015 at 15:18
  • 2
    \$\begingroup\$ Catalog appears to consider Bf and bf to be different languages. \$\endgroup\$ Nov 10, 2015 at 1:13
  • 1
    \$\begingroup\$ Is one allowed to print an infinite number of 1s? That is, not print out 1s forever, but print out an infinite list of 1s all at once? This would be theoretically demonstrated, but the language has no notion of printing more than once. It just generates an output. So is it okay if it runs indefinitely, but would print infinite 1s given infinite time (to finish executing)? \$\endgroup\$
    – AviFS
    Apr 26, 2020 at 1:42

458 Answers 458

1
5 6
7
8 9
16
2
\$\begingroup\$

MATL, 4 bytes

`GtD

Relevant MATL features *

To explain the code, the following MATL features need to be presented first.

  • ` ...] is a "do ...while" loop. The top of the stack is consumed at the end of each iteration, and used to decide whether to go on with a new iteration or not. The last ] can be omitted if it's at the end of the program (loops are implicitly closed).
  • G works as follows:
    • When there has been no user-input it does nothing;
    • When there has been one user-input it pushes it onto the stack
    • When there has been more than one user-input it takes a numeric argrument and pushes one of those user-inputs onto the stack
  • t by default duplicates the top element of the stack
  • D by default displays the top element of the stack, and consumes it.
  • If a function requires more inputs than currently are in the stack, user-input is implicitly triggered. The entered elements are placed below the current bottom of the stack.

Code explanation

` enters the loop. At the first iteration, G does nothing. t implicitly asks for user input and duplicates it. D displays and consumes the duplicate, leaving the original input on the stack. If this input is 0 the loop is exited and the program finishes (a single 0 has been displayed). If the input is 1, control goes to the beginning of the loop again. Now G pastes the input, t duplicates it, D displays and consumes that duplicate, and again there's a 1 to be used as loop condition, so the loop begins again, indefinitely (an infinite number of 1 is displayed).


* at the time of writing. The behaviour of G has changed since then: G now triggers implicit input when there has been no user-input yet. However, this doesn't affect the code, which works the same. The only difference is that in the first iteration the implicit input is now triggered by G, not by t.

\$\endgroup\$
2
\$\begingroup\$

Pepe, 15 bytes

REeErEErReEEree

Try it online!

Explanation:

REeErEErReEEree  # Full program
REeE             # Take input as number
    rEE          # Create label 0
       rReEE     # Output number -r (preserve)
            ree  # Goto label 0 if [input] != 0
\$\endgroup\$
2
\$\begingroup\$

Self-modifying Brainfuck, 30 19 bytes

Similar method to my BF answer. Input and print, subtract the 0 (the source's last byte) from the input, so cell is 0 or 1. Loop printing if input cell is 1. Tested on my Python interpreter.

,.<[->-<]>[<<.>>]10

You can also run it on TIO.

\$\endgroup\$
2
\$\begingroup\$

Flobnar, 10 bytes

<1._
|@&
0

Try it online!

\$\endgroup\$
2
\$\begingroup\$

AlgiX with -x, 3 bytes

[.]

Explanation

AlgiX takes each character of input (converts it to charcode if it's not a digit) and runs the entire code for each value, initializing the accumulator to that value each run.

In this case, there's only 1 input, a 1 or a 0, so the code runs once.

[.] - Implicit a = input
[   - If a == 0, skip to ]
 .  - Print value of a
  ] - If a != 0, jump back to [
    - Implicit output value of a

Normally, the implicit output after each run would output a as a character, however the -x flag overrides that and outputs its value instead.

\$\endgroup\$
2
\$\begingroup\$

VSL, 36 32 bytes

fn main(){do{print(i)}while i>0}

This is probably familiar to anyone who knows any C-esque language but this takes input using a global variable i.

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Befunge, 4 bytes

&:.%

Try it online!

Please note: this answer is no longer valid with this particular interpreter. At the time of writing, the interpreter used had a quirk where trying to read more integers when there weren’t any would return the last integer. I believe that this was “fixed” in some interpreter update. (Thanks to @osuka_ for realizing that this answer no longer works)

Explanation:

&       Take number input
 :.     Duplicate and print input
   %    Mods the second from-the-top with the top number in the stack
        This means that if the top is 1, it will yield 0 % 1 = 0,
        But if it is a 0, it errors out and stops execution because you are
        trying to divide by 0
        
&       The program wraps back around if it didn't error, and the & takes
        the last number in the input if it has already taken them all, yielding
        the original 1 or 0

Coincidentally, this doesn't also work for /, because it strangely asks you what you want the answer to be.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ The modulo trick is really clever. I love it. \$\endgroup\$
    – IQuick 143
    Apr 30, 2019 at 14:15
  • 1
    \$\begingroup\$ This doesn't work - it prints -1 instead of 1 after the first time. \$\endgroup\$
    – osuka_
    Aug 26, 2019 at 18:56
  • \$\begingroup\$ @osuka_ I think it’s due to the interpreter being updated, unfortunately. I remember it used to be that reading an end of feed with & would give the last integer again (which would make this print 1). I think they changed it so it gives -1 on an EOF instead. Thanks for letting me know \$\endgroup\$ Aug 26, 2019 at 19:19
  • 1
    \$\begingroup\$ @MildlyMilquetoast No worries - The reason I stumbled upon this is that I was looking for other befunge answers, to see if anyone had already posted one identical (or very similar) to one I just wrote. I love the mod trick! \$\endgroup\$
    – osuka_
    Aug 26, 2019 at 19:30
  • \$\begingroup\$ This can be fixed by adding two !s after the & \$\endgroup\$
    – Jo King
    Aug 27, 2019 at 3:48
2
\$\begingroup\$

Verbosity v2, 290 bytes

IncludeTypePackage<OutputSystem>
IncludeTypePackage<InputSystem>
IncludeStructurePackage<Loops>
input=InputSystem:NewInput<DEFAULT>
outpu=OutputSystem:NewOutput<DEFAULT>
condi=InputSystem:ReadEvaluatedLineOfInput<input>
Loops:ConstructLoop<Do;condi>[OutputSystem:DisplayAsText<outpu;condi>]

Try it online!

First non-trivial Verbosity v2 answer! Although how it works is very trivial, as you can see from the ungolfed version:

IncludeTypePackage<OutputSystem>
IncludeTypePackage<InputSystem>
IncludeStructurePackage<Loops>

input  = InputSystem:NewInput<DEFAULT>
output = OutputSystem:NewOutput<DEFAULT>

condition = InputSystem:ReadEvaluatedLineOfInput<input>

Loops:ConstructLoop<Do; condition> [
	OutputSystem:DisplayAsText<output; condition>
]

Try it online!

Simply enter a do...while loop, which prints the input at least once, then terminates if it's falsey (i.e. 0).

\$\endgroup\$
2
\$\begingroup\$

tq, 3 bytes

?(?

Explanation

?,   # Take an input
  (? # Extend the array while
     # the input is not false
\$\endgroup\$
2
\$\begingroup\$

AWK, 17 bytes

{while($0)print}1

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Same effect, with 17 bytes, using a for statement instead of a while: {for(;$0;)print}1, or even $0{for(;;)print}1 \$\endgroup\$
    – PauloVlw
    May 18, 2021 at 0:34
2
\$\begingroup\$

MAWP v1.1, 18 14 bytes

@A{1A:.}1M[!:]

-4 bytes with integer input.

Try it!

\$\endgroup\$
2
  • \$\begingroup\$ Nice answer! You should specify it is MAWP 0.1 (0.0 is not allowed, by the way, because it is not a programming langauge at all). \$\endgroup\$
    – null
    Aug 5, 2020 at 13:51
  • \$\begingroup\$ OH, sorry about that, I just used the answer generator here: 8dion8.github.io \$\endgroup\$
    – Razetime
    Aug 5, 2020 at 15:18
2
\$\begingroup\$

MarioLang, 25 bytes

   >:<
   "==
 ;[!:
===#=
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Why is this non-competing? Just FYI: "Non-competing" generally means "Uses language features that are newer than the challenge" or "Used to be valid but the rules changed". \$\endgroup\$
    – DJMcMayhem
    Jun 30, 2016 at 15:16
  • \$\begingroup\$ I mean that I am not using this code to win this challenge. but upvotes are free! \$\endgroup\$
    – user54200
    Jul 1, 2016 at 5:32
  • 1
    \$\begingroup\$ That's not what non-competing means here. Also, this answer predates yours and is a lot shorter. \$\endgroup\$
    – Dennis
    Jul 22, 2016 at 19:57
  • \$\begingroup\$ @Dennis You're correct. \$\endgroup\$
    – user54200
    Jul 23, 2016 at 2:30
  • \$\begingroup\$ @DrGreenEggsandIronMan I was just aware that there was a shorter one and said "non-competing". \$\endgroup\$
    – user54200
    Jul 23, 2016 at 2:31
2
\$\begingroup\$

NDBall, 57 chars, 8 cells in 2 dimentions

(0)>0
(1)%
(2)Y[1,>0,>1]
(3)P
(4)E
(2,1)>1
(2,2)P
(2,3)<1

Visual representation of code (hand made by me)

enter image description here

Checked in NDBallSim V1.0.1

\$\endgroup\$
2
\$\begingroup\$

05AB1E, 3 bytes

i[?

Try it online!

i[?  # full program
i    # if...
     # implicit input...
i    # is 1...
  ?  # output...
     # implicit output...
  ?  # without trailing newline...
 [   # forever
     # implicit end loop
     # implicit end if
     # implicit output
\$\endgroup\$
2
\$\begingroup\$

Python 3, 35 bytes

n=input()
while 1:print(n);0/int(n)
\$\endgroup\$
4
  • \$\begingroup\$ Welcome to the site! Nice first answer. \$\endgroup\$ Dec 1, 2020 at 13:31
  • \$\begingroup\$ Also, golfing with suggested edits is usually not recommended, I'll leave a comment on xnor's answer for you. \$\endgroup\$ Dec 1, 2020 at 13:33
  • \$\begingroup\$ @RedwolfPrograms Thanks for the tip 😅 I'll pay more attention next time \$\endgroup\$ Dec 1, 2020 at 13:40
  • \$\begingroup\$ No problem, it happens a lot. Hopefully you'll get to 50 rep soon! \$\endgroup\$ Dec 1, 2020 at 13:44
2
\$\begingroup\$

convey, 10 bytes

{,!"}
 >"^

Try it online!

There's a few ten-byters i've found, but I can't see any way to get lower. I was thinking of this. but unfortunately that doesn't parse.

\$\endgroup\$
2
\$\begingroup\$

, 6 bytes

;@=.$#

Unwrapped:

  ;
@ = . $
  #

The IP starts at the top cell. ; takes the input as a numeric value. The IP then falls to =, printing the value. It hits ground (#) and starts moving to the right. . is a no-op. $ ignores the next command if the value is not zero. The IP wraps around to @, which terminates the program. The program repeats from = if it hasn't terminated.

\$\endgroup\$
2
\$\begingroup\$

Built-out, 5 bytes

truth

Yay, built-ins! ...just kidding.

Before running: push input to stack 2

truth

t      - not last 't': swap stacks 1 and 2
 r     - convert character (1-9) at top of stack 1 to integer
  u    - toggle EOF loop if top item of stack 1 is falsy (0)
    h  - duplicate top of stack 1
       - implicit: pop item of stack 1 if not empty, then go to previous 't' if stack 1 is still not empty AND 'u' did not toggle it off, terminate otherwise
   t   - last 't': return here if stack 1 is not empty

Try it online! (fork the project)

\$\endgroup\$
2
\$\begingroup\$

Grok, 10 bytes

:}1j
z}zhq

Explanation:

:}      # If input is 0, goes down and to the left, outputs 0, 
z}  q     wraps to the right, and terminates.

:}1j    # If input is non-zero, goes to the right, pushes 1,
 }zh      prints 1, and loops indefinitely.
\$\endgroup\$
2
\$\begingroup\$

Stax, 4 bytes

Wq|c

Run and debug it

W    - loop over rest of program forever
 q   - print without popping, with no newline
  |c - exit if value at the top of stack is truthy without popping
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to the site, and nice first answer! \$\endgroup\$ May 21, 2021 at 21:37
2
\$\begingroup\$

2D Deadfish, 7 bytes

(o^)>o<

It is a new 2D esolang based on Deadfish~ I made recently. Read more on it in the link in header.

Explanation

IP starts at the beginning with direction right. Statements inside parentheses is only executed if accumulator is 0. And input is set to the accumulator, or else 0.

So if you give input 0,

  • Parentheses block will start
  • o will output accumulator (which is 0)
  • ^ will change direction to up
  • It will eventually hit EOF token
  • And terminate soon!

And for input 1,

  • Skip the parentheses and jump to >
  • > changes direction to right (It keeps moving right)
  • o outputs accumulator (which is 1)
  • < changes direction to left (back)
  • o outputs 1 again
  • > changes direction to right
  • IP dances and repeats outputting 1

How to run it?

No online interpreter for now. but coming soon.

Until then clone the repo, and run interpreter.py. It will prompt you for the program first. When done typing program, hit CTRL+D (linux) or CTRL+Z (windows). And provide your input (if you don't want to give keep it blank) and hit enter. The program will start to run.

\$\endgroup\$
2
\$\begingroup\$

Piet, 12 codels

Codel size 16:

3x4 codel piet truth machine

Instructions:

INN
DUP (start)
DUP
OUTN
PTR (back to start if 1; continue if 0)
POP

It has the following behavior for other values:

  • if n % 4 == 1, print n forever
  • else, print n once and terminate

if n % 4 == 2, there will be a stack underflow error, as the code path is as follows:

INN
DUP 
DUP
OUTN
PTR
SWITCH (empties the stack)
PTR (error)
POP (error)
\$\endgroup\$
2
\$\begingroup\$

Mascarpone, 18.125 bytes

['1.:!]v*['0.]v*1[:!]v*'1<,>!

Try It Online!

I'm surprised to see so few Mascarpone answers even on the big questions like this. It's a shame, it's such a beautiful language even if it is a bit of a tarpit.

\$\endgroup\$
2
\$\begingroup\$

Perl -p, with the following restrictions ppencode, 15 bytes.

  • Use only keywords with lowercase alphabets only
  • Separate each of them with just a space
print while sin

Try it online!

How it works

  • sin(0) is zero
  • sin(1) is not zero
  • -p is for implicit I/O for line by line

Alternatives

sin can be replaced with one of following keywords:

abs int oct hex
\$\endgroup\$
3
  • \$\begingroup\$ can you do print while-$_? \$\endgroup\$
    – Jo King
    Aug 19, 2021 at 4:50
  • \$\begingroup\$ @JoKing if I had changed the restriction. \$\endgroup\$
    – user100411
    Aug 19, 2021 at 11:51
  • \$\begingroup\$ Oh, i don't know how I missed that oops \$\endgroup\$
    – Jo King
    Aug 19, 2021 at 12:39
2
\$\begingroup\$

Clam, 11 8 bytes

p=QrwQpQ

Try it online!

-3 bytes thanks to the Q global variable

Storing variables is a tad verbose in Clam...

Explanation

p=QrwQpQ
p            Print..
 =             Assignment..
  Q              Global variable Q
   r             Read next line of STDIN (automatically parsed to int if possible)
    w        While..
     Q         Q is truthy
      pQ         Print Q

Resulting JS code:

console.log(Q = arguments[0]);
while(Q) {
    console.log(Q);
}
\$\endgroup\$
2
\$\begingroup\$

Pure CPython 3.10 bytecode, 6 bytes

"Pure" means no constants and no names are allowed. As a result, the only method of input is by starting with values on the stack.

...and Python bytecode's only way to jump backwards (and therefore the only way to loop) uses "absolute" addressing, so my code assumes it is placed starting at instruction offset 3 (byte offset 6).

Hex of code: 04 00 46 00 70 03

Disassembly of code:

    >>    6 DUP_TOP
          8 PRINT_EXPR
         10 JUMP_IF_TRUE_OR_POP      3 (to 6)

Takes an integer on the stack. The easiest way to put 0 or 1 on the stack is:

          0 LOAD_ASSERTION_ERROR
          2 BUILD_TUPLE              X
          4 GET_LEN

Change X to 0 or 1. In hex, this is 4a 00 66 00 1e 00 (for 1) or 4a 00 66 01 1e 00 (for 0).

This will crash the interpreter for an input of 0 due to a buffer overflow. If this is not acceptable, add 2 bytes (append 53 00 (RETURN_VALUE)).

Attempt This Online! (0)

Attempt This Online! (1)


I'm going to use this opportunity to explain how CPython bytecode works. It's just an array of bytes, which are in opcode, oparg pairs.

For example, (hex) 01 02 03 04 is instruction_01(arg=02); instruction_03(arg=04).

The list of instructions is given in the documentation for the standard library dis module, although you sometimes need to dig about in Python's ceval.c to see exactly how they work.

In Python, bytecode is contained in a code object, which carries some metadata like source file lines, but the most important things are an array of constants (co_consts) and an array of names (co_names). In order to load a literal value, it must be loaded from co_consts; in order to lookup a global variable, its name must be in co_names. When I said I'm using "pure" bytecode, I mean that these arrays are both empty - so I can't use any literals (integers, strings, tuples, etc.), and I can't use any global variables, builtins, imports, or even look up any attributes. This allows an extremely minimal wrapper script (see the ATO link).

This leaves me with only PRINT_EXPR for output (or leaving a value on the stack), and no input at all other than taking a value already on the stack.

The truth machine is actually the easy part of this code, to be honest: it's essentially do { print x } while (x).

Loading an integer is a bit more involved: first I use LOAD_ASSERTION_ERROR to put a value on the stack. What value it is doesn't particularly matter, but this is one of only a few instructions I'm aware of that can load an object without any consts.

Then I use BUILD_TUPLE(1) to make the tuple (AssertionError,), and take its length with GET_LEN which is 1. To load 0 is a bit simpler: you only need

          0 BUILD_TUPLE              0
          2 GET_LEN

Although you can perfectly well leave the LOAD_ASSERTION_ERROR before that, to conveniently switch between loading 0 and 1.


Sidenote

GET_LEN is new in Python 3.10, so a historic method would have had to involve boolean <-> integer conversion, which is a bit more interesting IMO:

          0 LOAD_ASSERTION_ERROR
          2 DUP_TOP
          4 IS_OP                    0
          6 DUP_TOP
          8 BINARY_MULTIPLY
         10 PRINT_EXPR

This performs AssertionError is AssertionError, which is True. Then it does True * True to get the integer 1.

IS_OP(0) can be replaced with IS_OP(1) to do AssertionError is not AssertionError, which gives False, which gives 0.

\$\endgroup\$
2
\$\begingroup\$

Desmos, 33 bytes

n->ni+1,o->[1...n]0+i
i=0
o=0
n=0

The top line goes in a ticker, while the other lines are regular equations.

The input goes in variable i, while the output is shown in variable o.

Press the ticker (metronome icon) to start running the code.

Try It On Desmos!

Explanation

n->ni+1: If i=0, it becomes n->1, so n will always stay at 1. If i=1, it becomes n->n+1, so n will infinitely increment by 1.

o->[1...n]0+i: [1...n]0 creates a list of zeroes with length n. As shown with n->ni+1, if i=0, the length will always stay at 1; otherwise, it will keep increasing. +i simply converts the list of zeroes to a list of i's. So in summary, if i=0, then the list stays at length 1 and is populated with 0's. If i=1, then the list length is always increasing and is populated with 1's.

The rest of the code: It is simply to define the variables used in the actions above.

\$\endgroup\$
2
\$\begingroup\$

dotcomma, 8 bytes

[,].[.,]

Try it online!

Dotcomma is a language I recently invented, designed to do things in an interesting way with as few instructions as possible. In order to accomplish this, there are two operators (predictably . and ,) which can do entirely different things depending on context. This answer's explanation will be very introductory. To see some more complicated code, check out the examples in the page linked in the title.

This program is actually a pretty neat showcase of some of the more interesting features of dotcomma. You'll notice it's divides into two main parts, [,] and [.,], separated by a .. These are called blocks. Every block and operator has a return value.

The way dotcomma manages to do so many different things with each operator is by changing what they do based on what precedes and follows them. Take the , in the first block. Because it is at the start of a block, its return value will be a value taken from input. Because it is at the end of a block, it will also output this value and use it as the block's return value. Surprisingly compact for a language with four valid characters!

As for the first ., because it is preceded by a block, it will take the block's return value and use it as its own. It is followed by another block, so it will do one two things: if its return value is 0, the block will be skipped. Thus, only 0 will be outputted and the program will terminate.

However, if its return value is 1, the block will be looped. Within the block are two operators: .,. The . will have a return value of 1, as it follows the beginning of a block. The , will behave similarly to the first one, but instead of taking the number to be outputted from input, it will take it from the . (which will always be 1). The loop will run forever because the , will always set the looped block's return value to 1.

Hopefully this explanation isn't too confusing!

\$\endgroup\$
1
  • \$\begingroup\$ Why didn't I upvote this until now????? Every single Dotcomma answer needs an upvote. \$\endgroup\$
    – null
    Apr 15 at 13:36
2
\$\begingroup\$

tinylisp, 31 bytes

(d A(q((N)(i N(A(c 1(disp 1)))0

Defines a function A that takes the required input, as tinylisp has no concept of program input.

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You could if you so wanted replace all of the digits with N ;-) \$\endgroup\$
    – Neil
    Apr 22 at 14:38
2
\$\begingroup\$

PostScript, 36 bytes

.runstdin 0 eq{0 =}{{1 =}loop}ifelse

Probably needs to be run through ghostscript to get the .runstdin operator.

\$\endgroup\$
1
5 6
7
8 9
16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.