11
$\begingroup$

To illustrate a valid solution, here is a first non-optimized at all solution of value 79

cheese pieces on sudoku board

Let us fill a Peaceful Weighted Sudoku Grid with the maximum value with Chess pieces with the following rules:

  • The grid must contain a full set of chess pieces: both colors must have exactly one King, and at least one Queen, two Rooks, two Knights, two Bishops, and eight Pawns.
  • Neither side may be in checkmate.
  • No row, column, diagonal, or box may be completely filled.
  • No row, column, or box may contain two of the same piece of the same color, except pawns.
  • Each row, column, and box must contain at least one pawn of each color.
  • No diagonal may contain two Queens or Bishops of the same color.

Scoring

  • Every time a Queen appears you score 8 points
  • Every time a Rook appears you score 5 points
  • Every time a Bishop appears you score 3.3 points
  • Every time a Knight appears you score 2.7 points
  • Every time a Pawn appears you score 1 point

What is the maximum score you can reach? :D

Notes: there is no promotions for the pawns and you choose whether Blacks attack towards the north or if it is Whites :)

$\endgroup$
4
  • 4
    $\begingroup$ Are the corners of the board 1-cell diagonals? $\endgroup$ Commented Jul 4, 2025 at 11:40
  • $\begingroup$ @AxiomaticSystem, yes they are! $\endgroup$ Commented Jul 4, 2025 at 14:42
  • 3
    $\begingroup$ 1-cell diagonals don't exist. $\endgroup$ Commented Jul 7, 2025 at 6:57
  • $\begingroup$ @JKHA is there any better answer or any logic mistake as you did not accept any answer yet? $\endgroup$ Commented Jul 11, 2025 at 10:10

4 Answers 4

8
$\begingroup$

Here is my answer (this is OPTIMAL):

enter image description here

-- -- -- BQ BP -- WQ WP --
WQ BR WP BN WR BB BQ BP --
BQ BP WK WQ WP BR -- WR --
-- -- WR WP BR BQ BB WQ BP
BP BB BR -- WQ WR WP BK BQ
WP BQ WQ BP BN WB WR BR --
-- WP WB WR WN BP BR BQ WQ
-- WR BP BR BQ WQ WN -- WP
-- WQ BQ -- -- WP BP -- --

and the score is as stated above:

259.3

I have used

the CP-SAT solver simply.

Question Short answer
Why I have chosen CP-SAT over other solvers? Pure 0-1 decision model + many “at-most-one” rules → CP-SAT’s native territory. It bundles SAT learning, CP filtering and MILP, giving more speed than generic MILP or handcrafted backtracking.
Why is it (usually) the best tool here? • Handles all constraints with single-line primitives (AddAtMostOne, etc.)
• Exploits multi-core CPUs automatically
• No licence cost, yet :D world-class performance on all-integer puzzles like 9×9 Chess-Sudoku.
How do we know a solution is optimal? The solver tracks two numbers: best solution and a proven upper bound. When they coincide it returns status OPTIMAL—a mathematical certificate that no better arrangement exists.
Key tricks under the hood Branch-and-bound, constraint propagation, SAT-style conflict (no-good) learning, and parallel search -> all working together to prune the search tree aggressively.

Here is the python code, it takes 2 seconds to get the answer:

from ortools.sat.python import cp_model

def main():
n = 9
rows = range(n)
cols = range(n)

colors = ['W', 'B']
pieces = ['N', 'K', 'R', 'B', 'Q', 'P']
score  = dict(N=27, K=0, R=50, B=33, Q=80, P=10)   # ×10 for integers

lb = dict(N=2, K=1, R=2, B=2, Q=1, P=8)
ub = {p: 1 if p == 'K' else n * n for p in pieces}

m = cp_model.CpModel()

#------------------------------------------------------------------#
# Variables
#------------------------------------------------------------------#
V = {(c, p, i, j): m.NewBoolVar(f'{c}{p}_{i}_{j}')
     for c in colors for p in pieces for i in rows for j in cols}
E = {(i, j): m.NewBoolVar(f'E_{i}_{j}') for i in rows for j in cols}

# Exactly one status per square
for i in rows:
    for j in cols:
        m.Add(sum(V[c, p, i, j] for c in colors for p in pieces) + E[i, j] == 1)

#------------------------------------------------------------------#
# Global piece-count bounds
#------------------------------------------------------------------#
for c in colors:
    for p in pieces:
        total = sum(V[c, p, i, j] for i in rows for j in cols)
        m.Add(total >= lb[p])
        m.Add(total <= ub[p])

#------------------------------------------------------------------#
# ≥ 1 empty square constraints
#------------------------------------------------------------------#
for i in rows:                 # row
    m.Add(sum(E[i, j] for j in cols) >= 1)
