41
\$\begingroup\$

Vim is a great text editor for unix systems, but it's notorious for being difficult to exit.

Write a full program that will output :q to exit Vim. It should then read a single line of input, as it will then either be given a bash prompt, in which case the exit was successful, or an error, in which case there are unsaved changes.

The bash prompt will be this:

E37@vimmachine: /var/override)

While the error will be this:

E37: No write since last change (add ! to override)

Upon being given the bash prompt, the program's work is done, and it should not give any more output (except for whitespace).

Upon being given the error, your program should randomly (ie each possibility has a non-zero probability of being chosen) output :q!, to exit without saving, or :x, to save and exit.

This is so fewest bytes in each language wins!

\$\endgroup\$
15
  • 27
    \$\begingroup\$ I didn't know :x was a thing! I've always used :wq :) \$\endgroup\$ Jun 20, 2017 at 13:32
  • 3
    \$\begingroup\$ What if my bash prompt is E37: No write since last change? That is, how can an algorithm distinguish a prompt from an error message? \$\endgroup\$
    – anatolyg
    Jun 20, 2017 at 13:38
  • 5
    \$\begingroup\$ @anatolyg it can't, but it also doesn't have to. The given prompt will always be the one above, that is E37@vimmachine: /var/override) \$\endgroup\$
    – Mayube
    Jun 20, 2017 at 13:38
  • 2
    \$\begingroup\$ The given prompt will always be the one above That should be stated in the challenge spec. As is, it says looks like this, which can mean any number of things. \$\endgroup\$
    – Dennis
    Jun 21, 2017 at 3:16
  • 7
    \$\begingroup\$ (joined golf for this comment, sheesh) @musicman523 NEVER use :x to exit vim. Someday you'll accidentally hit :X then random keys when you're confused. After you finally :wq you'll never see your file again. \$\endgroup\$ Jun 21, 2017 at 14:14

20 Answers 20

16
\$\begingroup\$

Python 2, 66 bytes

Saved 3 bytes thanks to @Mr.Xcoder and 4 thanks to @Mayube!

from random import*
if'('in input(':q'):print choice([':x',':q!'])

Try it online!

\$\endgroup\$
6
  • 2
    \$\begingroup\$ If you switch to Python 2, you can save 1 bytes by using print instead of print(). And you can take the input with quotes \$\endgroup\$
    – Mr. Xcoder
    Jun 20, 2017 at 14:39
  • \$\begingroup\$ @Mr.Xcoder Thanks, it actually saved me 3 bytes! \$\endgroup\$ Jun 20, 2017 at 14:43
  • \$\begingroup\$ Yes, I didn't see you had 2 print statements \$\endgroup\$
    – Mr. Xcoder
    Jun 20, 2017 at 14:44
  • 3
    \$\begingroup\$ I gave this tip to totallyhuman so it's only fair I give it to you as well. You can remove print':q' altogether and change input() to input(':q') \$\endgroup\$
    – Mayube
    Jun 20, 2017 at 14:47
  • \$\begingroup\$ @Mayube oh that's awesome, thank you! \$\endgroup\$ Jun 20, 2017 at 14:48
7
\$\begingroup\$

Ruby, 35 bytes

p:q
p %i(q! x)[rand 2]if/\(/=~gets

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can shave a byte by removing the space between p and :q ;) \$\endgroup\$
    – ymbirtt
    Jun 20, 2017 at 16:59
  • 1
    \$\begingroup\$ awesome and weird! I didn't know that, thanks @ymbirtt \$\endgroup\$ Jun 20, 2017 at 17:27
6
\$\begingroup\$

05AB1E, 19 bytes

„:q,'Nåi„:x…:q!‚.R,

Try it online!

„:q,                # Print the string ":q"
    'Nåi            # If N is in the input
        „:x         #   Push the string ":x"
           …:q!     #   Push the string ":q!"
               ‚    #   Wrap them into an array
                .R, #   Randomly print one of them
\$\endgroup\$
6
\$\begingroup\$

Vimscript, 45 41 bytes

