dominicprice / endplay

A suite of tools for generation and analysis of bridge deals. Read the documentation at https://endplay.readthedocs.io
MIT License
21 stars 5 forks source link

Feature Request for generate_deals and calc_all_tables Pattern #11

Open BSalita opened 2 years ago

BSalita commented 2 years ago

I propose some features to make the following code pattern easier and more obvious.

  1. DealList.to_list() which returns a Python list of Deal. The issue is when I access d after calc_all_tables, I get an address exception so the workaround is to create a Python list/tuple before calc_all_tables, hence d_t = tuples(d).
  2. DDTableList.ResTable.to_list() which returns a Python list of lists (list of directions containing list of suits), ordered same as pprint() tuple(tuple(sd[suit][direction] for suit in [3,2,1,0,4]) for direction in [0,2,3,1])?
  3. Question: Why is resTable.pprint() ordered as NSWE instead of NSEW or NESW?
    d = generate_deals()
    d_t = tuple(d) # create a tuple before Deal storage goes wonky
    tables = calc_all_tables(d_t)
    t_t = (tt._data.resTable for tt in tables)

    for ii,(dd,sd,tt) in enumerate(zip(d_t,t_t,tables)):
        print(f"Deal: {ii+1}")
        dd.pprint()
        print()
        tt.pprint()
        print(tuple(tuple(sd[suit][direction] for suit in [3,2,1,0,4]) for direction in [0,2,3,1]))
        print()
dominicprice commented 2 years ago

generate_deals is a generator, so in the same way you might write list(range(n)) or list(permutations(l)) to collect the deals into a list you should do d = list(generate_deals()) - there isn't a DealList object as such. I think this idiom is common enough, and lazy evaluation has enough upsides, that it is ok as is but I am open to counter arguments.

Is there a particular reason you would like the DDTable as a 2D list? Seeing as it is trivial to add to_list I have put it in though. The reason for classes such as DDTable and DDTableList is that they just wrap the underlying C structs, avoiding making copies of the underlying data each time the dds interface is called. In the case above, the code could be rewritten using the __getitem__ operator of DDTable:

from endplay import *

deals = list(generate_deals())
tables = calc_all_tables(deals)

for ii, (dd, tt) in enumerate(zip(deals, tables)):
    print(f"Deal: {ii+1}")
    dd.pprint()
    print()
    tt.pprint()
    print(tuple(tuple(tt[s, p] for s in Denom.bidorder()) for p in Player.iter_order("NSEW")))
    print()

It might be worthwhile me making it easier to customize the order of iteration of the enumerations though.

As for why the pprint order is NSWE: I agree, NSEW is more logical. I have changed that to the default, but added players and denoms parameters which let you customize the table to display any subset.