```ts
export function judgeLancer(board: string[], side: string, from: number[], to: number[]): string {
  if (board.length !== 7 || board.some(row => row.length !== 7)) {
    throw new Error("Invalid board size");
  }
  if (!["W", "B"].includes(side)) {
    throw new Error("Invalid side");
  }
  if (!Array.isArray(from) || !Array.isArray(to) || from.length !== 2 || to.length !== 2) {
    throw new Error("Invalid move format");
  }
  const [fromRow, fromCol] = from;
  const [toRow, toCol] = to;
  if (fromRow < 0 || fromRow >= 7 || fromCol < 0 || fromCol >= 7) {
    return "off_board";
  }
  if (toRow < 0 || toRow >= 7 || toCol < 0 || toCol >= 7) {
    return "off_board";
  }
  const validChars = new Set(["W", "B", "."]);
  for (const row of board) {
    for (const char of row) {
      if (!validChars.has(char)) {
        throw new Error("Invalid board character");
      }
    }
  }
  if (board[fromRow][fromCol] !== side) {
    return "no_piece";
  }
  const [rowDiff, colDiff] = [Math.abs(toRow - fromRow), Math.abs(toCol - fromCol)];
  if (!((rowDiff === 0 || colDiff === 0) && (rowDiff > 0 && rowDiff <= 3 || colDiff > 0 && colDiff <= 3))) {
    return "bad_line";
  }
  const stepRow = rowDiff > 0 ? Math.sign(toRow - fromRow) : 0;
  const stepCol = colDiff > 0 ? Math.sign(toCol - fromCol) : 0;
  for (let i = 1; i < Math.max(rowDiff, colDiff); i++) {
    if (board[fromRow + i * stepRow][fromCol + i * stepCol] !== ".") {
      return "blocked";
    }
  }
  if (board[toRow][toCol] === side) {
    return "own_piece";
  }
  const [adjacentRow, adjacentCol] = [
    Math.abs(toRow - fromRow) === 1 ? toRow : null,
    Math.abs(toCol - fromCol) === 1 ? toCol : null
  ];
  if (adjacentRow !== null && board[adjacentRow][fromCol] === side) {
    return "too_close";
  }
  if (adjacentCol !== null && board[fromRow][adjacentCol] === side) {
    return "too_close";
  }
  return "ok";
}
```