for j in cols:                 # column
    m.Add(sum(E[i, j] for i in rows) >= 1)
for bi in range(0, n, 3):      # 3×3 box
    for bj in range(0, n, 3):
        m.Add(sum(E[i, j]
                  for i in range(bi, bi + 3)
                  for j in range(bj, bj + 3)) >= 1)

#------------------------------------------------------------------#
# ≥ 1 pawn of each colour per row, column, and box
#------------------------------------------------------------------#
for i in rows:                         # rows
    m.Add(sum(V['W', 'P', i, j] for j in cols) >= 1)
    m.Add(sum(V['B', 'P', i, j] for j in cols) >= 1)

for j in cols:                         # columns
    m.Add(sum(V['W', 'P', i, j] for i in rows) >= 1)
    m.Add(sum(V['B', 'P', i, j] for i in rows) >= 1)

for bi in range(0, n, 3):              # 3×3 boxes
    for bj in range(0, n, 3):
        m.Add(sum(V['W', 'P', i, j]
                  for i in range(bi, bi + 3)
                  for j in range(bj, bj + 3)) >= 1)
        m.Add(sum(V['B', 'P', i, j]
                  for i in range(bi, bi + 3)
                  for j in range(bj, bj + 3)) >= 1)

#------------------------------------------------------------------#
# ≥ 1 empty per diagonal
#------------------------------------------------------------------#
diags_pos = [[(i, j) for i in rows for j in cols if i + j == d]
             for d in range(0, 2 * n - 1)]
diags_neg = [[(i, j) for i in rows for j in cols if i - j == d]
             for d in range(1 - n, n)]
for diag in diags_pos + diags_neg:
    m.Add(sum(E[i, j] for i, j in diag) >= 1)

#------------------------------------------------------------------#
# “At-most-one” rules for non-pawn pieces
#------------------------------------------------------------------#
def at_most_one(vars_): m.AddAtMostOne(vars_)

nobox = [p for p in pieces if p != 'P']
for c in colors:
    for p in nobox:
        for i in rows:  # row
            at_most_one([V[c, p, i, j] for j in cols])
        for j in cols:  # column
            at_most_one([V[c, p, i, j] for i in rows])
        for bi in range(0, n, 3):      # box
            for bj in range(0, n, 3):
                at_most_one([V[c, p, i, j]
                             for i in range(bi, bi + 3)
                             for j in range(bj, bj + 3)])

# Bishop & queen diagonals (at-most-one)
for c in colors:
    for p in ['B', 'Q']:
        for diag in diags_pos + diags_neg:
            at_most_one([V[c, p, i, j] for i, j in diag])

#------------------------------------------------------------------#
# Objective
#------------------------------------------------------------------#
m.Maximize(sum(score[p] * V[c, p, i, j]
               for c in colors for p in pieces for i in rows for j in cols))

# Solve
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8
status = solver.Solve(m)

#------------------------------------------------------------------#
# Output
#------------------------------------------------------------------#
board = [['--' for _ in cols] for _ in rows]
for (c, p, i, j), var in V.items():
    if solver.BooleanValue(var):
        board[i][j] = c + p

print('\nBOARD:')
for i in rows:
    print(' '.join(board[i]))
print(f'\nTotal score = {solver.ObjectiveValue()/10:.1f}')

if status == cp_model.OPTIMAL:
    print('Status: OPTIMAL → proven best.')
elif status == cp_model.FEASIBLE:
    print('Status: FEASIBLE → good but not proven optimal.')
else:
    print('Status:', solver.StatusName(status))

if __name__ == '__main__':
main()

Please note that this code deliberately omits check and check-mate detection to keep things simple; an answer above includes a version that does handle check-mate.

Feel free to use my game link below if you'd like to explore a better solution or verify its validity (assuming I haven’t made a mistake somewhere!) Let me know if I have.

Weighted Sudoku Chess Gameplay

  • you can use text to get score and get errors
  • you can use PC to play interactively (unfortunately not very friendly with phone)
