4

Please answer with the shortest possible source code for a program that converts an arbitrary plaintext to its corresponding ciphertext, following the sample input and output I have given below. Bonus points* for the least CPU time or the least amount of memory used.

Example 1:

Plaintext: The quick brown fox jumps over the lazy dog. Supercalifragilisticexpialidocious!

Ciphertext: eTh kiquc nobrw xfo smjup rvoe eth yalz .odg !uioiapeislgriarpSueclfaiitcxildcos

Example 2:

Plaintext: 123 1234 12345 123456 1234567 12345678 123456789

Ciphertext: 312 4213 53124 642135 7531246 86421357 975312468

Rules:

  1. Punctuation is defined to be included with the word it is closest to.
  2. The center of a word is defined to be ceiling((strlen(word)+1)/2).
  3. Whitespace is ignored (or collapsed).
  4. Odd words move to the right first. Even words move to the left first.

You can think of it as reading every other character backwards (starting from the end of the word), followed by the remaining characters forwards. Corporation => XoXpXrXtXoX => niaorCoprto.

Thank you to those who pointed out the inconsistency in my description. This has lead many of you down the wrong path, which I apologize for. Rule #4 should clear things up.

*Bonus points will only be awarded if Jeff Atwood decides to do so. Since I haven't checked with him, the chances are slim. Sorry.

Will Bickford
  • 5,381
  • 2
  • 30
  • 45
  • 2
    I/O, standalone code to read/write a variable, function, ? – hobbs Sep 16 '09 at 01:54
  • 1
    "lazy" is miscoded in the ciphertext example, it should be "zlay", not "yalz". – Amber Sep 16 '09 at 02:02
  • My first solution output zlay as well. After comparing with the spec, I thought maybe I just misunderstood the spec, but perhaps you're right. – recursive Sep 16 '09 at 02:19
  • No that is what my program does and it is defined to be the gold standard because I wrote it like 7 years ago. – Will Bickford Sep 16 '09 at 02:46
  • Your program is inconsistent then - `quick => kiquc` goes right from q to u, but `over => rvoe` goes left from o to v. – Amber Sep 16 '09 at 03:31
  • 1
    @Dav - I think his version does the reverse: `quick => kiquc` starts with `k` first, then `c` last, then `i` second, etc. while `over => rvoe` starts with `r` first, then `e` last, then `v` second, then `o` second to last. Thus, consistency. – Chris Lutz Sep 16 '09 at 03:49
  • 1
    I see. In that case the problem statement should probably define the transformation differently - namely, it should describe how the ciphertext is generated instead of describing how it is read (or otherwise, define how the ciphertext is read in terms of reading backwards for each word...). – Amber Sep 16 '09 at 04:11
  • Yes I'm sorry for the poor explanation it has been a while since I wrote the algorithm. – Will Bickford Sep 16 '09 at 21:31

10 Answers10

7

Python, 50 characters

For input in i:

' '.join(x[::-2]+x[len(x)%2::2]for x in i.split())

Alternate version that handles its own IO:

print ' '.join(x[::-2]+x[len(x)%2::2]for x in raw_input().split())

A total of 66 characters if including whitespace. (Technically, the print could be omitted if running from a command line, since the evaluated value of the code is displayed as output by default.)


Alternate version using reduce:

' '.join(reduce(lambda x,y:y+x[::-1],x) for x in i.split())

59 characters.

Original version (both even and odd go right first) for an input in i:

' '.join(x[::2][::-1]+x[1::2]for x in i.split())

48 characters including whitespace.

Another alternate version which (while slightly longer) is slightly more efficient:

' '.join(x[len(x)%2-2::-2]+x[1::2]for x in i.split())

(53 characters)

Amber
  • 507,862
  • 82
  • 626
  • 550
4

J, 58 characters