ec"q"|exe"/("|ec["q!","x"][getpid()%2]

Shaved off 4 bytes by using getpid() to get a number. (Can anyone think of a shorter way to get a number that won't be the same everywhere, all the time?)

Assuming +3 bytes for invoking Vim with -c to run the above script and - to read input from stdin:

vim -c 'ec"q"|exe"/("|ec["q!","x"][reltime()[1]%2]' -
\$\endgroup\$
5
\$\begingroup\$

Python 2, 76 75 72 69 bytes

This answer has been out-golfed.

-1 byte thanks to Rod. -3 bytes thanks to Mayube. -3 bytes thanks to Artyer.

from random import*
print'::qx!'[random()>.5:('N'in input(':q'))*5:2]

Try it online!

\$\endgroup\$
12
  • \$\begingroup\$ This prints an extra newline where the challenge says it should not give any more output \$\endgroup\$ Jun 20, 2017 at 13:49
  • \$\begingroup\$ @Mayube May we output a newline upon terminating? @Adám sure, that's fine \$\endgroup\$
    – Stephen
    Jun 20, 2017 at 13:59
  • 1
    \$\begingroup\$ random()>.5 to save a byte \$\endgroup\$
    – Rod
    Jun 20, 2017 at 14:03
  • 2
    \$\begingroup\$ Does the randomness have to be uniformly distributed? If not, you could do random()>0, because there is a very very small chance that random() will return 0. \$\endgroup\$
    – mbomb007
    Jun 20, 2017 at 17:09
  • 1
    \$\begingroup\$ @Artyer You know what [0, 1) means, right? It means that zero is included because the range is zero-inclusive. stackoverflow.com/a/4396303/2415524 ...The easy way to remember it is that on a number line, closed dots are included, and open dots aren't. Brackets look closed, and parens look open. \$\endgroup\$
    – mbomb007
    Jun 20, 2017 at 20:34
3
\$\begingroup\$

JavaScript, 52 46 bytes

Saved 6 bytes thanks to @ETHProductions

prompt(':q')[30]&&alert(new Date%2?':q!':':x')
\$\endgroup\$
4
  • \$\begingroup\$ Doesn't there need to be a ! after the :q if the input is an error? \$\endgroup\$
    – Shaggy
    Jun 20, 2017 at 15:30
  • \$\begingroup\$ @Shaggy aww, didn't notice that, there goes 9 bytes \$\endgroup\$
    – Downgoat
    Jun 20, 2017 at 15:33
  • \$\begingroup\$ I think you can save a few bytes with prompt(':q')[30]&&.... Also, new Date%2?':x':':q!' \$\endgroup\$ Jun 20, 2017 at 17:01
  • \$\begingroup\$ @ETHproductions oh yeah, thanks! not sure how I overlooked a ternary \$\endgroup\$
    – Downgoat
    Jun 20, 2017 at 17:40
3
\$\begingroup\$

C# (.NET Core), 140 139 138 bytes

using static System.Console;class P{static void Main(){Write(":q");if(ReadLine()[3]==':')Write(new System.Random().Next()>9?":x":":q!");}}

Try it online!

  • 1 byte saved thanks to LiefdeWen!
  • 1 byte saved thanks to Mord Zuber!
\$\endgroup\$
8
  • \$\begingroup\$ Placing your program in the System namespace makes you able to shorten System.Random to Random, saving 1 byte \$\endgroup\$
    – LiefdeWen
    Jun 20, 2017 at 13:48
  • \$\begingroup\$ @CarlosAlejo works for me in TIO, however it outputs q! not :q! \$\endgroup\$
    – Mayube
    Jun 20, 2017 at 13:50
  • 1
    \$\begingroup\$ @CarlosAlejo Ahh, I didn't even realize that you didn't use a namespace, the question also doesn't say uniformly random, just all possibilities should have non-zero chance so you change .Next(2)>0 to .Next()>9, it leaves a bit of a bad taste in the mouth but it's still legal. \$\endgroup\$
    – LiefdeWen
    Jun 20, 2017 at 13:56
  • 4
    \$\begingroup\$ using static System.Console lets you drop all C. calls, and saves you a byte \$\endgroup\$
    – Mord Zuber
    Jun 20, 2017 at 16:09
  • 1
    \$\begingroup\$ @MordZuber what the...? I didn't even know that was possible! Thank you! \$\endgroup\$
    – Charlie
    Jun 20, 2017 at 18:28
3
\$\begingroup\$

><>, 32 30 29 bytes

  • Had a redundant !o.
  • -1 byte thanks to Aaron.

iii0["@!qx:q:"ooi{=?;o!ox~oo;

Try it online!

Explanation (old)

"@!qx:q:"ooi~i~i~i{=?;o!ox~oo;
"@!qx:q:"                        Push @!qx:q: on the stack (in reverse)
         oo                      Print :q [stack: @!qx:]
           i~i~i~                Remove first 3 input characters
                 i               Load @ or : from the input (= i)
                  {              Shift stack to the left [stack: !qx:i@]
                   =?            If 4th character was @
                     ;              Exit
                                 Else
                      o             Print :
                       !o           Jump to
                         x          Random direction (left or right because
                                    up and down retrigger x)
                                       Left:
                     ;o!o                 Print x and exit.
                                       Right:
                          ~oo;            Remove x, print q! and exit.

(will update soon)

\$\endgroup\$
3
  • \$\begingroup\$ I'm not sure this would be allowed, but you could win one byte by reading the 3 characters to discard first, then start working on a new stack with [ : iii0[ wil leave you with an empty stack ; nice one anyway, I like how you populate all your possible outputs at the start to avoid additional quotes \$\endgroup\$
    – Aaron
    Jun 21, 2017 at 20:36
  • \$\begingroup\$ @Aaron Thanks, that's a very neat trick! Why wouldn't it be allowed? \$\endgroup\$ Jun 22, 2017 at 14:04
  • \$\begingroup\$ Because you'd be reading the input before having printed the output that leads to its production, which I suppose goes against the spirit of the challenge. However it's not like the challenge can realistically implemented with the official ><> interpreter since python will wait for the input's EOF before executing the ><> code (or something like that) \$\endgroup\$
    – Aaron
    Jun 22, 2017 at 14:23
2
\$\begingroup\$

Actually, 27 bytes

":q"ü[":x",":q!"]`⌂`J'!,cIƒ

Try it online! (Note: As TIO doesn't play nice with stdin, I've replaced the , (read from stdin) with the literal string, which you can change to test it. Also, you'll need to disable output cache in order to get a different response with the random output.)

Explanation:

":q"ü[":x",":q!"]`⌂`J'!,cIƒ
":q"ü                       - Push the literal :q and print
     [":x",":q!"]           - Push the list of literals :x and :q!
                 `⌂`J       - Push function literals ⌂ (terminate) and J (choose random element from list)
                     '!     - Push the literal !
                       ,    - Read from stdin
                        c   - Pop top two values a,b and return "a".count(b)
                         I  - Pop top three values a,b,c and return b if a is truthy and c if a is falsy
                          ƒ - Pop a function from the stack and call it
\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog), 27 bytes

':q'⋄('!'∊⍞)/':q!' ':x'⊃⍨?2

Try it online!

':q' print this

 then

?2 random integer among the first two

⊃⍨ use that to select from

':q!' ':x' this list of two strings

()/ replicate that with, i.e. make n copies of each element in that, where n is

'!'∊⍞ is exclamation point a member of the text input? (Boolean, i.e. 0 or 1)

\$\endgroup\$
1
\$\begingroup\$

Batch, 98 bytes

@echo :q
@set/ps=
@if %s:~3,1%==@ exit/b
@set/an=%random%%%2
@if %n%==0 (echo :x)else echo :q!
\$\endgroup\$
1
\$\begingroup\$

Ruby, 33 bytes (32 code, +1 for -n flag)

p:q;$_[?!]? p([:q!,:x][$$%2]): p

I'm not too sure on the $$%2 snippet. I'm using it to generate a random bit to index my array by taking the current ruby process's pid modulo 2, and it'll be fairly unpredictable. .sample adds an extra byte.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

JavaScript, 76 71 50 bytes

prompt(":q")[3]<"@"?alert(new Date%2?":q!":":x"):0

Saved a bunch of bytes thanks to Artyer and Neil, as well as condensing my ternaries and moving first alert to prompt (duh).

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Why not just call prompt() directly? (Also, are you allowed prompt(":q")?) \$\endgroup\$
    – Neil
    Jun 20, 2017 at 14:28
  • \$\begingroup\$ You can use the time as a random number (new Date%2 instead of Math.random()>.5), and you can use prompt directly like @Neil said: prompt()[3]< \$\endgroup\$
    – Artyer
    Jun 20, 2017 at 15:22
  • \$\begingroup\$ @Neil Why? I had been doing a .indexOf on it, before I noticed the other way to do it. Forgot to switch back, thanks! \$\endgroup\$
    – Stephen
    Jun 20, 2017 at 19:55
  • \$\begingroup\$ @Artyer thanks, I had thought of that and then forgot about it \$\endgroup\$
    – Stephen
    Jun 20, 2017 at 19:55
1
\$\begingroup\$

Python 2, 64 bytes

import time
if'w'in input(':q'):print'::qx!'[time.time()%2>1::2]

Try it online!

Since this is just an agglomeration of both of these Python answers, I've marked this as community wiki.

\$\endgroup\$
1
\$\begingroup\$

Python 2, 47 bytes

print'::qx!'[id(0)%3<2:('N'in input(':q'))*5:2]

Try it online

Explanation:

The source of randomness is id(0)%3<2. The function id returns the memory location of the parameter. Passing anything will give a non-deterministic memory address. The result will always be even, but it will only sometimes be divisible by 3. The results modulo 3 vary. So, this can be a source of randomness. Using <2 means that roughly 2/3 of the time, the resulting boolean is True.

The rest of the answer is inspired by this one.

\$\endgroup\$
1
\$\begingroup\$

Keg, 14 12 bytes

\:~2%[q\!|x]

This pushes a random number and outputs corresondingly to the random number.

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

TCL, 95 bytes

puts :q;puts [if [string match *!* [gets stdin]] {puts [lindex ":q! :x" [expr round(rand())]]}]

A simple and rather long solution in tcl...

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

Assembly 86Bytes Linux System Calls

global _start
_start:
mov edx,4
mov ecx,g 
mov ebx,1
mov eax,4
int 0x80
g db ':q!',10
\$\endgroup\$
0
\$\begingroup\$

LOGO, 37 36 bytes

pr[:q]if 4<count rl[pr pick[:q! :x]]

Try it online at Anarchy Golf Performance checker.

Explanation:

pr[:q]if 4<count rl[pr pick[:q! :x]]   Main program.
pr                                     Print
  [:q]                                 the list `[:q]` without delimiter `[]`
      if           [              ]    If...
         4<                            4 is less than...
           count                       the number of word in the...
                 rl                    ReadLine (from stdin),
                    pr                 print
                       pick            a random word picked from the list...
                           [:q! :x]    [:q! :x]

(because E37@vimmachine: /var/override) has 2 words, while E37: No write since last change (add ! to override) has 10 words)

\$\endgroup\$
1
  • \$\begingroup\$ An explanation would be great. \$\endgroup\$
    – pajonk
    Jun 22, 2017 at 12:19
0
\$\begingroup\$

Perl 5 (with -E flag), 35 bytes

say":q";<>=~l&&say qw(:q! :x)[$$%2]

Run this with perl -E 'say":q";<>=~l&&say qw(:q! :x)[$$%2]'.

Try it online!

Ungolfed:

say(":q");
if(<> =~ /l/){ #read a line and check if it contains 'l'
    @a=(":q!",":x");
    say($a[$$ % 2]); #print one element from array based on PID
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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