Find Probability of Knight Remaining Chessboard

Last Updated : 4 Aug, 2026

Given an n x n chessboard and the initial position (x, y) of a Knight, find the probability that the Knight remains on the chessboard after making exactly k moves.

  • A Knight moves in an L-shape and, from its current position, can move to any of the following 8 positions:
    (±2, ±1) and (±1, ±2). 
  • For every move, the Knight selects one of these 8 possible moves with equal probability.
  • If a move takes the Knight outside the chessboard, it is considered to have left the board and cannot return.

Return the probability as a floating-point number, rounded to at most 6 decimal places.

Examples: 

Input: n = 8, x = 0, y = 0, k = 3
Output: 0.125000
Explanation: The probability that the Knight remains on the board after exactly 3 moves is 0.125000.

Input: n = 4, x = 1, y = 2, k = 4
Output: 0.024414
Explanation: The probability that the Knight remains on the board after exactly 4 moves is 0.024414.

Try It Yourself
redirect icon

[Naive Approach] Using Recursion - O(8 ^ k) Time and O(k) Space

The idea is to recursively try all 8 possible knight moves from the current position. If the knight moves outside the board, that path contributes 0 probability. If no moves are left, it contributes 1. The final probability is obtained by averaging the probabilities of all 8 moves.

Working of Approach:

  • Start from the given cell.
  • Recursively explore all 8 knight moves.
  • Return 0 if the knight leaves the board.
  • Return 1 when all k moves are completed.
  • Average the probabilities of all 8 recursive calls.
C++
#include <bits/stdc++.h>
using namespace std;

