// helper functions

// cnf formula exactly one of the variables in the chosen list to be true

function ext_one(list) {
    let temp = ""
    temp=temp+atl_one(list)
    temp=temp+atm_one(list)
    return temp
}

// cnf formula for atleast one of the variables in the chosen list to be true
function atl_one(list) {
    let temp=""
    list.forEach(item => {
        temp = temp +" " + item
    })
    temp=temp+" 0\n"
    console.log("at least, ", temp)
    return temp
}

// cnf formula for atmost one of the variables in the chosen list to be true
function atm_one(list) {
    let temp=""
    list.forEach(function (x) {
        list.slice(list.indexOf(x) + 1).forEach(y => {
            temp = temp +" -"+x+" -"+y+" 0\n"
        })
    })
    return temp
}

// function to map position (r,c) 0 <= r,c < N, in an NxN grid to the integer
// position when the grid is stored linearly by rows.

function varmap(r,c,N) {
    return r*N+c+1
}

// range
function range(start, stop, step) {
    if (typeof stop == 'undefined') {
        // one param defined
        stop = start;
        start = 0;
    }
    if (typeof step == 'undefined') {
        step = 1;
    }
    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
        return [];
    }
    var result = [];
    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
        result.push(i);
    }
    return result;
}

/**
 * @return {string}
 */
function sat(N){
// Start Solver: Comments
    let output="c SAT Expression for N="+N+((N === 1)? " queen\n": " queens\n")
    let size = N*N
    output = output + "c Chess board has "+size+((N === 1)? " position\n": " positions\n")

// Exactly 1 queen per row
    let tempG = ""
    range(0,N).forEach(row => {
        let A=[]
        range(0,N).forEach(column => {
            let position = varmap(row,column,N)
            A.push(position)
        })
        tempG = tempG+ext_one(A)
    })


// Exactly 1 queen per column
    range(0,N).forEach(column => {
        let A=[]
        range(0,N).forEach(row => {
            let position = varmap(row,column,N)
            A.push(position)
        })
        tempG = tempG+ext_one(A)
    })


// Atmost 1 queen per negative diagonal from left
    range(N-1,-1,-1).forEach(row => {
        let A=[]
        range(0,N-row).forEach(x => {
            A.push(varmap(row+x,x,N))
        })
        tempG=tempG+atm_one(A)
    })


// Atmost 1 queen per negative diagonal from top
    range(1,N).forEach(column => {
        let A=[]
        range(0,N-column).forEach(x => {
            A.push(varmap(x,column+x,N))
        })
        tempG=tempG+atm_one(A)
    })

// Atmost 1 queen per positive diagonal from right
    range(N-1,-1,-1).forEach(row => {
        let A=[]
        range(0,N-row).forEach(x => {
            A.push(varmap(row+x,N-1-x,N))
        })
        tempG=tempG+atm_one(A)
    })

// Atmost 1 queen per positive diagonal from top
    range(N-2,-1,-1).forEach(column => {
        let A=[]
        range(0,column+1).forEach(x => {
            A.push(varmap(x,column-x,N))
        })
        tempG=tempG+atm_one(A)
    })

    output = output +  'p cnf ' + (N*N) + ' ' + (tempG.split('\n').length - 1) + '\n' + tempG.trim()
    return output
}