JSFiddle - React, Tailwind, and code Playground
HTML
<div>
<h2>Laske todennäköisyys sille, että pakan permutaatiossa ei ole samoja kortteja peräkkäin</h2>
<p>Määritä pakan koostumus. Arvo k tarkoittaa kuinka monta korttia samaa arvoa on ja tämän perässä oleva numero (#) tarkoittaa kuinka monta kertaa tuo lukumäärä esiintyy. Esim. tavallinen korttipakka olisi k=4, #=13. Jos pakka on "epätasainen", lisää k-valintoja. Esim jos haluttaisiin selvittää tn että missään kohtaa ei ole vierekkäin herttaa, ruutua eikä ristiä, niin laitetaan k-valinnat (k=1, #=13) ja (k=13, #=3) eli padat ovat jokainen kortti oma yksikkönsä ja näitä on 13 kappaletta kun taas muut maat on kukin yhdistetty 13 kortin luokaksi.</p>
<div>
<ul id="kInputList">
</ul>
</div>
<button id="addButt">Lisää k-valinta</button>
</div>
<button id="calcButt">Laske todennäköisyys</button>
<div>
<span id="answer"></span>
</div>
CSS
#kInputList li {
margin-top: 10px;
}
button {
margin-bottom: 20px;
}
#answer {
background: lightgreen;
margin: 10px;
}
JavaScript
const sum = a => a.reduce((cum,x)=>cum+BigInt(x), 0n);
const range = (a,b,c=1) => Array(b-a).fill(0).map((_,j)=>a+j*c);
function gcd(a, b) {
while (b !== 0n) {
const r = a % b;
a = b;
b = r;
}
return a;
}
function binomial(n,k){
let result = 1n;
for(var i=1; i <= k; i++){
result *= BigInt(n+1-i);
result /= BigInt(i);
}
return result;
}
function fallingFact(n, k) {
let result = 1n;
for(var i=1; i <= k; i++){
result *= BigInt(n+1-i);
}
return result;
}
function fact(n) {
let result = 1n;
for(var i=2; i <= n; i++){
result *= BigInt(i);
}
return result;
}
class P {
constructor(cs) {
this.cs = cs.map(c=>BigInt(c));
}
mul(q) {
return new P(range(0, this.cs.length + q.cs.length-1)
.map(m=>sum(range(0, this.cs.length).map(j=> m-j>=0 && m-j<q.cs.length ? this.cs[j]*q.cs[m-j] : 0n ))));
}
toString() {
return this.cs.map((c,j)=>c.toString()+ ( j>1 ? "x^"+j.toString() : (j==0 ? "" : "x") ) )
.join(" + ");
}
}
const calcProb = (ns) => {
const ps = range(0, Math.max.apply(Math, ns)+1)
.map(m=>
new P(range(0, m+1).map(j=>(-1n)**BigInt(m-j)*binomial(m-1, m-j)*fallingFact(m, m-j) ))
);
let q = ns.reduce((cum,x)=>cum.mul(ps[x]), new P([1]));
let numer = q.cs.reduce((cum, c,j)=>cum+c*fact(j), 0n);
let denom = fact(sum(ns));
let g = gcd(numer, denom);
return [numer/g, denom/g];
};
const makeKInput = () => {
let ret = document.createElement("li");
ret.innerHTML = `<label>k: <input type="number" min="1" value="1"></label><label>#: <input type="number" min="0" value="1"></label>`;
return ret;
};
const addKInput = () => {
document.getElementById("kInputList").appendChild(makeKInput());
};
const getKNums = (el) => {
let [k, n] = Array.from(el.querySelectorAll("input")).map(y=>+y.value);
if (typeof k == "number" && typeof n == "number") {
return [k,n];
} else {
return [1,...