// export function Weights(size) {
//     let set = new Set()

//     for(let i = 0; i < size; i++) {
//         set.add(i + 1)
//     }

//     return new Map([
//         [ 1, set ]
//     ])
// }

export function Weights(size) {
    let out = []

    for(let i = 0; i < size; i++) {
        out.push(1/size)
    }

    return out
}

export function Add(left, right, out = new Map()) {
    for(let i = 0; i < left.size * right.size; i++) {
        let li = parseInt(i / left.size) + 1
        let ri = (i % left.size) + 1

        let key = li + ri
        let base = out.get(key) ?? 0
        out.set(key, base + left.get(li) + right.get(ri))
    }
    // for(let li = 0; li < left.size; li++) {
    //     for(let ri = 0; ri < right.size; ri++) {
    //         let i = li + ri
    //         let b = out.get(i) ?? 0
    //         out.set(i, b + left.get(i) + right.get(i))
    //     }
    // }

    return out
    
}

export function Mul(left, to) {
    let out = left

    for(let i = 1; i < to; i++) {
        out = Add(out, left)
    }

    return out
}

// console.log(Weights(6))
// console.log(Add(Weights(6), Weights(6)))
// console.log(Mul(Weights(6), 3))

export function WeightOf(size) {
    return 1 / size
}

function probSum2dN(N, S) {
    let P = 0
    for(let r1 = 1; r1 < N + 1; r1++) {
        let r2 = S - r1
        if(1 <= r2 && r2 <= N) {
            P += 1
        }
    }
    return [ P, Math.pow(N, 2) ]
}

// function conv(a, b) {
//     let bf = b.reverse()
//     let len = (a.length) + (b.length)
//     let P = new Map()
    
//     for(let i = 1; i < len; i++) {
//         let topSliceRange = [
//             Math.max(i - a.length, 0),
//             Math.min(i, b.length)
//         ]
//         let bottomSliceRange = [
//             Math.max(b.length - i, 0),
//             Math.min(b.length, len - i)
//         ]
//         let topSlice = a.slice(...topSliceRange)
//         let bottomSlice = bf.slice(...bottomSliceRange)

//         P.set(
//             i + 1,
//             topSlice.reduce(
//                 (a, v, i) => a + (v * bottomSlice[i]),
//                 0
//             )
//         )
//     }

//     return P
// }

// const conv = (vec1, vec2) => {
//     if (vec1.length === 0 || vec2.length === 0) {
//         throw new Error('Vectors can not be empty!');
//     }
//     const volume = vec1;
//     const kernel = vec2;
//     /* Initialized to zero by default */
//     const convVec = new Float32Array(volume.length + kernel.length);

//     let i = 0;
//     for (let j = 0; j < kernel.length; ++j) {
//         convVec[j] = volume[0] * kernel[j];
//     }

//     for (i = 1; i < volume.length; ++i) {
//         for (let j = 0; j < kernel.length; ++j) {
//             convVec[i + j] += volume[i] * kernel[j];
//         }
//     }

//     return convVec;
// };

// console.log(
//     conv(
//         Weights(6),
//         Weights(6)
//         // conv(Weights(6), Weights(6))
//     )
// )

class Distribution extends Float32Array {
    static Die(size) {
        return new Distribution(1, size, 1 / size)
    }

    constructor(first, last, fill) {
        
        let len = (last + 1) - first
        let b = new ArrayBuffer(len * 4)
        super(b)
        
        this.first = first
        this.last = last
        if(fill) {
            this.fill(fill)
        }
    }

    forEach(func) {
        for(let i = this.first; i <= this.last; i++) {
            func(this.get(i), i)
        }
    }

    set(i, value) {
        super.set([ value ], i - this.first)
    }

    increase(i, value) {
        let index = i - this.first
        super.set([ this.at(index) + value ], index)
    }

    get(i) {
        return this.at(i - this.first)
    }

    contains(indice) {
        return indice >= this.first && indice <= this.last
    } 
}

function conv(d1, d2) {
    let ax1 = d1.first + d2.first
    let ax2 = d1.last + d2.last
    console.log(ax1, ax2, ax2 - ax1)
    let Pc = new Distribution(ax1, ax2, 0)

    for(let S = ax1; S <= ax2; S++) {
        for(let r1 = d1.first; r1 <= d1.last; r1++) {
            let r2 = S - r1

            if(d2.contains(r2)) {
                Pc.increase(S, d1.get(r1) * d2.get(r2))
            }
        }
    }

    return Pc
}

// console.log(Distribution.Die(6))
// let a = Distribution.Die(12)
// a.set(2, 0.000069)
// a.forEach(console.log)

console.log(
    conv(
        Distribution.Die(6),
        conv(Distribution.Die(6), Distribution.Die(6))
    )
)