-
Notifications
You must be signed in to change notification settings - Fork 895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add dou dizhu #969
add dou dizhu #969
Conversation
Nice one!!! I put a comment in the makefile to help with the failing test. |
It is unclaimed, so feel free. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not reviewed the .cc files yet; I will wait for you to make changes to the headers & tests first if that's ok.
@finbarrtimbers Thanks for the review! Here is one issue I am uncertain how to deal with: in several functions I use std::vector& as input type because during the procedures it may dynamically enlarge the vector. It cannot be known how long this vector will be beforehand. Do you know how to use absl::Span in case like this? |
In this case you can pass it in via a pointer,
|
@lanctot Thanks! |
Yes, sorry, I might have mentioned One slight difference to what Marc said- If you're not modifying the container or any of the objects within it, specify the type as If you're modifying the objects within the container, then the type should be specified as Span is an abstraction around fixed-size, contiguous blocks of memory ( |
else SpielFatalError("Non valid rank"); | ||
} | ||
|
||
std::string FormatSingleHand(const std::array<int, kNumRanks>& hand){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is an example of something that should be a Span. It should convert automatically.
} | ||
|
||
// given a single-rank hand, map it to action id | ||
int SingleRankHandToActionId(const std::array<int, kNumRanks>& hand){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another example of Span, as you're not modifying the hand container (or any of the members).
// given an arbitrary hand, search for possible single-rank hands | ||
// if prev_action = kInvalidAction, search for all possible such hands | ||
// otherwise, only search for those that are ranked higher than prev_action | ||
void SearchSingleRankActions(std::vector<Action>* actions, const std::array<int, kNumRanks>& hand, int prev_action = kInvalidAction){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This signature is a good example too- actions is great as a pointer, while hand should be a Span.
// and the result hand is stored in ans_hand reference | ||
bool dfs_airplane_kicker(int chain_length, int depth, | ||
int target_count, int& count, int max_search_rank, | ||
int* used_rank, int* ans_hand, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I was unclear/did a bad job reviewing this.
Originally, these were std::array<int, kNumRanks>&
. I think that the type here should be absl::Span<int>
.
You would convert them into a span like this:
dfs_airplane_kicker(chain_length, depth+1, target_count, count, rank, absl::MakeSpan(used_rank), absl::MakeSpan(ans_hand), kicker_type)
// a dfs backtrack algorithm that found the action ids of all possible airplane combination | ||
// the action ids are stored in action_ids reference | ||
void dfs_add_all_airplane_kickers(int chain_head, int chain_length, int depth, int max_search_rank, | ||
int* used_rank, const int* ans_hand, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, here, I think that you should make this signature:
absl::Span<int> used_rank, absl::Span<const int> ans_hand, std::vector<Action>* action_ids
(and call absl::MakeSpan(used_rank)
on the calling code).
I went through and made some comments about specific signatures- please let me know if that helps or if you have any questions. Thanks for working with me on this review- I think you're 95% of the way there, just a few changes to make, mostly just swapping some function signatures. |
Thanks that helps a lot! Some final questions.
|
|
Thanks! The arguments should now all be changed to absl::Span if they can. |
This looks great! I'll be merging this internally, and it should be merged at head soon. Thanks for working with me, @rezunli96! |
Thank you @finbarrtimbers for such a thorough review and great advice! |
Hi, I implemented dou dizhu.
After some thinking process, there are a few places that I implemented differently from what Wikipedia described. Specifically, for the hand category airplane+solo, I decided to permit cases like 333-444-555-7-7-7. E.g., pairs, trios can be kickers. For more details, please see my blog.
Also, I plan to implement mahjong in the future if nobody had claimed it yet.