function aln_xdrop(a, b, pen, xdrop) {
let max_sc = xdrop, max_i = -1, max_j = -1;
let st = 0, H = [];
for (let j = 0; j < b.length; ++j) { // initialize row -1
const sc = xdrop - pen * (j + 1);
if (sc <= 0) break;
H[j] = sc;
}
for (let i = 0; i < a.length; ++i) {
let H11 = st === 0? xdrop - pen * i : H[st - 1]; // H[i-1,j-1]
let H01 = H11 - pen; // H[i,j-1] = H[i-1,j-1] - pen
if (H01 <= 0) ++st; // ignored dropped cells
let max_row_sc = 0; // max score on row i
for (let j = st; j < b.length; ++j) {
let H00 = H11 + (a[i] == b[j]? 1 : -pen); // H[i,j] = H[i-1,j-1] + s(a[i], b[j])
if (j < H.length)
H00 = H00 > H[j] - pen? H00 : H[j] - pen; // H[i,j] = max(H[i,j], H[i-1,j] - pen)
H00 = H00 > H01 - pen? H00 : H01 - pen; // H[i,j] = max(H[i,j], H[i,j-1] - pen)
if (j >= H.length && H00 <= max_sc - xdrop) break;
max_row_sc = max_row_sc > H00? max_row_sc : H00; // keep the max row score
if (H00 > max_sc) // keep the overall max score and the cell position
max_sc = H00, max_i = i, max_j = j;
H01 = H00;
H11 = j < H.length? H[j] : 0;
H[j] = H00;
}
if (max_row_sc <= max_sc - xdrop) break;
}
return [max_sc - xdrop, max_i, max_j];
}
let a = "GTTGATGGTCTACAACGTTATCGTCACAGCCCATGCATTTGTAATAATCTTCTTCATAGTAATA";
let b = "GATAGATGGTCTGAGCTATGATATCAATTGGCTTCCTAGGGTTTATCGTGTGAGCACACCATATT";
let [max_sc, max_i, max_j] = aln_xdrop(a, b, 2, 10);
console.log(max_sc, max_i, max_j, a.substr(0, max_i+1), b.substr(0, max_j+1));
ZnVuY3Rpb24gYWxuX3hkcm9wKGEsIGIsIHBlbiwgeGRyb3ApIHsKCWxldCBtYXhfc2MgPSB4ZHJvcCwgbWF4X2kgPSAtMSwgbWF4X2ogPSAtMTsKCWxldCBzdCA9IDAsIEggPSBbXTsKCWZvciAobGV0IGogPSAwOyBqIDwgYi5sZW5ndGg7ICsraikgeyAvLyBpbml0aWFsaXplIHJvdyAtMQoJCWNvbnN0IHNjID0geGRyb3AgLSBwZW4gKiAoaiArIDEpOwoJCWlmIChzYyA8PSAwKSBicmVhazsKCQlIW2pdID0gc2M7Cgl9Cglmb3IgKGxldCBpID0gMDsgaSA8IGEubGVuZ3RoOyArK2kpIHsKCQlsZXQgSDExID0gc3QgPT09IDA/IHhkcm9wIC0gcGVuICogaSA6IEhbc3QgLSAxXTsgLy8gSFtpLTEsai0xXQoJCWxldCBIMDEgPSBIMTEgLSBwZW47IC8vIEhbaSxqLTFdID0gSFtpLTEsai0xXSAtIHBlbgoJCWlmIChIMDEgPD0gMCkgKytzdDsgLy8gaWdub3JlZCBkcm9wcGVkIGNlbGxzCgkJbGV0IG1heF9yb3dfc2MgPSAwOyAvLyBtYXggc2NvcmUgb24gcm93IGkKCQlmb3IgKGxldCBqID0gc3Q7IGogPCBiLmxlbmd0aDsgKytqKSB7CgkJCWxldCBIMDAgPSBIMTEgKyAoYVtpXSA9PSBiW2pdPyAxIDogLXBlbik7IC8vIEhbaSxqXSA9IEhbaS0xLGotMV0gKyBzKGFbaV0sIGJbal0pCgkJCWlmIChqIDwgSC5sZW5ndGgpCgkJCQlIMDAgPSBIMDAgPiBIW2pdIC0gcGVuPyBIMDAgOiBIW2pdIC0gcGVuOyAvLyBIW2ksal0gPSBtYXgoSFtpLGpdLCBIW2ktMSxqXSAtIHBlbikKCQkJSDAwID0gSDAwID4gSDAxIC0gcGVuPyBIMDAgOiBIMDEgLSBwZW47IC8vIEhbaSxqXSA9IG1heChIW2ksal0sIEhbaSxqLTFdIC0gcGVuKQoJCQlpZiAoaiA+PSBILmxlbmd0aCAmJiBIMDAgPD0gbWF4X3NjIC0geGRyb3ApIGJyZWFrOwoJCQltYXhfcm93X3NjID0gbWF4X3Jvd19zYyA+IEgwMD8gbWF4X3Jvd19zYyA6IEgwMDsgLy8ga2VlcCB0aGUgbWF4IHJvdyBzY29yZQoJCQlpZiAoSDAwID4gbWF4X3NjKSAvLyBrZWVwIHRoZSBvdmVyYWxsIG1heCBzY29yZSBhbmQgdGhlIGNlbGwgcG9zaXRpb24KCQkJCW1heF9zYyA9IEgwMCwgbWF4X2kgPSBpLCBtYXhfaiA9IGo7CgkJCUgwMSA9IEgwMDsKCQkJSDExID0gaiA8IEgubGVuZ3RoPyBIW2pdIDogMDsKCQkJSFtqXSA9IEgwMDsKCQl9CgkJaWYgKG1heF9yb3dfc2MgPD0gbWF4X3NjIC0geGRyb3ApIGJyZWFrOwoJfQoJcmV0dXJuIFttYXhfc2MgLSB4ZHJvcCwgbWF4X2ksIG1heF9qXTsKfQoKbGV0IGEgPSAgIkdUVEdBVEdHVENUQUNBQUNHVFRBVENHVENBQ0FHQ0NDQVRHQ0FUVFRHVEFBVEFBVENUVENUVENBVEFHVEFBVEEiOwpsZXQgYiA9ICJHQVRBR0FUR0dUQ1RHQUdDVEFUR0FUQVRDQUFUVEdHQ1RUQ0NUQUdHR1RUVEFUQ0dUR1RHQUdDQUNBQ0NBVEFUVCI7CmxldCBbbWF4X3NjLCBtYXhfaSwgbWF4X2pdID0gYWxuX3hkcm9wKGEsIGIsIDIsIDEwKTsKY29uc29sZS5sb2cobWF4X3NjLCBtYXhfaSwgbWF4X2osIGEuc3Vic3RyKDAsIG1heF9pKzEpLCBiLnN1YnN0cigwLCBtYXhfaisxKSk7