19
\$\begingroup\$

Sandbox

Your challenge is to write a program that when first run, will do one of the actions below at random with equal chances of both:

  • A cat program

    • A standard cat program: read everything from STDIN and put it on STDOUT (or your language's closest equivalent).
  • Do nothing and halt

    • This shouldn't output anything.

The behaviour is permanent - once the program chooses between the two options, it should do that no matter how much times you run the script. It's fine if this resets when you reboot.

Please provide an explanation on how to reset the program (which file to delete for example)

Standard loopholes are forbidden.

This is a , so the shortest code (in bytes or equivalent) wins.

\$\endgroup\$
9

13 Answers 13

9
\$\begingroup\$

Python 3, 94 bytes

from random import*
s=randint(0,1)*"print(open(0).read())"
open(__file__,"w").write(s)
exec(s)

Try it online!

Picks one of or print(open(0).read()) and replaces the contents of the file with it. Then, executes that code once.

To reset it, you will have to copy-paste this code into the file again, since it overwrites the file itself. This perseveres so long as the file exists and is not modified, so it is remembered through reboots and even if you move the file to another computer.

-5 bytes thanks to Jonathan Allan
(Also -5 thanks to Jakque by using choice(["print(open(0).read())",""]) instead of randint(0,1)*"print(open(0).read())" - both are excellent golfs; I just chose the first one.)

\$\endgroup\$
3
  • 2
    \$\begingroup\$ s="print(open(0).read())"*randint(0,1) saves five. \$\endgroup\$ Dec 27, 2021 at 20:58
  • 2
    \$\begingroup\$ s=choice(["print(open(0).read())",""]) also works for -5 \$\endgroup\$
    – Jakque
    Dec 28, 2021 at 0:58
  • \$\begingroup\$ You can use import os;s=ord(os.urandom(1))%2*... to save a couple more bytes. \$\endgroup\$
    – Yonatan N
    Dec 28, 2021 at 22:45
4
\$\begingroup\$

R, 37 36 bytes

Edit: -1 byte thanks to Giuseppe

{q=rt(1,1)<0;function(x)if(q)cat(x)}

Try it online!

Function that acts randomly as cat or no-op on first call, and then stays with this behaviour forever (or until deleted).


R, 83 bytes

if(!F)write(paste("F=",F<-sample(1:2,1)),".Rprofile");if(F<2)show(scan("stdin",""))

Try it online!

Full program: saves state into ".Rprofile" file in directory from which R or Rscript is launched: delete this to reset program behaviour.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ rt(1,1) should be a byte shorter? \$\endgroup\$
    – Giuseppe
    Dec 27, 2021 at 23:29
4
\$\begingroup\$

Haskell, 89 bytes

This method uses no special files. In fact it doesn't store data anywhere.

To set up your randomize_va_space should be set to zero (linux).

You can check this with:

sysctl -anr "e_v"

I won't tell you how to set it to 0 since in general this should not be set to 0, and setting it to 0 represents a possible security risk. Don't play with your kernel unless you know what you are doing or have nothing to lose on the device.

import Unsafe.Coerce
main=([[interact id],[pure()]]>>=([0..7]>>))!!mod(unsafeCoerce(+))16

Try it online!

TIO is stuck on cat and I have no way to reset it. You can switch the + to a : to see a version that is stuck on the noop.

To reset it locally it should be enough to set the randomize_va_space to 2 run the program once and then set it back to 0.

Explanation

More detailed explanation here

In Haskell, all complex objects including functions are internally represented as a pointer. This is a number in binary that "points" to a specific location in memory. This is because we want to pass these values by reference, since copying the whole thing is expensive, and since Haskell disallows mutation we can with no problem.

However simple objects like ints are passed by value since they are so small that copying them is about as expensive as copying a pointer would be. unsafeCoerce is a super unsafe function which just takes the raw bytes from one object and reinterprets it as the raw bytes for another type.

So if we use unsafeCoerce from a function to an Int, the resulting Int is just the value of the pointer to the object. And the value of that simple object is dependent only on where the complex object is located not anything about what it is.

When randomize_va_space is on, this means the value of unsafeCoerce(+) is a random multiple of 8. However when it's off, it is fixed to one value which depends on some factors about the machine.

\$\endgroup\$
1
  • \$\begingroup\$ Grats on breaking TIO \$\endgroup\$
    – emanresu A
    Dec 28, 2021 at 18:57
4
\$\begingroup\$

Bash + coreutils, 64 bytes

awk -va=$(awk '!/E/{$0=(systime()-$1)%88}1' /proc/uptime) 'a<44'

Try it online!

Here's how it works.

AWK is called with a variable a which is a floating point number greater than or equal to 0 and less than 88. So it uses the a<44 test to get a 50/50 chance to decide what action to take. If that evaluates as true, then it prints STDIN to STDOUT. If it's false, it silently consumes STDIN.

The value of a is set by the inner AWK call. That logic read the first numeric value in /proc/uptime, which is the number of seconds since the system was booted. The it subtracts that "uptime" from the current date/time to get the boot time of the OS. Then it computes a modulo of 88 seconds to deal with the (very annoying) fact that the calculations aren't consistent at the seconds level.

Essentially it's using the boot time of the OS to decide whether or not to "cat" or "discard" the input. So it will make the same decision each time it's run until the system is rebooted.

\$\endgroup\$
3
\$\begingroup\$

Zsh, 29 21 bytes

X=$[RANDOM%2]
f()>&$X

Attempt This Online!

A function which either does>&1 (copy input to STDOUT) or >&0 (write to STDIN, which doesn't work).

Can be shorter.


If using the PID as a source of randomness is allowed (which doesn't work on Attempt This Online because of how the sandbox works):

Zsh, 11 bytes

f()>&$[$%2]
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Does this actually do the task? It seems like it just does one of the two things at random. \$\endgroup\$
    – Wheat Wizard
    Dec 28, 2021 at 1:00
  • \$\begingroup\$ @WheatWizard it's a function; the wrapper on ATO runs it three times with the input input and it always does either 3 cats (prints input each time) or 3 NOPs. What part do you think it's not doing? The X= bit is only run once in total; it can be seen as part of the function's definition \$\endgroup\$
    – pxeger
    Dec 28, 2021 at 1:54
  • \$\begingroup\$ How do you run this for the first time? These are snippets which create functions which then print the same thing every time. Here is what I would consider a valid submission using this idea (Source code is the function body, independent of the function name, it redefines the function and recurses on the first run): ato.pxeger.com/… \$\endgroup\$ Dec 28, 2021 at 21:41
  • \$\begingroup\$ @GammaFunction how is my answer any different to, for example, a Python answer of the form def f():...? The answer is the code to define the function. This definition is always run exactly once. Then each time you run it, you call f. \$\endgroup\$
    – pxeger
    Dec 28, 2021 at 22:24
  • \$\begingroup\$ @GammaFunction I don't see why your example is valid because it doesn't include the initial function definition. Zsh doesn't have function expressions, so you have to define it with a name, and include the f(){ } in your answer and byte count. At this point you don't need to bother with the $0; you can just call it f since you know it's called that name \$\endgroup\$
    – pxeger
    Dec 28, 2021 at 22:28
2
\$\begingroup\$

APL (Dyalog Unicode), 15 bytes

Anonymous lambda. Takes one or two dummy arguments. Requires 0-based indexing.

{6::∇a∘←?2⋄a:⍞}

Try it online!

You can reset the program by erasing its global state a.

{} "dfn":

6:: if we hit a value error:

  a∘← globally assign to a:

   ?2 a random 0 or 1

 now try:

  a: if a [is 1]:

    read STDIN [and implicitly return and print it]

\$\endgroup\$
9
  • \$\begingroup\$ Is this a progam or just a function? (Looks to me like a is something that exists at the program scope and we are re-running a function rather than a program.) \$\endgroup\$ Dec 27, 2021 at 21:03
  • \$\begingroup\$ @JonathanAllan This is a function that takes an argument just to run; it doesn't use the argument. \$\endgroup\$
    – Adám
    Dec 27, 2021 at 21:03
  • \$\begingroup\$ I read "it should do it no matter how much times you run the script." as "this must be a full program, which has some way to enforce the repeated behaviour between runs". \$\endgroup\$ Dec 27, 2021 at 21:05
  • \$\begingroup\$ Program or function doesn't really matter for that, imo. It is trivial to rewrite as a full program. The argument has nothing to do with the saved state; it uses a global variable for that. \$\endgroup\$
    – Adám
    Dec 27, 2021 at 21:06
  • \$\begingroup\$ As written it looks to me like we must write a full program, but I've asked. (It might make a huge difference for some languages!) \$\endgroup\$ Dec 27, 2021 at 21:17
2
\$\begingroup\$

C (gcc), 149 bytes

Stores either s or u into the user.a extended attribute of the executable. setxattr() doesn't replace an already-existing value, so I just write the value and then retrieve it to see whether to cat the input (s) or not (u).

To reset the program, run setfattr -x user.a {programname}

main(a,v,s)char*v,*s;{char r[]="user.a";srand(time(0));s=r+rand()%2;setxattr(*v,r,s,1,1);getxattr(*v,r,s,1);if(*s&2)while(~(a=getchar()))putchar(a);}

Try it online!

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

JavaScript (ES2020), browser, 56 52 bytes

(localStorage.d||=Math.random())>.5&&alert(prompt())

Sets the d property of localStorage if it's undefined. Stacksnippets doesn't like setting localstorage, so run this in your console to see.

Full program. -4 thanks to tsh.

\$\endgroup\$
5
  • \$\begingroup\$ Maybe you can save the random number and then test >.5 every time the program run. \$\endgroup\$
    – tsh
    Dec 28, 2021 at 1:04
  • \$\begingroup\$ @tsh Nice idea! \$\endgroup\$
    – emanresu A
    Dec 28, 2021 at 2:09
  • \$\begingroup\$ But typically, a cat support multiple lines input. \$\endgroup\$
    – tsh
    Dec 28, 2021 at 2:48
  • \$\begingroup\$ @tsh That's a system limitation :P \$\endgroup\$
    – emanresu A
    Dec 28, 2021 at 2:49
  • \$\begingroup\$ Saving +new Date and checking %2 should shave 5 more bytes. However I'm not sure this really qualifies as a "Full program" since the Storage API needs a Document, I think the shortest would thus be an HTML one <script>your-code</script>, but I guess this will depend on how the question gets edited anyway. \$\endgroup\$
    – Kaiido
    Dec 29, 2021 at 14:37
1
\$\begingroup\$

Batch, 53 bytes

@if "%c%"=="" set/ac=%random%%%2
@if %c%==1 find/v""

Use set c= to reset the flag. Explanation: If c is empty, the first line sets c to a random value that is either 0 or 1, then the second line copies STDIN to STDOUT only if c is 1. I don't know why the builtin find command fails to find the empty string in any input, but it's consistent, so we can simply invert the condition, thus turning find into a cat program.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ As usual for weird arcane history of Microsoft stuff, Raymond Chen wrote about this ten years ago! \$\endgroup\$
    – ErikF
    Dec 28, 2021 at 5:41
1
\$\begingroup\$

AWK, 48 bytes

BEGIN{a=systime()%2;getline a<"_";print a>"_"}
a

Try it online!

systime() is used to decide whether to print or not. State is saved in the file _. getline does not clobber variables if it doesn't read anything.

\$\endgroup\$
0
\$\begingroup\$

Python 3, 66 62 bytes

import random
if random.randint(1,2)==1:print(str(input("I")))

Gets a random value and if it's 1, it gets and prints user input. I just put an I (for input) because my Python interpreter allows you to give input even when not asked for.

\$\endgroup\$
0
\$\begingroup\$

Zsh, 35 bytes

((RANDOM&1))&&p='<&0'&&<&0
<<<$p>$0

Try it online!

Randomly overwrites the file with either <&0 (equivalent to cat) or nothing.

\$\endgroup\$
0
\$\begingroup\$

MATLAB/Octave, 80 60 bytes

global x;if x;else;x=randi(1:2);end;if x>1;input('','s');end

Will either do nothing, or whatever the user inputs to ans= (considered "STDOUT" for our purpose), then stick with that choice.

When first used a global variable (x here) is empty. Empty values evaluate to false. If x is false, it will set it to a random integer of either 1 or 2. This will then never evaluate false again, so the first part of the program will then never run again.

If x is 2, then the program will request user input (considered "STDIN" for our purpose). If x is 1, will do nothing at all.


Relies on the fact that a global variable is persistent once created, and will only reset if the user clears all variables ("reboots" for our purpose).

I would add a TIO link, but unfortunately that doesn't seem to want to handle global variables.

\$\endgroup\$

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