$\endgroup$
5
  • 2
    $\begingroup$ Simulated annualing. Is that something we pretend to do every year? $\endgroup$ Commented Jul 4, 2025 at 11:56
  • 1
    $\begingroup$ Worth nothing that although the code omits checkmate detection, there is no checkmate in your maximum and it's a valid answer. $\endgroup$ Commented Jul 6, 2025 at 11:59
  • $\begingroup$ Any reason not to also use AddAtLeastOne and AddExactlyOne? Any special settings used to get CP-SAT to solve in 2 seconds? CP-SAT takes much longer on my machine. $\endgroup$ Commented Jul 8, 2025 at 5:11
  • $\begingroup$ @RobPratt I used AddAtMostOne because each non-pawn piece is optional in a row/column/box but must never appear twice, and this helper encodes exactly that rule in the most propagation-friendly way in my opinion. $\endgroup$ Commented Jul 8, 2025 at 7:52
  • $\begingroup$ @RobPratt every variable is binary, I replaced all duplicate-piece rules with AddAtMostOne (which CP-SAT converts to a tight SWC encoding), and I let the solver run with its defaults plus multi-threading as 8, so presolve, conflict-driven search and rapid Large-Neighborhood-Search kicks in and the 9 × 9 instance falls in well under 2 to 10 seconds, maybe sometimes a little longer but I tried a couple of times, it took at most around 20 secs. $\endgroup$ Commented Jul 8, 2025 at 7:55
7
$\begingroup$

Using @Oray's tool, I've managed 279.3 as follows:

enter image description here

Note that despite the automated checker, there is no error: if we specify that black attacks to the north, as permitted by the question, there is no check. In any case the question only excludes checkmate, and white can easily escape check.

Methodology: Mostly trial and error :-) I was looking for a solution with the maximum 18 queens and 18 rooks, managed to find one and with some juggling squeeze in the required pieces and an extra bishop.

