Tic-Tac-Toe and Chess, with fewest [distinct] characters
APL (Dyalog Unicode), 369 characters, score 28

{Q←(QQ←⍴⍵)[1]
R←∨/¨⍵=⊂'RBQK'
B←({⍵(⍵[↑(⍳Q),¨¨⊂1--Q-⍳Q])}↑(⍳Q)=⊂⍳Q),{⍵,{⍵[{⍵[(1--1)1]}¨⍳QQ]}¨⍵}(⊂QQ)⍴¨(⍳Q)=⊂⍳Q
K←(Q-1)={∨/1↑⍴{(,⍵)/,⍳⍴⍵}⍵}¨B×⊂R
1-∨/K:1-1
K←↑∨/K/B
BB←{(,⍵)/,⍳⍴⍵}K×1-R
R←↑∨/BB-B←{(,⍵)/,⍳⍴⍵}R×1-K
1-⍴B:⍵[BB]=1↑''
BB←(1-∨/¨'RBQK'=⊂⍵[(,K)/,⍳⍴K])/'RBQK'
'K'=BB:×/∨/¨(⍳1--1)=⊂R∨-R
1-∨/(1-(⍳1--1)='RB'⍳BB)×(=/,{∨/1-×⍵})R∨-R:1-1
×/(1↑'')=⍵[B--(×⊂R)×⍳-1-∨/R]}↑⍞⍞⍞⍞

Try it online!
Character statistics:
 -  1  B  )  (  ⍵  /  Q  ⍳  R  '  ∨  LF   K  ,  =  ←  }  { ⊂ × ¨ ⍴ ↑ ] [ ⍞ :
27 26 22 20 20 19 19 18 15 15 14 12  12  12 12 11 10 10 10 9 9 9 8 8 7 7 4 4
chars 28

Decisions made during optimizing the score:

Boolean guard : is needed for early returns from a dfn {}. Either LF (\n) or a statement separator character ⋄ cannot be removed as a side effect.
I didn't try to avoid four letters RBQK as avoiding it requires at least ⎕A and the code would get messy.
Removed composition ∘, reflex/flip ⍨, and self ⊢ in favor of dfns and explicitly writing down arguments with parentheses.
Removed ≢ (tally) in favor of ⍴ (shape/reshape), as tally = first element of shape, and reshape is unavoidable.
Removed ⍉ (transpose) and ⌽ (reverse/rotate) in favor of explicit indexing [] combined with index generator ⍳. Although there are one-char functions to do the indexing (⌷, ⊃), none is suitable for transpose operation.
Removed ⊃ (first/pick) in favor of ↑ (mix/take), as take is unavoidable and indexing+mix can simulate both uses of ⊃.
Removed ∧ (logical and) in favor of × (times), and | (abs/mod) by using the workaround x∨-x for |x (abs) and explicit membership ∊ (which was removed later) for x|y (mod). ⊤ was also removed that way.
Removed ∘.f in favor of f⊂ or f¨⊂. Similar trick was used to simulate ∊ (membership) and ~ (set minus): x∊y → ∨/¨x=⊂y, x~y → (1-∨/¨x=⊂y)/x
Removed ⍸ (extract indices of ones) with the workaround (,x)/,⍳⍴x.
Removed zero with 1-1, four by extracting from ⍴⍵, and + with --.
Removing blanks in plain code is easy, but this code has ' '. I avoided it with 1↑'', which &quot;overtakes&quot; length 1 from an empty string and gives a single blank. (It is a slightly different thing from the literal ' ', but they are compatible in most cases.)

Ungolfed with comments
{
  ⍝ 4×4 boolean matrix where 1 means a white piece
  whites←⍵∊'RBKQ'
  ⍝ one matrix per a winning position; roughly looks like
  ⍝ 1 0 0 0 ... 1 1 1 1 ... 1 0 0 0
  ⍝ 1 0 0 0     0 0 0 0     0 1 0 0
  ⍝ 1 0 0 0     0 0 0 0     0 0 1 0
  ⍝ 1 0 0 0     0 0 0 0     0 0 0 1
  masks←((⊂,⊂∘⌽)∘.=⍨⍳4),(⊢,⍉¨)(⍳4)⌽¨⊂4 4⍴4↑1
  ⍝ 1 if the white is about to win in that specific winning position
  filter←3=masks{≢⍸⍺∧⍵}¨⊂whites
  ⍝ No three-in-a-row: return false
  ~∨/filter:0

  ⍝ fetch the mask closest to white's winning
  mask←(⍸filter)⊃masks
  ⍝ coordinates of misplaced piece (from) and empty position (to)
  from←⍸whites&gt;mask
  to←⍸whites&lt;mask
  ⍝ No from: the remaining place must be empty
  ~≢from:' '=⍵[to]

  ⍝ get the type of the piece to move
  type←'RBKQ'~⍵[⍸mask]
  ⍝ Knight: true if 1×2 steps away, ignoring any obstacles
  'K'=type:∧/1 2∊|⊃from-to
  ⍝ two booleans indicating if it can move in diagonals (BQ) or
  ⍝ cardinal directions (RQ)
  diag cross←0 2⊤⊃'RB'⍳type
  ⍝ two booleans indicating if the direction to move is actually
  ⍝ diagonal or cardinal
  isdiag←=/|⊃from-to
  iscross←0∊|⊃from-to
  ⍝ Not aligned with the piece to move: return false
  diag cross⍱.∧isdiag iscross:0
  ⍝ If aligned, true if all cells between from and to are blanks
  ∧/' '=¯1↓⍵[from+(×v)×⍳⌈/⊃|v←to-from]
}↑{⍞}¨⍳4  ⍝ Take 4 lines of input, format as matrix and pass to function