Convert degrees to one of the 32 points of the compass
Javascript 470 453 438 434 432 421 404
s=String;s.prototype.a=s.prototype.replace;var a=prompt()/11.25,a=a+0.5|0,b,k,c=a,d=c%8,c=c/8|0,e=["north","east","south","west"],f,g,h;f=e[c];g=e[(c+1)%4];h=f==e[0]|f==e[2]?f+g:g+f;b="1;1 by 2;1-C;C by 1;C;C by 2;2-C;2 by 1".split(";")[d].a(1,f).a(2,g).a("C",h);k=b.a(/north/g,"N").a(/east/g,"E").a(/south/g,"S").a(/west/g,"W").a(/by/g,"b").a(/[\s-]/g,"");b=b[0].toUpperCase()+b.slice(1);alert(b+" "+k)
You can copy this code to your console and execute it. It prompts you for the degrees input and outputs the result with alert();
Ungolfed Javascript can be found at this fiddle: http://jsfiddle.net/AezL3/11
Haskell 415 372 347 330 317 304 301C
Ended up converging on a solution like @VadimR's (and the symmetry's back!). Usage: h 219
outputs "Southwest by south SWbS"
d"N"="north"
d"S"="south"
d"E"="east"
d"W"="west"
d"b"=" by "
d"-"="-"
d(x:y)=d[x]++d y
e(x:y)=x:tail(d$x:y)
k 'N'='S'
k 'S'='N'
k 'E'='W'
k x=x
r="N NbE N-NE NEbN NE NEbE E-NE EbN E EbS E-SE SEbE SE SEbS S-SE SbE "
p=words$r++(map k r)
g x=p!!mod(round$x/11.25)32
h x=e(g x)++(filter(/='-')$' ':g x)
3 more chars gone, thanks @shiona.
Perl, 250 236 231 188 187
Edit: Some bytes off exploiting symmetry (as I've seen in @bazzargh solution)
+Edit: And some evil tricks...
+Edit: Back to where I started (working with list, not string), and exploiting more symmetry = 1 byte off and a whole lot uglier.
$_=((@_=(1,@_=qw(1b3 1-13 13b1 13 13b3 3-13 3b1),3,map{y/1/2/r}reverse@_)),map{y/312/421/r}@_)[int<>/11.25+.5];print ucfirst s/\w/(' by ',north,south,east,west)[$&]/ger,' ',y/1-4-/NSEW/dr
Pretty-printed:
$_=(
(@_=
(
1,
@_=qw(1b3 1-13 13b1 13 13b3 3-13 3b1),
3,
map{y/1/2/r}reverse@_
)
),map{y/312/421/r}@_
)[int<>/11.25+.5];
print ucfirst s/\w/(' by ',north,south,east,west)[$&]/ger,' ',y/1-4-/NSEW/dr
5.014 required because of r
modifier.