$\endgroup$
6
  • $\begingroup$ great answer, it will take some time to implement to movements of white and black directions and also for checkmate situations, so I will not able to fix the checkmate part to be honest, I wish I would though. $\endgroup$ Commented Jul 4, 2025 at 14:42
  • $\begingroup$ Note that the corners are considered 1-cell diagonals and hence must be empty. $\endgroup$ Commented Jul 4, 2025 at 14:54
  • $\begingroup$ @RobPratt that wasn't stated at the time I posted, and frankly I think it's a rather silly interpretation. Not going to take the time to redo it (especially since you've already got a maximum), this can stand as the current best answer to the question as it was phrased at the time. $\endgroup$ Commented Jul 4, 2025 at 14:59
  • 1
    $\begingroup$ @user111403 OK, without 1-cell diagonals, an upper bound is 279.3, so your solution is optimal under those rules. $\endgroup$ Commented Jul 6, 2025 at 15:12
  • 1
    $\begingroup$ @EgorHans I agree. On the other hand the OP is free to state a rule that "the corners must be empty", which is what it amounts to, but I view that as an edit to the question invalidating existing answers, which is why I have left this answer unchanged. $\endgroup$ Commented Jul 7, 2025 at 7:12
4
$\begingroup$

I'll start us off with

236 points, at nine queens, five rooks, two bishops, two knights, and nine pawns per side: enter image description here
Both kings are in check, but can escape by blocking with either of their knights.
The main difficulty was fitting one of each queen, and one of each pawn, in all nine boxes while leaving an empty cell in every diagonal: Looking for grids with rotational symmetry was an excellent way to ensure that all conditions were satisfied throughout the grid.

This answer would not be possible without this custom board editor!

EDIT:

248.6, with a much more deliberate placement of empty squares and no checks in sight:
enter image description here

$\endgroup$
5
  • $\begingroup$ This doesn't appear to satisfy the condition of one white and one black bishop on each diagonal. $\endgroup$ Commented Jul 4, 2025 at 5:23
  • $\begingroup$ @quarague. The rules say only at most one bishop of each colour in each diagonal. $\endgroup$ Commented Jul 4, 2025 at 5:42
  • 1
    $\begingroup$ @Pranay True, my bad, didn't read careful enough. $\endgroup$ Commented Jul 4, 2025 at 6:25
  • $\begingroup$ @quarague the rules are too many :D confusion is kinda inevitable. $\endgroup$ Commented Jul 4, 2025 at 9:00
  • $\begingroup$ @Oray The rules should be a lot clearer now, feel free to have another go! $\endgroup$ Commented Jul 4, 2025 at 10:52
4
$\begingroup$

The maximum score, obtained via integer linear programming, is

259.3

Here is one such solution:

enter image description here

Although both kings are in check, neither is in checkmate.

As text:

-- -- WP BR -- WQ BQ BP --
WQ BP -- WP BQ WR -- BR --
-- BQ WR BN WB BP WQ WP --
WP BB WB WQ BR -- WR BQ BP
BQ -- BR WR BP WN BN WQ WP
BP WR WQ BQ WP BB BR WN --
-- WP BK WB WQ BR BP WR BQ
-- BR BQ BP WR WP WK -- WQ
-- WQ BP -- -- BQ WP -- --

I used the following SAS code, which ignores the checkmate requirement:

proc optmodel;
   num n = 9;
   set ROWS = 1..n;
   set COLS = ROWS;
   set CELLS = ROWS cross COLS;
   set BOXES = 0..2 cross 0..2;
   set CELLS_box {<bi,bj> in BOXES} = 3*bi+1..3*bi+3 cross 3*bj+1..3*bj+3;
   num numDiagonals init 0;
   set DIAGONALS = 1..numDiagonals;
   set <num,num> CELLS_d {DIAGONALS};
   for {d in 2..2*n} do;
      numDiagonals = numDiagonals + 1;
      CELLS_d[numDiagonals] = {<i,j> in CELLS: i+j = d};
   end;
   for {d in 1-n..n-1} do;
      numDiagonals = numDiagonals + 1;
      CELLS_d[numDiagonals] = {<i,j> in CELLS: i-j = d};
   end;

   set COLORS = /W B/;

   set PIECES = /N K R B Q P/;
   num lb {PIECES} = [2 1 2 2 1 8];
   num ub {p in PIECES} = (if p = 'K' then 1 else card(CELLS));
   num score {PIECES} = [2.7 0 5 3.3 8 1];

   /* IsPiece[c,p,i,j] = 1 if color c, piece p is in cell (i,j) */
   var IsPiece {COLORS, PIECES, CELLS} binary;

   /* IsEmpty[i,j] = 1 if cell (i,j) is empty */
   var IsEmpty {CELLS} binary;

   /* declare objective */
   max TotalScore = sum {c in COLORS, p in PIECES, <i,j> in CELLS} score[p] * IsPiece[c,p,i,j];

   /* declare constraints */
   con OnePiecePerCell {<i,j> in CELLS}:
      sum {c in COLORS, p in PIECES} IsPiece[c,p,i,j] + IsEmpty[i,j] = 1;

   con Cardinality {c in COLORS, p in PIECES}:
      lb[p] <= sum {<i,j> in CELLS} IsPiece[c,p,i,j] <= ub[p];

   con OneEmptyPerRow {i in ROWS}:
      sum {j in ROWS} IsEmpty[i,j] >= 1;

   con OneEmptyPerColumn {j in ROWS}:
      sum {i in ROWS} IsEmpty[i,j] >= 1;

   con OneEmptyPerDiagonal {d in DIAGONALS}:
      sum {<i,j> in CELLS_d[d]} IsEmpty[i,j] >= 1;

   con OneEmptyPerBox {<bi,bj> in BOXES}:
      sum {<i,j> in CELLS_box[bi,bj]} IsEmpty[i,j] >= 1;

   con AtMostOneColorPiecePerRow {c in COLORS, p in PIECES diff /P/, i in ROWS}:
      sum {j in ROWS} IsPiece[c,p,i,j] <= 1;

   con AtMostOneColorPiecePerColumn {c in COLORS, p in PIECES diff /P/, j in ROWS}:
      sum {i in ROWS} IsPiece[c,p,i,j] <= 1;

   con AtMostOneColorPiecePerBox {c in COLORS, p in PIECES diff /P/, <bi,bj> in BOXES}:
      sum {<i,j> in CELLS_box[bi,bj]} IsPiece[c,p,i,j] <= 1;

   con AtLeastOnePawnPerColorRow {c in COLORS, i in ROWS}:
      sum {j in ROWS} IsPiece[c,'P',i,j] >= 1;

   con AtLeastOnePawnPerColorColumn {c in COLORS, j in ROWS}:
      sum {i in ROWS} IsPiece[c,'P',i,j] >= 1;

   con AtLeastOnePawnPerColorBox {c in COLORS, <bi,bj> in BOXES}:
      sum {<i,j> in CELLS_box[bi,bj]} IsPiece[c,'P',i,j] >= 1;

   con AtMostOnePerDiagonal {c in COLORS, p in /Q B/, d in DIAGONALS}:
      sum {<i,j> in CELLS_d[d]} IsPiece[c,p,i,j] <= 1;

   /* call MILP solver */
   solve;

   /* print solution */
   str sol {CELLS} init '--';
   for {<i,j> in CELLS} do;
      for {c in COLORS, p in PIECES: IsPiece[c,p,i,j] > 0.5} do;
         sol[i,j] = c||p;
         leave;
      end;
   end;
   print sol;
quit;
$\endgroup$
3
  • $\begingroup$ This still fails the checkmate test, but unless I'm overlooking something, that can be fixed without altering the result just by swapping all of the queens. $\endgroup$ Commented Jul 4, 2025 at 14:57
  • 1
    $\begingroup$ @robbpratt your code does not consider properly "Each row, column, and box must contain at least one pawn of each color." in my opinion, and your solution as well. $\endgroup$ Commented Jul 6, 2025 at 9:31
  • 1
    $\begingroup$ @Oray Corrected now, and my score agrees with yours. $\endgroup$ Commented Jul 6, 2025 at 15:11

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.