int dx[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
int dy[8] = {-1, 1, -2, 2, -2, 2, -1, 1};

// Returns probability of staying on board
double solve(int n, int k, int row, int col)
{

    // Knight moved outside board
    if (row < 0 || row >= n || col < 0 || col >= n)
        return 0.0;

    // No moves left
    if (k == 0)
        return 1.0;

    double res = 0.0;

    // Try all 8 possible moves
    for (int i = 0; i < 8; i++)
        res += solve(n, k - 1, row + dx[i], col + dy[i]) / 8.0;

    return res;
}

double knightProbability(int n, int k, int row, int column)
{
    return solve(n, k, row, column);
}

int main()
{

    cout << fixed << setprecision(6) << knightProbability(4, 4, 1, 2);

    return 0;
}
Java
import java.util.Arrays;

class GFG {

    static int[] dx = { -2, -2, -1, -1, 1, 1, 2, 2 };
    static int[] dy = { -1, 1, -2, 2, -2, 2, -1, 1 };

    // Returns probability of staying on board
    public static double solve(int n, int k, int row,
                               int col)
    {

        // Knight moved outside board
        if (row < 0 || row >= n || col < 0 || col >= n)
            return 0.0;

        // No moves left
        if (k == 0)
            return 1.0;

        double res = 0.0;

        // Try all 8 possible moves
        for (int i = 0; i < 8; i++)
            res += solve(n, k - 1, row + dx[i], col + dy[i])
                   / 8.0;

        return res;
    }

    public static double
    knightProbability(int n, int k, int row, int column)
    {
        return solve(n, k, row, column);
    }

    public static void main(String[] args)
    {
        System.out.printf("%.6f%n",
                          knightProbability(4, 4, 1, 2));
    }
}
Python
dx = [-2, -2, -1, -1, 1, 1, 2, 2]
dy = [-1, 1, -2, 2, -2, 2, -1, 1]

# Returns probability of staying on board


def solve(n, k, row, col):
    # Knight moved outside board
    if row < 0 or row >= n or col < 0 or col >= n:
        return 0.0

    # No moves left
    if k == 0:
        return 1.0

    res = 0.0

    # Try all 8 possible moves
    for i in range(8):
        res += solve(n, k - 1, row + dx[i], col + dy[i]) / 8.0

    return res


def knightProbability(n, k, row, column):
    return solve(n, k, row, column)


if __name__ == '__main__':
    print(f"{knightProbability(4, 4, 1, 2):.6f}")
C#
using System;

class GFG {
    static int[] dx = { -2, -2, -1, -1, 1, 1, 2, 2 };
    static int[] dy = { -1, 1, -2, 2, -2, 2, -1, 1 };

    // Returns probability of staying on board
    static double solve(int n, int k, int row, int col)
    {
        // Knight moved outside board
        if (row < 0 || row >= n || col < 0 || col >= n)
            return 0.0;

        // No moves left
        if (k == 0)
            return 1.0;

        double res = 0.0;

        // Try all 8 possible moves
        for (int i = 0; i < 8; i++)
            res += solve(n, k - 1, row + dx[i], col + dy[i])
                   / 8.0;

        return res;
    }

    public double knightProbability(int n, int k, int row,
                                    int column)
    {
        return solve(n, k, row, column);
    }

    public static void Main()
    {
        GFG obj = new GFG();
        Console.WriteLine(
            "{0:F6}", obj.knightProbability(4, 4, 1, 2));
    }
}
JavaScript
const dx = [ -2, -2, -1, -1, 1, 1, 2, 2 ];
const dy = [ -1, 1, -2, 2, -2, 2, -1, 1 ];

// Returns probability of staying on board
function solve(n, k, row, col)
{
    // Knight moved outside board
    if (row < 0 || row >= n || col < 0 || col >= n)
        return 0.0;

    // No moves left
    if (k === 0)
        return 1.0;

    let res = 0.0;

    // Try all 8 possible moves
    for (let i = 0; i < 8; i++) {
        res += solve(n, k - 1, row + dx[i], col + dy[i])
               / 8.0;
    }

    return res;
}

function knightProbability(n, k, row, column)
{
    return solve(n, k, row, column);
}

// Driver Code
console.log(knightProbability(4, 4, 1, 2).toFixed(6));

Output
0.024414

[Better Approach] Using DP with Memoization - O(n ^ 2 * k) Time and O(n ^ 2 * k) Space

The idea is to store the probability for every state (row, column, remaining moves). If the same state is encountered again, return the stored value instead of recomputing it. This avoids repeated recursive calculations.

Working of Approach:

  • Define a DP state as (row, column, remaining moves).
  • If the state is already computed, return its value.
  • Otherwise recursively calculate probabilities for all 8 moves.
  • Store the computed probability in the DP table.
  • Return the stored result.
C++
#include <bits/stdc++.h>
using namespace std;

int dx[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
int dy[8] = {-1, 1, -2, 2, -2, 2, -1, 1};

// Returns probability using memoization
double solve(int n, int k, int row, int col, vector<vector<vector<double>>> &dp)
{

    // Knight moved outside board
    if (row < 0 || row >= n || col < 0 || col >= n)
        return 0.0;

    // No moves left
    if (k == 0)
        return 1.0;

    // Already computed
    if (dp[row][col][k] != -1.0)
        return dp[row][col][k];

    double res = 0.0;

    // Explore all 8 moves
    for (int i = 0; i < 8; i++)
        res += solve(n, k - 1, row + dx[i], col + dy[i], dp) / 8.0;

    return dp[row][col][k] = res;
}

double knightProbability(int n, int k, int row, int column)
{

    vector<vector<vector<double>>> dp(n, vector<vector<double>>(n, vector<double>(k + 1, -1.0)));

    return solve(n, k, row, column, dp);
}

int main()
{

    cout << fixed << setprecision(6) << knightProbability(4, 4, 1, 2);

    return 0;
}
Java
import java.util.Arrays;

class GFG {

    static int[] dx = { -2, -2, -1, -1, 1, 1, 2, 2 };
    static int[] dy = { -1, 1, -2, 2, -2, 2, -1, 1 };

    // Returns probability using memoization
    static double solve(int n, int k, int row, int col,
                        double[][][] dp)
    {

        // Knight moved outside board
        if (row < 0 || row >= n || col < 0 || col >= n)
            return 0.0;

        // No moves left
        if (k == 0)
            return 1.0;

        // Already computed
        if (dp[row][col][k] != -1.0)
            return dp[row][col][k];

        double res = 0.0;

        // Explore all 8 moves
        for (int i = 0; i < 8; i++)
            res += solve(n, k - 1, row + dx[i], col + dy[i],
                         dp)
                   / 8.0;

        return dp[row][col][k] = res;
    }

    public double knightProbability(int n, int k, int row,
                                    int column)
    {

        double[][][] dp = new double[n][n][k + 1];

        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int l = 0; l <= k; l++)
                    dp[i][j][l] = -1.0;

        return solve(n, k, row, column, dp);
    }

    public static void main(String[] args)
    {
        GFG obj = new GFG();
        System.out.printf(
            "%.6f%n", obj.knightProbability(4, 4, 1, 2));
    }
}
Python
dx = [-2, -2, -1, -1, 1, 1, 2, 2]
dy = [-1, 1, -2, 2, -2, 2, -1, 1]

# Returns probability using memoization
def solve(n, k, row, col, dp):
    # Knight moved outside board
    if row < 0 or row >= n or col < 0 or col >= n:
        return 0.0
    
    # No moves left
    if k == 0:
        return 1.0
    
    # Already computed
    if dp[row][col][k]!= -1.0:
        return dp[row][col][k]
    
    res = 0.0
    
    # Explore all 8 moves
    for i in range(8):
        res += solve(n, k - 1, row + dx[i], col + dy[i], dp) / 8.0
    
    dp[row][col][k] = res
    return res

def knightProbability(n, k, row, column):
    dp = [[[-1.0 for _ in range(k + 1)] for _ in range(n)] for _ in range(n)]
    return solve(n, k, row, column, dp)

if __name__ == '__main__':
    print(f'{knightProbability(4, 4, 1, 2):.6f}')
C#
using System;

class GFG {
    static int[] dx = { -2, -2, -1, -1, 1, 1, 2, 2 };
    static int[] dy = { -1, 1, -2, 2, -2, 2, -1, 1 };

    // Returns probability using memoization
    static double solve(int n, int k, int row, int col,
                        double[, , ] dp)
    {
        // Knight moved outside board
        if (row < 0 || row >= n || col < 0 || col >= n)
            return 0.0;

        // No moves left
        if (k == 0)
            return 1.0;

        // Already computed
        if (dp[row, col, k] != -1.0)
            return dp[row, col, k];

        double res = 0.0;

        // Explore all 8 moves
        for (int i = 0; i < 8; i++)
            res += solve(n, k - 1, row + dx[i], col + dy[i],
                         dp)
                   / 8.0;

        return dp[row, col, k] = res;
    }

    public double knightProbability(int n, int k, int row,
                                    int column)
    {
        double[, , ] dp = new double[n, n, k + 1];

        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int l = 0; l <= k; l++)
                    dp[i, j, l] = -1.0;

        return solve(n, k, row, column, dp);
    }

    public static void Main()
    {
        GFG obj = new GFG();
        Console.WriteLine(
            "{0:F6}", obj.knightProbability(4, 4, 1, 2));
    }
}
JavaScript
const dx = [ -2, -2, -1, -1, 1, 1, 2, 2 ];
const dy = [ -1, 1, -2, 2, -2, 2, -1, 1 ];

