Consider the following (hypothetical) schema. Would you add a surrogate key to the "chessboard" table ? The values for {xxx,yyy,pc} are constrained, either by "restricted" domains, or by the PK+FK constraints. 
In which cases would adding a surrogate key (for {xxx,yyy} help?
(additional constraints (such as: no more than one King per Color ...) would be necessary for a real chess game, (but part of) the business rules (such as valid moves ...) would be handled by the "application logic" anyway)
-- this is Postgres-specific:
-- create a schema to play in
DROP SCHEMA chess CASCADE ;
CREATE SCHEMA chess ;
SET search_path='chess' ;
        -- Domain with only values A-H to three allowed.
CREATE DOMAIN chess_column
        AS CHAR(1) NOT NULL
        check (value >= 'A' AND value <= 'H')
        ;
        -- Domain with only values 1-8 allowed.
CREATE DOMAIN chess_row
        AS INTEGER NOT NULL
        check (value >= 1 AND value <= 8)
        ;
        -- Table with only valid pieces
CREATE TABLE chess_piece
        ( id INTEGER NOT NULL PRIMARY KEY
        , pname varchar
        ) ;
INSERT INTO chess_piece(id,pname) VALUES
 ( -6, 'Black King' ) , ( -5, 'Black Queen' ) , ( -4, 'Black Rook' )
, ( -3, 'Black Bishop' ) , ( -2, 'Black Knight' ) , ( -1, 'Black Pawn' )
, ( 6, 'White King' ) , ( 5, 'White Queen' ) , ( 4, 'White Rook' )
, ( 3, 'White Bishop' ) , ( 2, 'White Knight' ) , ( 1, 'White Pawn' )
        ;
CREATE TABLE chessboard
        ( xxx chess_column
        , yyy chess_row
        , pc INTEGER NOT NULL REFERENCES chess_piece(id)
        , PRIMARY KEY (xxx,yyy)
        );
        -- Too lazy to enter the entire board
        -- ; only put a White Pawn at E2
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'E', 2, p.id
FROM chess_piece p
WHERE p.pname = 'White Pawn';
        ;
        -- Shift the pawn
UPDATE chessboard b
SET yyy = 4
FROM chess_piece p
WHERE b.pc = p.id
AND p.pname = 'White Pawn';
AND b.xxx = 'E' AND b.yyy = 2
        ;
        -- Try to put a piece outside the board
\echo Try put a piece outside the board
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'I', 2, p.id
FROM chess_piece p
WHERE p.pname = 'Black Pawn';
        ;
        -- add a non-existing piece
\echo add a non-existing piece
INSERT INTO chessboard(xxx,yyy,pc)
VALUES( 'H', 1, 42)
        ;
        -- Position is already occupied
\echo Position is already occupied
INSERT INTO chessboard(xxx,yyy,pc)
SELECT 'E', 4, p.id
FROM chess_piece p
WHERE p.pname = 'Black Pawn';
        ;