thomasoa / andrews-deal

Automatically exported from code.google.com/p/andrews-deal
Other
10 stars 6 forks source link

New "symmetrize" command #13

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

I love the double-dummy solver from Bo in Deal.

Back in January 2000, Alex Martelli's article in "The Bridge World"
discussed the value of "symmetrization" in simulation results. The
particular context there was measuring the value of one hand with the other
three unknown. Given three such unknown hands, the average of the measured
quantity over all six permutations of their location is a more reliable
estimator of the true quantity than the value of the measured quantity on
only one permutation. Similarly, for evaluating the double-dummy expectancy
of a contract given a pair of hands, computing both permutations of
defensive hands reduces the likelihood that the simulation data is skewed
by favourable finesses, etc.

Thus, to reproduce Martelli's work one might like to be able to say

sdev thetricks
south is "KQJT987 432 32 2"
set denomination spades

main {
    symmetrize { thetricks add [tricks south $denomination] } { east west
north }
    accept
}

deal_finished {
    puts "[thetricks average] [thetricks count]"
}

or to evaluate slam on a finesse:

sdev thetricks
north is "AQJ J543 432 432"
south is "432 AKQ2 AKQ AKQ"
set denomination notrump

main {
    symmetrize { thetricks add [tricks south $denomination] } { east west }
    accept
}

deal_finished {
    puts "[thetricks average] [thetricks count]"
}

So, using your undocumented "rotatehands" function as a guide, I added such
a symmetrize command and it seems to work well. I can reproduce Martelli's
results, and the above slam's trick expectancy is slightly over 12.5 (stiff
SK always gets dropped). If the list of labile hands has only one hand,
then the script gets executed transparently on the existing deal, which
might be desirable behaviour in some weird circumstance.

I'm happy to document and make this feature available in the next release
if you are interested.

Thanks again for your software, which I have loved for many years!

Mark

Original issue reported on code.google.com by Mark.J.A...@gmail.com on 14 Aug 2009 at 3:20

GoogleCodeExporter commented 9 years ago
Hmm, sorry, didn't meant to classify this as a defect, but I never saw where I 
could
specify!

Original comment by Mark.J.A...@gmail.com on 14 Aug 2009 at 3:20

GoogleCodeExporter commented 9 years ago
Sorry I missed this submission.  I'd love to see your script.

Original comment by thomasoa on 24 Feb 2010 at 3:30

GoogleCodeExporter commented 9 years ago

Original comment by thomasoa on 24 Feb 2010 at 3:30

GoogleCodeExporter commented 9 years ago
Actually it's not a script. I modified the C source. Attached is a patchfile 
suitable
for running from the directory above a deal 3.1.7 source directory.

Original comment by Mark.J.A...@gmail.com on 2 Mar 2010 at 4:06

Attachments:

GoogleCodeExporter commented 9 years ago
I'm currently using this functionality in a "child" Deal process. Having dealt 
a pair
of partnership hands that matches some complex constraints for bidding 
practice, I
then want to deal a series of opponents hands, and evaluate relevant 
denominations
from each side over both permutations of the opponents' hands. Averaging over 
100
hands or so gives numbers accurate to around 0.1 trick which is more than good 
enough
to decide "Did we reach the right contract?"

The simplest way to do this is to call 

    eval [exec ./deal -e "north is \"[north]\"; south is \"[south]\"; set
denominations {$calcdenominations}; set format \"%.1f\"" -i averagetricks.tcl
$num_hands_to_analyze]

from the parent script, where averagetricks.tcl is

source format/none

if {![info exists denominations]} {
    set denominations [list notrump]
}

set results [dict create]
foreach denomination $denominations {
    foreach declarer { north south } {
        set name "$declarer$denomination"
        sdev $name
        dict set results $declarer $denomination $name
    }
}

main {
    foreach denomination $denominations {
        symmetrize {
            eval [dict get $results south $denomination] add [deal::tricks south
$denomination]
            eval [dict get $results north $denomination] add [deal::tricks north
$denomination]
        } { east west }
    }
    accept
}

deal_finished {
    foreach denomination $denominations {
        foreach declarer { north south } {
            set value [eval [dict get $results $declarer $denomination] average]
            if {[info exists format]} {
                set value [format $format $value]
            }
            puts -nonewline "dict set results $declarer $denomination $value; "
        }
    }
    puts ""
}

I believe the ordering of calls to deal::tricks is optimal. You want to recycle 
some
of the data when only the opening lead is changing, and can't do so when the 
hands
are changing.

Original comment by Mark.J.A...@gmail.com on 2 Mar 2010 at 4:30