17
$\begingroup$

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):
•   Single non-space characters may replace any of the 5 original spaces.
•   Spaces and non-space characters may be added to the ends of lines.

No-nos and pedantry:
•   No commenting.
•   No additional " quotation marks.
•   No new lines. (Intended, but not made explicit, in the original puzzle statement.)
•   All syntax should abide by The C Programming Language, 2nd Edition, Kernighan & Ritchie.
•   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.

$\endgroup$
11
  • 25
    $\begingroup$ This kind of question is excellent for the Programming Puzzles & Code Golf Stack Exchange. :) codegolf.stackexchange.com $\endgroup$
    – MichaelK
    Jun 25, 2016 at 14:37
  • 1
    $\begingroup$ what's wrong with the code you already have? $\endgroup$
    – JMP
    Jun 25, 2016 at 15:44
  • 1
    $\begingroup$ 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. $\endgroup$ Jun 25, 2016 at 15:47
  • 1
    $\begingroup$ 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). $\endgroup$
    – humn
    Jun 25, 2016 at 15:53
  • 3
    $\begingroup$ 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.) $\endgroup$
    – ais523
    Feb 19, 2017 at 1:13

5 Answers 5

7
+150
$\begingroup$

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.)

$\endgroup$
1
  • $\begingroup$ Comments are not for extended discussion; this conversation has been moved to chat. $\endgroup$ Sep 26, 2016 at 15:54
9
$\begingroup$

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.

$\endgroup$
4
  • 1
    $\begingroup$ 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 $\endgroup$
    – Dave
    Jun 25, 2016 at 17:40
  • 1
    $\begingroup$ Good point.  I considered for(int v=8; …, but when I realized that that was too modern, I dropped back and punted. $\endgroup$ Jun 25, 2016 at 17:44
  • $\begingroup$ No additional " quotation marks. Someone found a hole in this challenge! $\endgroup$
    – EKons
    Jun 26, 2016 at 10:43
  • $\begingroup$ 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 $\endgroup$
    – humn
    Jun 27, 2016 at 2:07
7
$\begingroup$

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

$\endgroup$
6
  • 2
    $\begingroup$ Clever!  It never occurred to me to add a } and a {.  P.S. I also count 24 characters. $\endgroup$ Jun 26, 2016 at 20:57
  • $\begingroup$ 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...) $\endgroup$
    – humn
    Jun 27, 2016 at 3:53
  • $\begingroup$ Corrected the count to 24. $\endgroup$ Jun 27, 2016 at 18:24
  • $\begingroup$ 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. $\endgroup$
    – humn
    Jun 27, 2016 at 19:46
  • 1
    $\begingroup$ > 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 ..." $\endgroup$ Jun 27, 2016 at 19:46
7
+200
$\begingroup$

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.

$\endgroup$
16
  • $\begingroup$ 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. $\endgroup$
    – humn
    Sep 20, 2016 at 17:48
  • $\begingroup$ I looked myself, but I didn't really find anything conclusive one way or the other. $\endgroup$
    – dcfyj
    Sep 20, 2016 at 17:49
  • $\begingroup$ 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 $\endgroup$
    – humn
    Sep 20, 2016 at 17:57
  • $\begingroup$ I figured it probably wasn't valid, thus the secondary answer. Nonetheless, I got my 20 ^^. $\endgroup$
    – dcfyj
    Sep 20, 2016 at 17:58
  • 1
    $\begingroup$ 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.” $\endgroup$ Sep 20, 2016 at 22:06
1
$\begingroup$

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

$\endgroup$
3
  • $\begingroup$ I am trying to reduce it below 19 characters... Nice question humn $\endgroup$
    – KSR
    Sep 22, 2016 at 10:43
  • 1
    $\begingroup$ The declaration of a variable inside for is not in K&R 2nd edition era C standards, it was added in C99. $\endgroup$
    – Arkku
    Sep 22, 2016 at 12:54
  • $\begingroup$ 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… $\endgroup$
    – Arkku
    Sep 22, 2016 at 13:28

Your Answer

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

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