Flag Semaphore Encoder
Python, 244 238 233 232
e='abhioptuwycdjmnsqxzfgvklebr'
for w in raw_input().split():
for i in 0,3,6,9:print' '.join(''.join((' '+'\|/-O-/|\ '[j])[`j`in'4'+'6736031025071568328578162735'[e.find(c):][:2]]for j in range(i,9)[:3])for c in w if c.lower()in e)
This uses a favorite trick of mine: single-track encoding. I've labeled the semaphore bits (sbits)
\|/ 012
- - -> 3 5
/|\ 678
to obtain the following chart of which sbits occur for which letter:
0: ciotuy
1: djkptv
2: elquwx
3: bhopqrs
5: fjmrwyz
6: ahiklmn
7: abcdefg
8: gnsvxz
each letter occurs exactly twice in the chart, since the signalman has two arms. Then, I view this as a graph on the letters a-z, with edges between letters sharing sbits, with the edges labeled according to the shared sbit. Ideally, I'd find a Hamilton path through this graph, such that subsequent edges don't have the same label. No such paths exist... so you'll note that the variable e
contains the letter b
twice.
With my nearly-Hamilton path e
, I construct an array d
of sbit labels used in the traversal of e
. Then, to figure out where to put her arms, the signalman need only find the desired letter in the following handy chart
abhioptuwycdjmnsqxzfgvklebr
6736031025071568328578162735
whence her arms go in the position directly below, and below&right of the letter.
Perl, 282 264 251 247 245 243 241 240 236 233 229 227 220 218 216 214 characters
$_=lc<>;map{y/a-z//cd;y/a-z/`HABDP\xc0(!\x12"$0\xa0\t\n\f\30\x88\3\5\x82\24\x84\21\x90/;@a=($/)x4;map{$s=ord;$a[$_/3].=substr" \\|/-O-/|\\",$_==4||$s>>$_-($_>4)&1?$_+1:0,1for 0..8;$_.=" "for@a}split//;print@a}split
With some prettifying line breaks:
$_=lc<>;
map{
y/a-z//cd;
y/a-z/`HABDP\xc0(!\x12"$0\xa0\t\n\f\30\x88\3\5\x82\24\x84\21\x90/;
@a=($/)x4;
map{
$s=ord;
$a[$_/3].=substr" \\|/-O-/|\\",$_==4||$s>>$_-($_>4)&1?$_+1:0,1for 0..8;
$_.=" "for@a
}split//;
print@a}split
It's taken me a while to get this working (my first attempt at a Perl answer). It's based on a similar idea to a lot of the other answers. Each flag can be in one of 8 positions, there are two flags, and the two flags can't ever be in the same position. This means I can encode the position of both flags in one byte - which also means I can translate directly from a character to its encoding using Perl's y///
function (operator?). So:-
a = 01100000 96 = `
b = 01001000 72 = H
c = 01000001 65 = A
d = 01000010 66 = B
e = 01000100 68 = D
f = 01010000 80 = P
etc...
Therefore:
y/a-z/`HABDP..../;
I've escaped a fair few of the characters which are outside the normal used range to make the copying and pasting of the program easy - but I'm fairly sure I could write a program to replace the escape codes with the characters themselves saving me roughly 30 characters.
Scala, 272 characters
println(readLine.filter(c=>c.isLetter||c==' ').toLowerCase.split(" ").map{_.map(q=>(" O "/:("^@a,6Tr?W*+5Sq9(2Pn%/-47MU"(q-'a')-27+""))((g,x)=>g.updated(x-'0',"\\|/-O-/|\\"(x-'0'))).grouped(3).toList).transpose.map(_.mkString(" ")).mkString("\n")}.mkString("\n\n"))
Ungolfed (well, less-golfed):
println(
readLine.filter(c => c.isLetter || c==' ').
toLowerCase.
split(" ").
map{ s =>
val lookup = "^@a,6Tr?W*+5Sq9(2Pn%/-47MU".map(c => (c-27).toString)
s.map(q =>
(" O " /: lookup(q-'a')){(g,x) =>
g.updated(x-'0', "\\|/-O-/|\\"(x-'0'))
}.grouped(3).toList
).transpose.map(_.mkString(" ")).mkString("\n")
}.mkString("\n\n")
)