17

What is the smallest number of non-space characters that can be added in order to change the following code into a complete C program that prints  LoopyLoopyLoopyLoopy?

#include<stdio.h>
main(){
<-- ^
| @ |
v --> printf("Loopy");}

Starts as: 5 lines with no leading spaces, totaling 52 non-space characters and 5 within-line spaces.

Possible edits (additions that don't move the original characters):
• &hairsp; Single non-space characters may replace any of the 5 original spaces.
• &hairsp; Spaces and non-space characters may be added to the ends of lines.

No-nos and pedantry:
• &hairsp; No commenting.
• &hairsp; No additional " quotation marks.
• &hairsp; No new lines. (Intended, but not made explicit, in the original puzzle statement.)
• &hairsp; All syntax should abide by The C Programming Language, 2nd Edition, Kernighan & Ritchie.
• &hairsp; If any variables are used before they are initialized, the program should be successful with any initial values for those variables.

Notes about the original puzzle statement: The word visible was used instead of instead of non-space. Adding lines was unintentionally allowed as a newline would count as a character added to the end of an existing line. The line #include<stdio.h> could have been left out for a more streamlined version of essentially the same puzzle, as mentioned by Arkku.

Hazel へいぜる
  • 10,581
  • 15
  • 74
humn
  • 21,899
  • 4
  • 60
  • 161
  • 25
    This kind of question is excellent for the Programming Puzzles & Code Golf Stack Exchange. :) http://codegolf.stackexchange.com/ – MichaelK Jun 25 '16 at 14:37
  • 1
    what's wrong with the code you already have? – JMP Jun 25 '16 at 15:44
  • 1
    I'm quite disappointed that #define - makes the compiler mad. Otherwise, I'd be perfectly happy to have the preprocessor eat the code I don't want, and insert some stuff I do. – Milo Brandt Jun 25 '16 at 15:47
  • 1
    The compiler gave the error on purpose just to stall you, @MiloBrandt, while it secretly works on this puzzle itself. Besides that, the puzzle doesn't leave room for adding #preprocessor lines (or any lines at all). – humn Jun 25 '16 at 15:53
  • 1
    @MichaelKarnerfors - it would probably be closed as off topic since it only allows a single programming language to compete and is more "puzzle"y than most things there. – Robert Fraser Jun 26 '16 at 05:36
  • I found a solution that's 20 characters, but it's practically the same as one of the already posted answers, I just played with the placements a little. – dcfyj Sep 20 '16 at 13:21
  • Please do post your solution, @dcfyj, every character counts when puzzles are in the balance! The previous solutions will always get credit for getting so close so many months earlier. I'd be curious to see if our solutions are identical. (If they differ there's even the awkward possibility that yours won't work on the judges' compiler.) – humn Sep 20 '16 at 16:51
  • @humn judge away. – dcfyj Sep 20 '16 at 16:59
  • Does this count? #include<stdio.h> main(){printf("LoopyLoopyLoopyLoopy");} ? – jmbmage Sep 20 '16 at 23:42
  • 3
    This sort of question is ontopic at PPCG, it's just incredibly rare that anyone writes a good one. (This is a good one, though.) We have the "programming-puzzle" tag for things like this, and it's hardly used, even though "programming puzzles" is part of our name. (I'm beginning to think that we should just let you lot have them; you're better at them.) – ais523 Feb 19 '17 at 01:13
  • 1
    Thank you for the positive feedback, @ais523. A drop-in at The Nineteenth Byte didn't seem to raise any interest at the time. You might also like this puzzle's inspiration: Debugging with printf(). Then there are this site's sometimes-truly-hardcore mathjax puzzles, the first of which gives a lighthearted-but-motivated-by-respect nod to PPCG: MathJax exposed. – humn Feb 19 '17 at 01:31

5 Answers5

9

21

#include<stdio.h>
main(){int v=8;for(;0                   # 13 (because the space doesn't count …
<--v^0;0                                #  4                … as a visible character)
|'@'|0)                                 #  4
v --> printf("Loopy");}

Cleaned up:

#include<stdio.h>
main()
{
    int v=8;
    for(; 0 < --v^0; 0|'@'|0)
        v-- > printf("Loopy");
}

