42
\$\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\$
  • 26
    \$\begingroup\$ I didn't know :x was a thing! I've always used :wq :) \$\endgroup\$ – musicman523 Jun 20 '17 at 13:32
  • 2
    \$\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 '17 at 13:38
  • 4
    \$\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\$ – Skidsdev Jun 20 '17 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 '17 at 3:16
  • 5
    \$\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\$ – Aaron McMillin Jun 21 '17 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\$
  • 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 '17 at 14:39
  • \$\begingroup\$ @Mr.Xcoder Thanks, it actually saved me 3 bytes! \$\endgroup\$ – musicman523 Jun 20 '17 at 14:43
  • \$\begingroup\$ Yes, I didn't see you had 2 print statements \$\endgroup\$ – Mr. Xcoder Jun 20 '17 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\$ – Skidsdev Jun 20 '17 at 14:47
  • \$\begingroup\$ @Mayube oh that's awesome, thank you! \$\endgroup\$ – musicman523 Jun 20 '17 at 14:48
7
\$\begingroup\$

Ruby, 35 bytes

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

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You can shave a byte by removing the space between p and :q ;) \$\endgroup\$ – ymbirtt Jun 20 '17 at 16:59
  • 1
    \$\begingroup\$ awesome and weird! I didn't know that, thanks @ymbirtt \$\endgroup\$ – André Diego Piske Jun 20 '17 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\$
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\$
  • \$\begingroup\$ This prints an extra newline where the challenge says it should not give any more output \$\endgroup\$ – musicman523 Jun 20 '17 at 13:49
  • \$\begingroup\$ @Mayube May we output a newline upon terminating? @Adám sure, that's fine \$\endgroup\$ – Stephen Jun 20 '17 at 13:59
  • 1
    \$\begingroup\$ random()>.5 to save a byte \$\endgroup\$ – Rod Jun 20 '17 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 '17 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 '17 at 20:34
5
\$\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\$
3
\$\begingroup\$

JavaScript, 52 46 bytes

Saved 6 bytes thanks to @ETHProductions

prompt(':q')[30]&&alert(new Date%2?':q!':':x')
\$\endgroup\$
  • \$\begingroup\$ Doesn't there need to be a ! after the :q if the input is an error? \$\endgroup\$ – Shaggy Jun 20 '17 at 15:30
  • \$\begingroup\$ @Shaggy aww, didn't notice that, there goes 9 bytes \$\endgroup\$ – Downgoat Jun 20 '17 at 15:33
  • \$\begingroup\$ I think you can save a few bytes with prompt(':q')[30]&&.... Also, new Date%2?':x':':q!' \$\endgroup\$ – ETHproductions Jun 20 '17 at 17:01
  • \$\begingroup\$ @ETHproductions oh yeah, thanks! not sure how I overlooked a ternary \$\endgroup\$ – Downgoat Jun 20 '17 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\$
  • \$\begingroup\$ Placing your program in the System namespace makes you able to shorten System.Random to Random, saving 1 byte \$\endgroup\$ – LiefdeWen Jun 20 '17 at 13:48
  • \$\begingroup\$ @CarlosAlejo works for me in TIO, however it outputs q! not :q! \$\endgroup\$ – Skidsdev Jun 20 '17 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 '17 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 '17 at 16:09
  • 1
    \$\begingroup\$ @MordZuber what the...? I didn't even know that was possible! Thank you! \$\endgroup\$ – Charlie Jun 20 '17 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\$
  • \$\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 '17 at 20:36
  • \$\begingroup\$ @Aaron Thanks, that's a very neat trick! Why wouldn't it be allowed? \$\endgroup\$ – PidgeyUsedGust Jun 22 '17 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 '17 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\$
  • 2
    \$\begingroup\$ Why not just call prompt() directly? (Also, are you allowed prompt(":q")?) \$\endgroup\$ – Neil Jun 20 '17 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 '17 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 '17 at 19:55
  • \$\begingroup\$ @Artyer thanks, I had thought of that and then forgot about it \$\endgroup\$ – Stephen Jun 20 '17 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\$
  • \$\begingroup\$ An explanation would be great. \$\endgroup\$ – pajonk Jun 22 '17 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, privacy policy and cookie policy

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