>,&.>/({~(,~(>:@+:@i.@-@<.,+:@i.@>.)@-:)@<:@#)&.><;.2,&' '
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 5
    Reading all these Code Golfs, I have come to hate J. Knowing that there is this language that can do so much, with so little. And what I hate is that I have no idea what this means. It looks like a bunch of mutated smilies to me :P – Mike Cooper Sep 16 '09 at 04:27
  • 5
    I think every SO golfer needs to download a J interpreter and verify these J answers. There are so many, and I know some of them are just people writing smileys. – Chris Lutz Sep 16 '09 at 04:30
  • Obviously, it's not actually a program for the question but instead a secretly coded message to other J programmers that laughs at all the people who don't know J. Obviously. – Amber Sep 16 '09 at 05:33
  • I actually haven't seen any dishonest J answers yet. (Chris may be more active on SO than I.) It's true, though, that there's not many people who double-check these... – ephemient Sep 16 '09 at 13:51
  • Heh. Python's list comprehensions and slice notation happen to come in handy this time. – Amber Sep 17 '09 at 00:34
  • I can't say I'm skilled at J, but I agree: Python's slice notation is very useful here. The `(>:@+:@i.@-@<.,+:@i.@>.)@-:` bit in the middle tries to emulate it, but it's rather unexpectedly verbose in J. – ephemient Sep 17 '09 at 02:35
4

Haskell, 64 characters

unwords.map(map snd.sort.zip(zipWith(*)[0..]$cycle[-1,1])).words

Well, okay, 76 if you add in the requisite "import List".

ephemient
  • 198,619
  • 38
  • 280
  • 391
3

Python - 69 chars

(including whitespace and linebreaks)

This handles all I/O.

for w in raw_input().split():
 o=""
 for c in w:o=c+o[::-1]
 print o,
recursive
  • 83,943
  • 34
  • 151
  • 241
1

Perl, 78 characters

For input in $_. If that's not acceptable, add six characters for either $_=<>; or $_=$s; at the beginning. The newline is for readability only.

for(split){$i=length;print substr$_,$i--,1,''while$i-->0;
print"$_ ";}print $/
hobbs
  • 223,387
  • 19
  • 210
  • 288
  • I would just add 10 characters for `perl -ne''` - it's not that much more, and we could shave a few off by using 5.10 (change `print $/` to `say""` or at least remove the space between `print` and the variable, perhaps rewrite to condense two `--` into `-=2` and see if you can't shrink it a character, remove the `;` before the ending bracket of the loop). – Chris Lutz Sep 16 '09 at 04:38
  • Also, changing the `while()` loop to a C-style `for()` loop might (might) shave a few characters. Haven't tried it. – Chris Lutz Sep 16 '09 at 04:40
  • I didn't put maximum effort into this one; I've been working on some real-world code for a change. I'm not sure whether the `--` can be eliminated, but and given the discussion above I'm not even sure whether I'm on spec. If you want this entry, go ahead and edit and you can have it :) – hobbs Sep 16 '09 at 05:56
1

Lua

130 char function, 147 char functioning program

Lua doesn't get enough love in code golf -- maybe because it's hard to write a short program when you have long keywords like function/end, if/then/end, etc.

First I write the function in a verbose manner with explanations, then I rewrite it as a compressed, standalone function, then I call that function on the single argument specified at the command line.

I had to format the code with <pre></pre> tags because Markdown does a horrible job of formatting Lua.

Technically you could get a smaller running program by inlining the function, but it's more modular this way :)

t = "The quick brown fox jumps over the lazy dog. Supercalifragilisticexpialidocious!"
T = t:gsub("%S+", -- for each word in t...
                  function(w) -- argument: current word in t
                    W = "" -- initialize new Word
                    for i = 1,#w do -- iterate over each character in word
                        c = w:sub(i,i) -- extract current character
                        -- determine whether letter goes on right or left end
                        W = (#w % 2 ~= i % 2) and W .. c or c .. W
                    end
                    return W -- swap word in t with inverted Word
                  end)


-- code-golf unit test
assert(T == "eTh kiquc nobrw xfo smjup rvoe eth yalz .odg !uioiapeislgriarpSueclfaiitcxildcos")

-- need to assign to a variable and return it,
-- because gsub returns a pair and we only want the first element
f=function(s)c=s:gsub("%S+",function(w)W=""for i=1,#w do c=w:sub(i,i)W=(#w%2~=i%2)and W ..c or c ..W end return W end)return c end
--       1         2         3         4         5         6         7         8         9        10        11        12        13
--34567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
-- 130 chars, compressed and written as a proper function

print(f(arg[1]))
--34567890123456
-- 16 (+1 whitespace needed) chars to make it a functioning Lua program, 
-- operating on command line argument

Output:

$ lua insideout.lua 'The quick brown fox jumps over the lazy dog. Supercalifragilisticexpialidocious!'
eTh kiquc nobrw xfo smjup rvoe eth yalz .odg !uioiapeislgriarpSueclfaiitcxildcos

I'm still pretty new at Lua so I'd like to see a shorter solution if there is one.


For a minimal cipher on all args to stdin, we can do 111 chars:
for _,w in ipairs(arg)do W=""for i=1,#w do c=w:sub(i,i)W=(#w%2~=i%2)and W ..c or c ..W end io.write(W ..' ')end

But this approach does output a trailing space like some of the other solutions.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
1

C, 140 characters

Nicely formatted:

main(c, v)
  char **v;
{
  for( ; *++v; )
  {
    char *e = *v + strlen(*v), *x;
    for(x = e-1; x >= *v; x -= 2)
      putchar(*x);
    for(x = *v + (x < *v-1); x < e; x += 2)
      putchar(*x);
    putchar(' ');
  }
}

Compressed:

main(c,v)char**v;{for(;*++v;){char*e=*v+strlen(*v),*x;for(x=e-1;x>=*v;x-=2)putchar(*x);for(x=*v+(x<*v-1);x<e;x+=2)putchar(*x);putchar(32);}}
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
0

For an input in s:

f=lambda t,r="":t and f(t[1:],len(t)&1and t[0]+r or r+t[0])or r
" ".join(map(f,s.split()))

Python, 90 characters including whitespace.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
0

Bash - 133, assuming input is in $w variable

Pretty

for x in $w; do 
    z="";
    for l in `echo $x|sed 's/\(.\)/ \1/g'`; do
        if ((${#z}%2)); then
            z=$z$l;
        else
            z=$l$z;
        fi;
    done;
    echo -n "$z ";
done;
echo

Compressed

for x in $w;do z="";for l in `echo $x|sed 's/\(.\)/ \1/g'`;do if ((${#z}%2));then z=$z$l;else z=$l$z;fi;done;echo -n "$z ";done;echo

Ok, so it outputs a trailing space.

Shizzmo
  • 16,231
  • 3
  • 23
  • 15
0

TCL

125 characters

set s set f foreach l {}
$f w [gets stdin] {$s r {}
$f c [split $w {}] {$s r $c[string reverse $r]}
$s l "$l $r"}
puts $l
Community
  • 1
  • 1
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304