public long piece_can_reach(int piece_index, int steps) {

    // Create piece bitboard
    long piece_bb = 1L << piece_index;
    int piece_type = getPieceType(piece_bb);
    int piece_colour = piece_type & 0x01;

    // All player pieces except the moving piece
    long friend_bb = colour_bb[piece_colour] & ~piece_bb;

    // Check if moving piece is saving a player piece from being captured
    // This piece can't contribute to good squares, since it will be captured
    // However, it can unfreeze the piece before it has moved!!!!
    int trap_num = trap_number[piece_index];
    if (trap_num != -1) {
      if ((TRAP[trap_num] & friend_bb) != 0) {
        if ((TOUCH_TRAP[trap_num] & colour_bb[piece_colour]) == piece_bb) {
          friend_bb ^= TRAP[trap_num];
        }
      }
    }

    // All squares the piece can occupy and not be frozen
    // Second term required for the however comment above
    long unfrozen_sq_bb = (touching_bb(friend_bb) |
      (touching_bb(colour_bb[player]) & piece_bb) |
      ~touching_bb(stronger_enemy_bb[piece_type]));

    // Check if the piece is frozen
    if ((unfrozen_sq_bb & piece_bb) == 0) {
      return piece_bb;
    }

    // Check trap squares, if no same coloured pieces touches then piece can't cross
    long bad_trap_bb = 0L;
    for (int i = 0; i < 4; i++) {
      if ((TOUCH_TRAP[i] & friend_bb) == 0) {
        bad_trap_bb |= TRAP[i];
      }
    }

    // All empty squares the piece can be on and not be frozen
    long good_sq_bb = unfrozen_sq_bb & empty_bb & ~bad_trap_bb;

    // Flood fill, to see what squares the piece can reach in required steps
    long reached_bb = piece_bb;
    for (int i = 1; i < steps; i++) {
      reached_bb |= touching_bb(reached_bb, piece_type) & good_sq_bb;
    }

    // On final step, any empty square, not on an exposed trap, will do
    reached_bb |= touching_bb(reached_bb, piece_type) & empty_bb & ~bad_trap_bb;

    // Set of squares reachable in desired steps
    return reached_bb;

  }