poker-html-client
Version:
HTML client for online poker
196 lines (173 loc) • 7.26 kB
text/typescript
interface ChipStack {
type: number;
amount: number;
}
interface ChipStackCalcIntermediate {
difference: number;
count: number;
index: number;
}
class ChipItem {
public baseAmount: KnockoutObservable<number>;
private maxStackCount = 5;
constructor(base: number) {
this.baseAmount = ko.observable(base);
}
public getData(amount: number) {
const self = this;
const list = [1, 5, 10, 50, 100, 500].map((item) => (item * self.baseAmount()));
const stack = this.calculateStackSimple(amount, list);
return this.transform(stack);
}
public transform(stack: ChipStack[]) {
const result = [] as number[][];
for (let i = 0; i < stack.length; i++) {
const item = [] as number[];
for (let j = 0; j < stack[i].amount; j++) {
item.push(stack[i].type);
}
result.push(item);
}
return result;
}
public calculateStack(amount: number, chipAmounts: number[]) {
let stack = this.calculateStackInternal(amount, chipAmounts);
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
stack = this.calculateStackInternal(amount, chipAmounts.slice(0, stack.length - 1));
if (stack.length > this.maxStackCount) {
throw new Error("Could not divide stack for amount " + amount);
}
}
}
}
}
}
}
return stack;
}
public calculateStackSimple(amount: number, chipAmounts: number[]): ChipStack[] {
if (amount === 0) {
return [] as ChipStack[];
}
const item1 = this.calculateStackSimpleInternal(amount, chipAmounts, false);
if (item1.difference > 0) {
const item2 = this.calculateStackSimpleInternal(item1.difference, chipAmounts, true);
if (item2.count === 0) {
return [{
amount: Math.max(item1.count, 1),
type: item1.index,
}];
}
if (item1.count === 0) {
return [{
amount: Math.max(item2.count, 1),
type: item2.index,
}];
}
return [{
amount: Math.max(item1.count, 1),
type: item1.index,
}, {
amount: Math.max(item2.count, 1),
type: item2.index,
}];
}
return [{
amount: Math.max(item1.count, 1),
type: item1.index,
}];
}
private calculateStackSimpleInternal(amount: number, chipAmounts: number[], allowOveradd: boolean): ChipStackCalcIntermediate {
const self = this;
const minimumAmount = chipAmounts[0];
let intermediate = chipAmounts.filter((ca) => amount >= ca);
let upperBound: number;
if (intermediate.length === 0) {
upperBound = minimumAmount;
} else {
upperBound = intermediate.reduce((prev, current) => Math.max(prev, current), Number.MIN_VALUE);
}
if (allowOveradd) {
intermediate = chipAmounts.filter((ca) => amount <= ca);
if (intermediate.length === 0) {
upperBound = minimumAmount;
} else {
upperBound = intermediate.reduce((prev, current) => Math.min(prev, current), Number.MAX_VALUE);
}
}
const effectiveChipsAmount = chipAmounts.filter((ca) => ca <= upperBound);
let target: {
amount: number;
chipsAmount: number;
difference: number
}[];
if (allowOveradd) {
target = effectiveChipsAmount.map(function(item) {
return {
amount: item,
chipsAmount: Math.min(Math.floor((amount + item - 1) / item), self.maxStackCount),
difference: 0,
};
});
target = target.concat(effectiveChipsAmount.map(function(item) {
return {
amount: item,
chipsAmount: Math.min(Math.floor(amount / item), self.maxStackCount),
difference: 0,
};
}));
} else {
target = effectiveChipsAmount.map(function(item) {
return {
amount: item,
chipsAmount: Math.min(Math.floor(amount / item), self.maxStackCount),
difference: 0,
};
});
}
target = target.filter((item) => item.chipsAmount <= self.maxStackCount)
.map(function(item) {
return {
amount: item.amount,
chipsAmount: item.chipsAmount,
difference: amount - (item.amount * item.chipsAmount),
};
});
const difference = target
.map((item) => Math.abs(item.difference))
.reduce((prev, curr) => Math.min(prev, curr), Number.MAX_VALUE);
const minimalSlice = target.filter((item) => Math.abs(item.difference) === difference)[0];
return {
difference: minimalSlice.difference,
count: minimalSlice.chipsAmount,
index: chipAmounts.filter((item) => item <= minimalSlice.amount).length,
};
}
private calculateStackInternal(amount: number, chipAmounts: number[]): ChipStack[] {
const result = [];
let amountLeft = amount;
for (let i = 0; i < chipAmounts.length; i++) {
const chipAmount = chipAmounts[i];
const chipsQty = Math.floor(amountLeft / chipAmount);
if (chipsQty === 0) {
continue;
}
result.push({ type: i + 1, amount: chipsQty });
amountLeft -= chipsQty * chipAmount;
}
if (amountLeft > 0 && result.length === 0) {
result.push({ type: 1, amount: 1 });
}
return result;
}
}