//#include<cstdio>
//#include<cassert>
//#include<iostream>
//#include<cstring>
//#include<algorithm>
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define MAX ((int)1e5 + 5)
#define MAXL ((ll)1e18 + 5)
#define MAX_X ((ll)1e5 + 2)
#define pi (2.0*acos(0))
#define M ((int)1e6 + 7)
#define MOD ((int)998244353 + 0)
#define NN ((int)1e5 + 7)
#define N ((int)3e3 + 2)
#define eps (0)
#define fastio ios_base::sync_with_stdio(false),cin.tie(NULL)
#define logn 29
#define endl "\n"
#define mp make_pair
#define BUCK 105
#define LEF (idx<<1)
#define RIG ((idx<<1)|1)
//#define int ll


using namespace std;
using namespace __gnu_pbds;

typedef long long ll;
typedef unsigned long long ull;

/*fast io
ios_base::sync_with_stdio(false);
cin.tie(NULL);
*/




typedef tree < pair < ll, pair < ll, ll > >,  null_type,  less < pair < ll, pair < ll, ll > > >,  rb_tree_tag,  tree_order_statistics_node_update > o_set;
/// o_set s;
/// s.order_of_key(k) : Number of items strictly smaller than k .
/// *(s.find_by_order(k)) : K-th element in a set (counting from zero).

int pwr[2][N];

int dpp[2][N] ; //, sum[2][N];

//int power(int n , int p)
//{
//    if(n<0 || p<0) return 0;
//    if(pwr[n][p] != -1) return pwr[n][p];
//    if(n == 0) return pwr[n][p] = 0;
//    if(p == 0) return pwr[n][p] = 1;
//    return pwr[n][p] = 1ll*power(n,p-1)*n%MOD;
//}

int power(int n , int p)
{
    if(n == 0) return 0;
    if(p == 0) return 1;

    int ans = power(n,p>>1);
    ans = 1ll*ans*ans%MOD;
    if(p&1) ans = 1ll*ans*n%MOD;
    return ans;
}


int main()
{
//    cout<<(5%3 + 5);
    fastio;
//    memset(dpp,-1,sizeof dpp);
//    memset(pwr,-1,sizeof pwr);
    int a , b , c , d;
    cin>>a>>b>>c>>d;
    int row = c - a , col = d - b;

    bool cur = 0;

    pwr[0][0] = pwr[1][0] = 1;

    for(int i = 1 ; i<=col ; i++){
        pwr[0][i] = 1ll*pwr[0][i-1]*(a+row-1)%MOD;
        pwr[1][i] = 1ll*pwr[1][i-1]*(a+row)%MOD;
    }

    dpp[0][col+1] = dpp[1][col+1] = 0;

    for(int i = 0 ; i<=col ; i++){
//        dpp[0][i] = power(a+row,col-i);
        dpp[0][i] = pwr[1][col-i];
//        sum[0][i] = 1ll*dpp[0][i]*power(a+row-1,i)%MOD;
//        sum[0][i] = 1ll*dpp[0][i]*pwr[0][i]%MOD;
//        if(i>0){
//            sum[0][i] = (sum[0][i] + sum[0][i-1]);
//            if(sum[0][i] >= MOD) sum[0][i] -= MOD;
//        }
    }

    for(int i = row ; i>=1 ; i--){
        cur = !cur;
//        for(int j = 1 ; j<=col ; j++){
//            pwr[1][j] = pwr[0][j];
//            pwr[0][j] = 1ll*pwr[0][j-1]*(i-2+a)%MOD;
//        }
        int con = 0;
        for(int j = col ; j>=0 ; j--){
            dpp[cur][j] = 1ll*(b+j)*dpp[!cur][j]%MOD;
//            int tmp = 1ll*(sum[!cur][col] - sum[!cur][j] + MOD)*power(power(a+i-1,j),MOD-2)%MOD;
            con = 1ll*(a+i-1)*(con + dpp[!cur][j+1])%MOD;
//            int tmp = 1ll*(sum[!cur][col] - sum[!cur][j] + MOD)*power(pwr[1][j],MOD-2)%MOD;
            dpp[cur][j] = (dpp[cur][j] + con);
            if(dpp[cur][j] >= MOD) dpp[cur][j] -= MOD;
//            sum[cur][j] = 1ll*dpp[cur][j]*power(a+i-2,j)%MOD;
//            sum[cur][j] = 1ll*dpp[cur][j]*pwr[0][j]%MOD;
//            if(j > 0){
//                sum[cur][j] = (sum[cur][j] + sum[cur][j-1]);
//                if(sum[cur][j] >= MOD) sum[cur][j] -= MOD;
//            }
        }
    }

    cout<<dpp[cur][0]<<endl;

    return 0;
}


Measured memory_bytes: 3688