Pretend that the v=8 is in the initialize field of the for statement.  for(v=8; 0 < --v^0; … is a slightly warped version of for(v=8; --v > 0; … or, approximately, for(v=8; v > 0; v--)  (I'm not sweating the fence-post issues for now).  This uses the ^ bitwise exclusive OR operator, for which 0 is the identity; value ^ 0 = value and, in particular, --v^0 = --v.

The step portion (third field) of the for statement evaluates the constant 0|'@'|0 and does nothing with the result, so that is a no-op.  Note that the rules prohibit adding ", but don't mention '.

Naïvely, for(v=8; v > 0; v--) will loop eight times.  But the body of the loop does v--, so v gets decremented twice for each iteration, and the loop runs only four times.  The body of the loop evaluates v-- and printf("Loopy") (evaluating the return code of the printf), compares them, and does nothing with the result of the comparison.

Peregrine Rook
  • 4,880
  • 2
  • 26
  • 40
  • 1
    I think even in the old days you were allowed to assign on declaration, so you could save a byte with int v=8;for(;0 – Dave Jun 25 '16 at 17:40
  • 1
    Good point.  I considered for(int v=8; …, but when I realized that that was too modern, I dropped back and punted. – Peregrine Rook Jun 25 '16 at 17:44
  • No additional " quotation marks. Someone found a hole in this challenge! – EKons Jun 26 '16 at 10:43
  • This is better than on-my-own lowest of 22 (at post time was 31!), but by harvesting body parts from KeyboardWielder's and your solutions, made a Frankenstein that's at 20 – humn Jun 27 '16 at 02:07
7

Quick attempt with 24 visible characters:

#include<stdio.h>
main(){f(f(f(f())));}f(v){v
<--v^v
|'@'|
v --> printf("Loopy");}

Explanation:

Put the printf into a function f() that is called 4 times (nested to save on some semicolons) and just make the rest of the stuff valid syntax.


Other failed ideas:

  • Digraphs / trigraphs - None that could be abused.
  • Use of isxdigit - Assuming a simple macro definition that evaluates its argument 4 times in its 4 comparisons, and hoping that <stdio.h> includes <ctype.h>. The latter is true for gcc but sadly the former isn't.
  • Use of qsort - Works (probably compiler dependent), but is suboptimal. Example updated first line:

    main(){f(0);}f(v){v||qsort(&v,3,1,f),v

KeyboardWielder
  • 5,956
  • 25
  • 55
  • 2
    Clever!  It never occurred to me to add a } and a {.  P.S. I also count 24 characters. – Peregrine Rook Jun 26 '16 at 20:57
  • If you come up with something different, gotta leave this gem on display! If the goal were just LoopyLoopy this might be absolutely minimal. By harvesting body parts from Peregrine Rook's and your solutions, I made a Frankenstein that's at 20. (On my own had worked down to 22 from a robust 31...) – humn Jun 27 '16 at 03:53
  • Corrected the count to 24. – KeyboardWielder Jun 27 '16 at 18:24
  • Sure enough, even though gcc requires a -trigraphs switch, the rule book shows trigraphs on page 229. Finally something learned from that book (which I consider a haiku love-letter rather than a manual). Can now imagine trigraphs in a truly obscure C[lassical] puzzle. – humn Jun 27 '16 at 19:46
  • 1

    a haiku love-lettter --- Indeed. My all-time favourite is the section about void: "The (nonexistent) value of a void object may not be used in any way ..."

    – KeyboardWielder Jun 27 '16 at 19:46
  • I must say the qsort attempt was very clever, but it may be undefined behaviour as it is not guaranteed that v is 3 bytes long. – Arkku Sep 21 '16 at 12:42
7

Here's what I came up with: $20$ Characters

  #include
 main(){int v=8;for(;0        //13 characters
 <--v^0;0                    //4 characters
 |'@ |')                     //3 characters
 v --> printf("Loopy");}    

This is basically the same idea as Peregrine Rook, with some minor changes.

I also found this: $19$ characters

 #include<stdio.h>
 main(){int v;for(;-8        //12 characters
 <--v^0;0                    //4 characters
 |'@ |')                     //3 characters
 v --> printf("Loopy");}  

This interestingly enough compiles but doesn't count in this challenge as the value of v is not defined.

dcfyj
  • 7,756
  • 23
  • 64
  • Olé! The judges' compiler didn't even require a bribe for either solution. They're still leafing through the rule book in search of multi-character literals (a thrilling maneuver, in any case), though, and will wait another day regardless to close the finish line. – humn Sep 20 '16 at 17:48
  • I looked myself, but I didn't really find anything conclusive one way or the other. – dcfyj Sep 20 '16 at 17:49
  • Some internet historians indicate, inconclusively yes, that "multi-chars" might not have been official until 1999, but showing them off like this is a wonderful surprise contribution here – humn Sep 20 '16 at 17:57
  • I figured it probably wasn't valid, thus the secondary answer. Nonetheless, I got my 20 ^^. – dcfyj Sep 20 '16 at 17:58
  • The judges found multi-character constants(!) on page 193 in section A2.5.2, titled of all things "Character Constants" – humn Sep 20 '16 at 18:21
  • I found that too, but it was looking like you needed to put an "L" in front of the quote... – dcfyj Sep 20 '16 at 18:21
  • "L" for "wide" means characters/strings that use 16 bits/char, not a sequence of 8-bit characters – humn Sep 20 '16 at 18:23
  • Does that make the 19 chr solution valid then? or is only the 20 valid? – dcfyj Sep 20 '16 at 18:24
  • 19 all the way! – humn Sep 20 '16 at 18:24
  • 1
    Much as I hate to be a pedant, “If any variables are used before they are initialized, the program should be successful with any initial values for those variables.” v is not initialized, and the code depends on its being initialized to $0$.  Lest I be accused of pedantry, we’re playing by K&R rules, and K&R, section 2.4 Declarations (page number 54 of the PDF file; printed page number 40) says, “Automatic variables for which there is no explicit initializer have undefined (i.e., garbage) values.” – Peregrine Rook Sep 20 '16 at 22:06
  • Caught the judges napping, @Peregrine Rook, thank you. (A 20-character hybrid does hold up, though.) – humn Sep 20 '16 at 22:47
  • The revision checks out without being tested. It's identical to the hybrid just mentioned.Good recovery! The 19-char version is well worth showing too. – humn Sep 20 '16 at 23:47
  • OK, I'll add in back in in a minute. – dcfyj Sep 20 '16 at 23:49
  • The int v;for(;-8 only works for some initial values of v and as an automatic variable v is not implicitly initialised… – Arkku Oct 11 '16 at 15:09
  • @Arkku If you read the text below that entry you'll see that I said it's not valid for this challenge. It was one of my attempts that humn told me to put back in because it was interesting. – dcfyj Oct 11 '16 at 15:17
  • @dcfyj Ok, I did actually read that text but it did not specify why it does not count in this challenge, and the comments related to it are several weeks old so I did not re-read them, sorry. (Perhaps add the explanation as to why it doesn't work in the answer itself? =) – Arkku Oct 11 '16 at 15:23
7

19

In accordance with the updated rules:

#include<stdio.h>
main(){int v=4;for('\
<-- ^\
| @ |';v;)
v --> printf("Loopy");}

16 or 17

The original rules (in effect at the time of posting this) unintentionally permitted adding a newline character to the end of a line, which enabled:

#include<stdio.h>
v;
main(){for(;-8
<--v^0;'\
| @ |')
v --> printf("Loopy");}

(16 if adding a newline character to end of line counts as space, 17 if it counts as a non-space.)

Note: The type of the global v defaults to int and is implicitly initialized to zero in ANSI C (the standard at the time of K&R 2nd edition) due to static duration.

15

If it were permitted to insert a single non-space character between two non-space characters:

#include<stdio.h>
main(v){for(;-8
<--v^0;'\
| @ |')
v --> printf("Loopy");}

This with the caveat:

The program must be run without arguments in an environment that passes 1 as the initial argument of main in that case. (As discussed in comments, this is permitted.)

Arkku
  • 1,134
  • 8
  • 12
1

Only 19

My code is:

#include<stdio.h>
main(){for(int v=8;0           // Here 12 non-space characters          
<--v^0;0                       // Here 4 non-space characters        
|'@ |')                        // Here 3 non-space characters          
v --> printf("Loopy");}

so, total of 19 non-space characters

KSR
  • 1,811
  • 11
  • 29
  • I am trying to reduce it below 19 characters... Nice question humn – KSR Sep 22 '16 at 10:43
  • 1
    The declaration of a variable inside for is not in K&R 2nd edition era C standards, it was added in C99. – Arkku Sep 22 '16 at 12:54
  • If it were allowed the declare inside for, you could have for(char v='…^D';v;) where ^D is a single character produced by ctrl-D (numeric value 4). The total is still the same 19, but… – Arkku Sep 22 '16 at 13:28