Skip to content

Instantly share code, notes, and snippets.

@zdraganov
Created May 23, 2020 08:11
Show Gist options
  • Save zdraganov/bb809a3a4a93c7e71e7071ba772733fa to your computer and use it in GitHub Desktop.
Save zdraganov/bb809a3a4a93c7e71e7071ba772733fa to your computer and use it in GitHub Desktop.
DDS example
import { dealerCompute } from 'results/utils/hands'
import { shortDirections } from 'results/constants'
const suitsSorted = ['S', 'H', 'D', 'C']
const ranksSorted = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']
const pbnDirectionCardsOrder = {
N: ['N', 'E', 'S', 'W'],
E: ['E', 'S', 'W', 'N'],
S: ['S', 'W', 'N', 'E'],
W: ['W', 'N', 'E', 'S']
}
function buildCard (cardString) {
const [rank, suit] = cardString.split('')
return { rank, suit }
}
function buildPbnCards (cards) {
const { S, H, D, C } =
cards.reduce((memo, card) => { memo[card.suit].push(card.rank); return memo },
{ S: [], H: [], D: [], C: [] })
return [S.join(''), H.join(''), D.join(''), C.join('')].join('.')
}
function sortPbnCards (cards) {
return cards.sort((c1, c2) => {
const suitCompared = suitsSorted.indexOf(c1.suit) - suitsSorted.indexOf(c2.suit)
if (suitCompared !== 0) {
return suitCompared
}
return ranksSorted.indexOf(c1.rank) - ranksSorted.indexOf(c2.rank)
})
}
// The format is
function buildPbn ({ boardNumber, cardHolding }) {
const dealer = dealerCompute(boardNumber)
const sortOrder = pbnDirectionCardsOrder[shortDirections[dealer]]
const handString = Object.entries(cardHolding)
.sort(([directionA, _cardsA], [directionB, _cardsB]) => {
return sortOrder.indexOf(directionA) - sortOrder.indexOf(directionB)
})
.map(([_, cards]) => {
return buildPbnCards(
sortPbnCards(cards.map(buildCard))
)
})
.join(' ')
return [shortDirections[dealer], handString].join(':')
}
function sortCardsString (cardsString) {
return cardsString
.split('')
.sort((cardA, cardB) => ranksSorted.indexOf(cardA) - ranksSorted.indexOf(cardB))
.join('')
}
export function buildPbnFromHand ({ boardNumber, hands }) {
const dealer = dealerCompute(boardNumber)
const sortOrder = pbnDirectionCardsOrder[shortDirections[dealer]]
const handsetObjects = hands.reduce((acc, hand) => {
const { direction } = hand
acc[shortDirections[direction]] = {
S: sortCardsString(hand.spades),
H: sortCardsString(hand.hearts),
D: sortCardsString(hand.diamonds),
C: sortCardsString(hand.clubs)
}
return acc
}, {})
const handsetString = Object.entries(handsetObjects)
.sort((directionA, directionB) => sortOrder.indexOf(directionA) - sortOrder.indexOf(directionB))
.map(([_, { S, H, D, C }]) => [S, H, D, C].join('.'))
.join(' ')
return { boardNumber, pbn: [shortDirections[dealer], handsetString].join(':') }
}
export default buildPbn
import dds from 'dds-node-adapter'
import buildPbn from './pbn'
import { vulnerablityCompute, dealerCompute } from 'results/utils/hands'
import { vulnerabilities } from 'results/constants'
const suitsToDDS = {
C: dds.SUIT_CLUBS,
D: dds.SUIT_DIAMONDS,
H: dds.SUIT_HEARTS,
S: dds.SUIT_SPADES,
NT: dds.SUIT_NOTRUMPS
}
const directionToDDS = {
N: dds.HAND_NORTH,
S: dds.HAND_SOUTH,
W: dds.HAND_WEST,
E: dds.HAND_EAST
}
const ddsToSuit = {
[dds.SUIT_CLUBS]: 'C',
[dds.SUIT_DIAMONDS]: 'D',
[dds.SUIT_HEARTS]: 'H',
[dds.SUIT_SPADES]: 'S',
[dds.SUIT_NOTRUMPS]: 'NT'
}
const cardsToDDS = {
2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, T: 10, J: 11, Q: 12, K: 13, A: 14
}
const ddsToCards = {
2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 'T', 11: 'J', 12: 'Q', 13: 'K', 14: 'A'
}
function decodeCardHolding (cardHoldingInteger) {
return Array.from(cardHoldingInteger.toString(2))
.reverse()
.reduce((memo, bitString, index) => bitString === '0' ? memo : memo.concat(index), [])
}
export function evaluateNextMove ({ boardNumber, cardHolding, trump, first, currentTrick }) {
const deal = {
trump: suitsToDDS[trump],
first: directionToDDS[first],
currentTrickRank: currentTrick.map(c => cardsToDDS[c.rank]),
currentTrickSuit: currentTrick.map(c => suitsToDDS[c.suit]),
remainCards: buildPbn({ boardNumber, cardHolding })
}
const options = {
target: dds.TARGET_MAXIMUM,
solutions: dds.SOLUTION_FULL,
mode: dds.MODE_AUTO_SEARCH
}
return dds.solveBoard(deal, options)
.then(({ suit, rank, equals, score }) => {
return rank.filter(r => r > 0)
.reduce((memo, r, i) => {
memo.push({ suit: suit[i], rank: r, score: score[i] })
if (equals[i] > 0) {
decodeCardHolding(equals[i]).forEach(r => {
memo.push({ suit: suit[i], rank: r, score: score[i] })
})
}
return memo
}, [])
.map(cardWithScore => ({
card: `${ddsToCards[cardWithScore.rank]}${ddsToSuit[cardWithScore.suit]}`,
score: cardWithScore.score
}))
})
.catch(err => { throw err })
}
const vulnerabilityToDDS = {
[vulnerabilities.NONE]: dds.VULNERABLE_NONE,
[vulnerabilities.ALL]: dds.VULNERABLE_BOTH,
[vulnerabilities.NS]: dds.VULNERABLE_NS,
[vulnerabilities.EW]: dds.VULNERABLE_EW
}
export async function calculateMinimaxTable ({ pbn, cardHolding, boardNumber }) {
if (!pbn) {
pbn = buildPbn({ cardHolding, boardNumber })
}
const resultTable = await dds.calcResultTable(pbn)
const par = await dds.par(resultTable, vulnerabilityToDDS[vulnerablityCompute(boardNumber)])
return { par, resultTable }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment