RSS LJ

February 9, 2004

Random silly puzzle ()

by fluffy at 8:57 PM
So, the friend who hosts this site for me popped online and gave me a little code snippet:
rc(char*ni){char*n=ni;while(n&&*n){if(*n>='A'&&*n<='Z'){*n+=32;if(*(n+1)){*(n+1 )-=32;return;}else{*ni-=32;}}n++;}}main(int c,char**v){if(c<2)exit();while(1){printf("%s ",v[1]);rc(v[1]);}}
Basically, compile it and run it with something like "./a.out Foobar" and it'll output the string repeatedly, rotating the capitalization to the right. (With the caveat that it doesn't work with more than one capital letter.)

But it seemed rather bloated to me, so I rewrote it...

main(int c,char**v){char*m,q;v++;while(c-1)for(m=*v; q=*m;)(q==(q&95))?(*m++)^=32,*(*m?m:*v)^=32:m++,puts(*v);}
which was nice and all, but it still seemed a bit big, and now also couldn't handle spaces.

Then I had another insight which led to shrinking it further:

main(int c,char**v){char*m,q;v++;while(c-1)for(m=*v; q=*m;*m++|=32,*(*m?m:*v)^=~q&32)puts(*v);}
so now it was at a size I could be proud of. But it still couldn't handle more than one capital letter, which led me to think about a totally different solution:
main(int c,char**v){char*m,q;v++;while(c-1)for(puts(m=*v),q=0;q^=~*m&32,*m; *m++^=q,*(*m?m:*v)^=q);}
which was great, since now it could handle strings with more than one capital letter, but it still died with spaces. Unfortunately, fixing that required adding a bunch of characters, making it bloated again:
main(int c,char**v){char*m,q;v++;while(c-1)for(puts(m=*v),q=0;q^=~*m&32,*m;*m^=(*m^q?q:0),m++,*(*m?m: *v)^=((*m^q)?q:0));}
(there's an easy way to trim two characters off but it makes the behavior technically undefined, even if it works in gcc).

Can anyone shorten this further? (For bonus points, make it handle characters other than [A-Za-z ] correctly too...)

Comments

#1860 celeriac (unregistered) 02/10/2004 12:12 am Ha!
Handling multiple caps but no spaces:

x(char*a){*a?x(a+1),*a^=32&(*a^*(a-1)):0;}main(int c,char**v){while(c-1)puts(v[1]),x(v[1]+1);}


Handling spaces too:

x(a,p)char*a,*p;{*a^32?*a?x(a+1,a),*a^=32&(*a^*p):0:x(a+1,p);}main(int c,char**v){while(c-1)puts(v[1]),x(v[1]+1,v[1]);}
#1861 02/10/2004 12:26 am
Oh wow. I have never seen K&R syntax used to such evil benefit before. (Though it doesn't seem to be useful for my code, since main(int c,char**v) is the same length as main(c,v)char**v,c;)

Hm, and I hadn't considered that "v++;" didn't actually cancel out just using v[1] everywhere. It's too bad the ++ can't just be folded into one of the loops.

However, your algorithm doesn't work right, since you're not wrapping around. The capitalization needs to rotate, like "a.out Foobar" should produce


Foobar
fOobar
foObar
fooBar
foobAr
foobaR
Foobar
...


and I don't even see any attempt at handling that in the first one (which isn't that hard to decipher). Your codes produce:


Foobar
FOobar
FOObar
FOOBar
FOOBAr
FOOBAR
FOOBAR
...


So, your code might be compact, but it's incorrect. I give you an E for effort. Wink
#1864 ? (unregistered) 02/11/2004 09:09 am Another coupla chars
Highly illegal in most jurisdictions, but hey!

main(c,v,m,q)char**v,*m;{v++;while(*v)for(puts(m=*v),q=0;q^=~*m&32,*m; *m^=(*m^q?q:0),m++,*(*m?m:*v)^=((*m^q)?q:0));}
#1866 02/11/2004 10:44 am
Hm. Using *v for the loop condition kind of defeats the point of having the loop condition to begin with since *v won't necessarily be a NUL or even accessible memory if there's no parameter passed, but it's a cute savings which happens to work when it's given valid input. Nice to see the K&R hack applied, though, since I'd forgotten that K&R allows you to just omit the type for ints.

I just realized there's a way of saving two more characters without getting undeinfed behavior, and there were a lot of unnecessary parentheses. So, now it's down to:

main(c,v,m,q)char**v,*m;{v++;for(;;)for(puts(m=*v),q=0;q^=~*m&32,
*m;*m^=(*m^q?q:0),*(*++m?m:*v)^=*m^q?q:0);}
#1882 celeriac (unregistered) 02/11/2004 07:01 pm
If you're not using c at all, why define q? Two more chars right there.

I tried writing a single for loop and got two chars on top of that:


main(t,v,p)char**v,*p;{for(t=*(p=*++v);p-*v||puts(p);*++p||(t=*--p,p=*v))*p-32?t^=*p,*p^=t&32,t^=*p:0;}
#1883 02/11/2004 08:11 pm
Holy crap.
#1884 Anonymous 02/11/2004 08:15 pm
Whoa, that worked on my linux box, but does not work on the OSX ibook. Both machines are powerPC...WTF?
#1885 Zetawoof (unregistered) 02/11/2004 08:26 pm
Celeriac - that fails when the first letter is capitalized. Sorry.
#1887 celeriac (unregistered) 02/11/2004 09:17 pm
Arrgh. Always forgetting the obvious test cases.
#1888 celeriac (unregistered) 02/11/2004 10:10 pm
main(t,v,p)char**v,*p;{for(t=*(p=*++v);;*++p||(p=*v))*p-32?t^=*p,*p^=t&32,t^=*p:0,*v==p?
t=*p,puts(p):0;}


It doesn't like the first character to be a space, otherwise it should work, but will fail in an obvious way as soon as I hit "Post"Rolling Eyes
#1904 02/15/2004 02:48 am
This handles space as a first character, but doesn't wrap around quite correctly (it does something like foobaR → foobar → Foobar):

main(c,v,m,t)char**v,*m;{for(c=32&**++v;puts(m=*v);)while(*m){if(*m^32){t=*m&32;*m=*m&~32|c;c=t;}m++;}}


It can probably be shortened a bunch.
#1905 02/15/2004 03:01 am
main(c,v,m,t)char**v,*m;{for(c=32&**++v;puts(m=*v);)while(*m^32?t=*m&32,*m=*m&95|c,c=t:t,*++m);}