Dyota's blog

Games: Harry Poker solver

This is a solver for a game that I call "Harry Poker" (the name is not important, the full rules are not described here). This game is played with a normal deck of cards, 54 cards (4 suits of 13 cards each, plus 2 Jokers).

This is a maths game. Each card in the deck has a numerical value. The numbered cards have the value of the their face values. The other cards are: A = 1, J = 11, Q = 12, K = 13, Joker = 0.

The game is played between multiple players. The object of the game is get as close to a target value as possible. The player who gets closest to the target wins.

The target is a number. Each player gets a hand of three cards. Players must use five arithmetic operations: add, subtract, multiply, divide, and power, to combine the cards in their hand to get a number that is as close to the target as possible.

This script is a solver for this game. Given a target and a hand of cards, it will calculate "how close" that hand can get to the target. It does this by brute-forcing every possible combination of numbers and operations (except for the power operator).

$target = 72

$cards = @( 2, 3, 9 )

# use indices to refer to cards, in case two cards have the same value
$cardIndices = 0..2

$combos = Get-Combination $cardIndices 2

function sum([int]$a,[int]$b) { 
    Write-Host "$a + $b = $($a + $b)"
    return $a + $b
}
function dif([int]$a,[int]$b) { 
    $big = if ($a -gt $b ) { $a } else { $b }
    $small = if ($a -gt $b ) { $b } else { $a }
    
    Write-Host "$big - $small = $($big - $small)"

    # return [Math]::Abs($a - $b)
    return $big - $small
}
function mul([int]$a,[int]$b) { 
    Write-Host "$a * $b = $($a * $b)"
    return $a * $b
}
function div([int]$a,[int]$b) { 
    # only do divison that is greater than 0 (i.e. top number is bigger)
    # and results in an integer

    $big = if ($a -gt $b ) { $a } else { $b }
    $small = if ($a -gt $b ) { $b } else { $a }
    
    if ($small -eq 0) { return $null }
    $div = $big / $small

    if ([int] $div -eq $div) {
        Write-Host "$big / $small = $($div)"
        
        return $div
    } else {
        return $null
    }
}

function pow([int]$a, [int]$b) {
    if ($b -lt 0) { return $null }  # negative exponent = fraction
    
    $result = [Math]::Pow($a, $b)
    
    if ($result -gt [int]::MaxValue) { return $null }  # overflow
    
    Write-Host "$a ^ $b = $($result)"
    return [int]$result
}

function battery($pair) {

    return @(
        sum $pair[0] $pair[1]
        dif $pair[0] $pair[1]
        mul $pair[0] $pair[1]
        div $pair[0] $pair[1]
        pow $pair[0] $pair[1]  # a^b
        pow $pair[1] $pair[0]  # b^a
    )

}

$results = $combos | 
    % {
        $pairIndices = @( $_.item1, $_.item2)

        $pair = @(
            $cards[$pairIndices[0]] # first number
            $cards[$pairIndices[1]] # second number
        )

        [int] $thirdIndex = $cardIndices | ? { $_ -notin $pairIndices }

        [int] $third = $cards[$thirdIndex] # third number

        Write-Host "`nFirst pair: $pair" -ForegroundColor Yellow
        $firstOp = battery $pair
        
        Write-Host "`nSecond pair: $third" -ForegroundColor Yellow
        $secondOp = $firstOp |
            % {
                if ($_ -ne $null) {
                    battery @(
                        [int] $_,
                        [int] $third
                    )
                }
            }

        $away = $secondOp | 
            
            % {
                write-host "$target - $_ = $([Math]::Abs($_ - $target))"
                return [Math]::Abs($_ - $target)
            }

        $away

        if ($away -eq 0) {
            Write-Host "Exact match!" -ForegroundColor Green
            break
        }

    }
    
    
$minimum = ($results | measure -Minimum).Minimum

Write-Host "The minimum is $minimum" -ForegroundColor Green

#cards #powershell #simulation