// Returns probability using memoization
function solve(n, k, row, col, dp)
{
    // Knight moved outside board
    if (row < 0 || row >= n || col < 0 || col >= n)
        return 0.0;

    // No moves left
    if (k === 0)
        return 1.0;

    // Already computed
    if (dp[row][col][k] !== -1.0)
        return dp[row][col][k];

    let res = 0.0;

    // Explore all 8 moves
    for (let i = 0; i < 8; i++)
        res += solve(n, k - 1, row + dx[i], col + dy[i], dp)
               / 8.0;

    dp[row][col][k] = res;
    return res;
}

function knightProbability(n, k, row, column)
{
    const dp = Array.from(
        {length : n},
        () => Array.from({length : n},
                         () => Array(k + 1).fill(-1.0)));
    return solve(n, k, row, column, dp);
}

// Driver Code
console.log(knightProbability(4, 4, 1, 2).toFixed(6));

Output
0.024414

[Expected Approach] Using Bottom-Up DP (Space Optimized) - O(n ^ 2 * k) Time and O(n ^ 2)

The idea is to maintain the probability of the knight being at every cell after each move. For every move, distribute the probability of each cell equally among all valid knight moves. Since only the previous move is needed to compute the current move, use two n × n matrices to save space.

Working of Approach:

  • Initialize the starting cell with probability 1.
  • For each move, create a new probability matrix.
  • Distribute the current probability equally among all valid moves.
  • Replace the previous matrix with the new one.
  • Sum all probabilities after k moves.

Let us understand with an example:
Input: n = 4, x = 1, y = 2, k = 4

  • Initialize the probability matrix with 1.0 at the starting cell (1, 2) and 0 elsewhere.
  • In the first move, distribute the probability 1/8 to every valid knight move from (1, 2).
  • Repeat this process for the remaining 3 moves, updating the probability matrix at each step.
  • After 4 moves, each cell stores the probability of the knight being at that position.
  • Sum the probabilities of all cells to get the final answer, 0.024414.
C++
#include <bits/stdc++.h>
using namespace std;

double knightProbability(int n, int k, int row, int column)
{
    vector<vector<double>> curr(n, vector<double>(n, 0.0));
    curr[row][column] = 1.0;

    vector<int> dx = {2, 2, -2, -2, 1, 1, -1, -1};
    vector<int> dy = {1, -1, 1, -1, 2, -2, 2, -2};

    for (int step = 0; step < k; step++)
    {
        vector<vector<double>> next(n, vector<double>(n, 0.0));
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (curr[i][j] == 0.0)
                    continue;

                for (int d = 0; d < 8; d++)
                {
                    int ni = i + dx[d];
                    int nj = j + dy[d];

                    if (ni >= 0 && nj >= 0 && ni < n && nj < n)
                    {
                        // Divide probability by 8 at each step
                        next[ni][nj] += curr[i][j] / 8.0;
                    }
                }
            }
        }
        curr = move(next);
    }

    double totProb = 0.0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            totProb += curr[i][j];
        }
    }

    return totProb;
}

int main()
{

    cout << fixed << setprecision(6) << knightProbability(4, 4, 1, 2);

    return 0;
}
Java
import java.util.Arrays;

class GFG {

    public double knightProbability(int n, int k, int row,
                                    int column)
    {

        double[][] curr = new double[n][n];
        curr[row][column] = 1.0;

        int[] dx = { 2, 2, -2, -2, 1, 1, -1, -1 };
        int[] dy = { 1, -1, 1, -1, 2, -2, 2, -2 };

        for (int step = 0; step < k; step++) {

            double[][] next = new double[n][n];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {

                    if (curr[i][j] == 0.0)
                        continue;

                    for (int d = 0; d < 8; d++) {

                        int ni = i + dx[d];
                        int nj = j + dy[d];

                        if (ni >= 0 && nj >= 0 && ni < n
                            && nj < n) {

                            // Divide probability by 8 at
                            // each step
                            next[ni][nj]
                                += curr[i][j] / 8.0;
                        }
                    }
                }
            }

            curr = next;
        }

        double totProb = 0.0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                totProb += curr[i][j];
            }
        }

        return totProb;
    }

    public static void main(String[] args)
    {
        GFG obj = new GFG();
        System.out.printf(
            "%.6f%n", obj.knightProbability(4, 4, 1, 2));
    }
}
Python
def knightProbability(n, k, row, column):
    curr = [[0.0] * n for _ in range(n)]
    curr[row][column] = 1.0

    dx = [2, 2, -2, -2, 1, 1, -1, -1]
    dy = [1, -1, 1, -1, 2, -2, 2, -2]

    for step in range(k):
        next = [[0.0] * n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                if curr[i][j] == 0.0:
                    continue

                for d in range(8):
                    ni = i + dx[d]
                    nj = j + dy[d]

                    if 0 <= ni < n and 0 <= nj < n:
                        # Divide probability by 8 at each step
                        next[ni][nj] += curr[i][j] / 8.0
        curr = next

    totProb = sum(sum(row) for row in curr)

    return totProb

if __name__ == '__main__':
    print(f"{knightProbability(4, 4, 1, 2):.6f}")
C#
using System;

class GFG {
    public double knightProbability(int n, int k, int row,
                                    int column)
    {
        double[, ] curr = new double[n, n];
        curr[row, column] = 1.0;

        int[] dx = { 2, 2, -2, -2, 1, 1, -1, -1 };
        int[] dy = { 1, -1, 1, -1, 2, -2, 2, -2 };

        for (int step = 0; step < k; step++) {
            double[, ] next = new double[n, n];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (curr[i, j] == 0.0)
                        continue;

                    for (int d = 0; d < 8; d++) {
                        int ni = i + dx[d];
                        int nj = j + dy[d];

                        if (ni >= 0 && nj >= 0 && ni < n
                            && nj < n) {
                            // Divide probability by 8 at
                            // each step
                            next[ni, nj]
                                += curr[i, j] / 8.0;
                        }
                    }
                }
            }

            curr = next;
        }

        double totProb = 0.0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                totProb += curr[i, j];
            }
        }

        return totProb;
    }

    public static void Main()
    {
        GFG obj = new GFG();
        Console.WriteLine(
            "{0:F6}", obj.knightProbability(4, 4, 1, 2));
    }
}
JavaScript
function knightProbability(n, k, row, column)
{
    let curr = Array.from({length : n},
                          () => Array(n).fill(0.0));
    curr[row][column] = 1.0;

    const dx = [ 2, 2, -2, -2, 1, 1, -1, -1 ];
    const dy = [ 1, -1, 1, -1, 2, -2, 2, -2 ];

    for (let step = 0; step < k; step++) {
        let next = Array.from({length : n},
                              () => Array(n).fill(0.0));
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                if (curr[i][j] === 0.0)
                    continue;

                for (let d = 0; d < 8; d++) {
                    let ni = i + dx[d];
                    let nj = j + dy[d];

                    if (ni >= 0 && nj >= 0 && ni < n
                        && nj < n) {
                        // Divide probability by 8 at each
                        // step
                        next[ni][nj] += curr[i][j] / 8.0;
                    }
                }
            }
        }
        curr = next;
    }

    let totProb = 0.0;
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            totProb += curr[i][j];
        }
    }

    return totProb;
}

// Driver Code
console.log(knightProbability(4, 4, 1, 2).toFixed(6));

Output
0.024414
Comment