What are my chess moves?
JavaScript (ES6), 256 ... 229 227 bytes

Takes input as two strings (p, s), where p is the case-insensitive name of the piece and s is the source square. Returns a space-separated list of destination squares.

f=(p,s,i=128)=&gt;i--?f(p,s,i)+([x=255,x&lt;&lt;8,2,x,195,60][P=(I=parseInt)(p,32)*5&amp;7]&gt;&gt;i/8&amp;((d=i%8)&lt;(S=(x=I(s,18)-181)/18|x%18*16,P&gt;2?8:P&lt;2|S&gt;23||2))&amp;!((S+=I('gfh1eivx'[i&gt;&gt;4],36)*(i&amp;8?d+1:~d))&amp;136)?'abcdefgh'[S&amp;7]+(S+16&gt;&gt;4)+' ':''):''


How it works

Piece name decoding

The name of the piece p is converted to an integer P by parsing it in base 32, multiplying the result by 5 and isolating the 3 least significant bits: parseInt(p, 32) * 5 &amp; 7

 Piece    | As base 32 |        * 5 | &amp; 7
----------+------------+------------+----
 "king"   |     674544 |    3372720 |  0
 "knight" |  695812669 | 3479063345 |  1
 "pawn"   |        810 |       4050 |  2    NB: 'pawn' is parsed as 'pa', because 'w'
 "queen"  |   28260823 |  141304115 |  3        is not a valid character in base 32
 "rook"   |     910100 |    4550500 |  4
 "bishop" |  388908825 | 1944544125 |  5


In addition to being a perfect hash, a good thing about this formula is that all sliding pieces (Queen, Rook and Bishop) appear at the end of the list, which allows to identify them with a simple P &gt; 2.

Source square decoding

The source square s is converted to an integer S by parsing it in base 18 and converting the result to 0x88 coordinates.

That leads to the following board representation:

     a    b    c    d    e    f    g    h
8  0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77
7  0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67
6  0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57
5  0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47
4  0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
3  0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
2  0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
1  0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07


Directions encoding

There are 16 possible directions: 4 along ranks and files, 4 along diagonals and 8 for the knights.

As hexadecimal:                     As decimal:

      +0x1F       +0x21                    +31         +33
+0x0E +0x0F +0x10 +0x11 +0x12        +14   +15   +16   +17   +18
      -0x01 [SRC] +0x01                     -1  [SRC]   +1
-0x12 -0x11 -0x10 -0x0F -0x0E        -18   -17   -16   -15   -14
      -0x21       -0x1F                    -33         -31


Therefore, the list of directions that a piece can move towards can be encoded as a 16-bit bitmask.

Bit:    |   F   E   D   C   B   A   9   8   7   6   5   4   3   2   1   0 | As
Vector: | +33 -33 +31 -31 +18 -18 +14 -14  +1  -1 +17 -17 +15 -15 +16 -16 | decimal
--------+-----------------------------------------------------------------+--------
King    |   0   0   0   0   0   0   0   0   1   1   1   1   1   1   1   1 | 255
Knight  |   1   1   1   1   1   1   1   1   0   0   0   0   0   0   0   0 | 65280
Pawn    |   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   0 | 2
Queen   |   0   0   0   0   0   0   0   0   1   1   1   1   1   1   1   1 | 255
Rook    |   0   0   0   0   0   0   0   0   1   1   0   0   0   0   1   1 | 195
Bishop  |   0   0   0   0   0   0   0   0   0   0   1   1   1   1   0   0 | 60


The absolute values of the direction vectors can be stored in base 36:

[16, 15, 17, 1, 14, 18, 31, 33][n] &lt;==&gt; parseInt('gfh1eivx'[n], 36)


Formatted and commented

f = (p, s, i = 128) =&gt;                     // given a piece p, a square s and a counter i
  i-- ?                                    // if i is &gt;= 0:
    f(p, s, i) + (                         //   do a recursive call to f()
      [ x = 255, x &lt;&lt; 8, 2, x, 195, 60 ][  //   take the direction bitmask for:
        P = (I = parseInt)(p, 32) * 5 &amp; 7  //   P = piece index in [0 .. 5]
      ] &gt;&gt; i / 8 &amp; (                       //   and test the bit for the current direction
        (d = i % 8) &lt; (                    //   d = current move distance - 1
          S = (x = I(s, 18) - 181) / 18 |  //   S = source square in
              x % 18 * 16,                 //       0x88 representation
          P &gt; 2 ? 8 : P &lt; 2 | S &gt; 23 || 2  //   compare d with the maximum move range for
        )                                  //   this piece
      ) ?                                  //   if the above test passes:
        (                                  //     we add to S:
          S += I(                          //       the absolute value of the vector of
            'gfh1eivx'[i &gt;&gt; 4], 36         //       the current direction,
          ) *                              //       multiplied by
          (i &amp; 8 ? d + 1 : ~d)             //       the move distance with the vector sign
        ) &amp; 136 ?                          //     if the result AND'd with 0x88 is not null:
          ''                               //       this is an invalid destination square
        :                                  //     else:
          'abcdefgh'[S &amp; 7] +              //       it is valid: convert it back to ASCII
          (S + 16 &gt;&gt; 4) + ' '              //       and append a space separator
      :                                    //   else:
        ''                                 //     this is an invalid move
    )                                      //   end of this iteration
  :                                        // else:
    ''                                     //   stop recursion


Test cases



f=(p,s,i=128)=&gt;i--?f(p,s,i)+([x=255,x&lt;&lt;8,2,x,195,60][P=(I=parseInt)(p,32)*5&amp;7]&gt;&gt;i/8&amp;((d=i%8)&lt;(S=(x=I(s,18)-181)/18|x%18*16,P&gt;2?8:P&lt;2|S&gt;23||2))&amp;!((S+=I('gfh1eivx'[i&gt;&gt;4],36)*(i&amp;8?d+1:~d))&amp;136)?'abcdefgh'[S&amp;7]+(S+16&gt;&gt;4)+' ':''):''

console.log(f('Rook',   'a8'));
console.log(f('Pawn',   'a2'));
console.log(f('Pawn',   'a3'));
console.log(f('Knight', 'a1'));
console.log(f('Bishop', 'h1'));
console.log(f('King',   'b2'));
console.log(f('Queen',  'h1'));