Skip to content
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

Clean TicTacToe games up #1311

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Conversation

odanrc
Copy link

@odanrc odanrc commented Feb 23, 2025

Hey!

I wanted to contribute to another project in my spare time, and this one seemed interesting; however, the website suggested checking out tic tace toe (TTT) for perfect information, which was a great suggestion, but then recommended poker and other games for references of imperfect information. I believe this is counterproductive: TTT is much simpler, and if one uses it to learn how to set up a perfect info game, then it should be a smaller step to follow through with phantom TTT, specially given that the poker code is not easily readable for a newcomer.

The problem is that phantom TTT is not a commonly known variant - can we even find a description longer than a paragraph online? - so I decided to clean it up a bit as I understood its code. I also noticed that TTT and variant's code embedded multiple assumptions about TTT's behavior. My goal with this set of commits (and PRs) is to generate abstractions and make TTT (and variants) more generic and easier to understand. These are the results of these commits:

  • Generalized and deduplacted the code in TTT and variants
  • Added GridBoard abstraction, which represents a board made of a grid of tiles
  • Allowed TTT to be instantiated with other dimensions
  • Started implementing a GridBoard::Tile and a Component class

For future PRs I plan to apply these same steps to other games, making implementing games more trivial and standardized.

Possible long-term goals:

  • Break the Game class down into multiple parts. It is doing way too much.
  • Change int typedefs (Action, Player, etc) to real classes, so that they can have properties, instead of relaying that info to the wrong class.
  • Generalize Game::ToString(). There should be an abstract Display/Render class that is able to convert the game state to a visual representation. This representation should not be constrained to a string - i.e., we should be able to polymorphically define if the output will be shown textually, through textures, or other means.
  • Make Phantom a transformer class, not specializations of games

Regarding this PR, it gives an overview of how the TTT and variants look like after the changes. I will likely break it down into multiple PRs, but I want to know what is the reviewers' preference first. I tried to make every commit as self-contained and small as possible, so they should be quite easy to review individually (and I recommend doing so). Do you prefer PRs per commit (or group of very similar commits), per feature, or per number of lines?

Note: On the bright side, the tests caught bugs quite well; on the dark side, though, I often had no idea where to look at to figure out what was breaking, specially when having to deal with python's dynamic typeness. I managed to get through by dumping variables' contents until I found which txt was breaking. Is there a document/tutorial describing how to find what/where things broke? If so, then maybe it should be made more visible in the Developer Guide section. If not, I suggest creating one.

The max game length of an ultimate TTT relies on the max length
of its meta TTT game. Encapsulate this instead of re-implementing
TicTacToe::MaxGameLenth in UltimateTTT::MaxGameLenth.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
The max game length of an phantom TTT relies on the max length
of its underlying TTT game. Encapsulate this instead of re-
implementing TicTacToe::MaxGameLenth in PhantomTTT::MaxGameLenth.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
This helps abstract away how the board is implemented.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
For now this is just a stump, but the idea is to eventually
grow this class to make it encapsulate more functionality
that is common to game boards.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
kNumCells and kNumSubgames have been used interchangeably.
This was only correct because they coincidentally match.
Fix the misuses to reference the correct constant.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
This function allows searching for a line on the board. Its check
were hardcoded to a 3x3 board. Make it more generic by automating
the process.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
Increase the semantic of relying on the size of the board by
creating a respective function. This improves code readability.
It also reduces/centralizes the use of the kNumCells constant,
making it easier to reach the goal of eventually turning it
into a variable.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
The dimensions of a grid board should be known upon
instantiation, and they must be provided by the caller
in order to make the class more generic.

For now we use a vector as the underlying container,
but we should use inplace_vector once supported.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
Use consts instead of hardcoding values and make the
code easier to follow through.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
This information may be needed by users.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
We want to generalize the board size, so use accessor methods
to get the number of actions instead.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
The use of kNumCells as a constant forces a TTT configuration.
Replace these hardcoded uses by dynamic values to allow other
TTT sizes.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
The use of kNumCells as a constant forces a TTT configuration.
Replace these hardcoded uses by dynamic values to allow other
TTT sizes.

As a side effect, UltimateTTTState is now a friend of TTTState,
since the ultimate TTT is a TTT. This makes it easier to share
members between these highly related classes.

Signed-off-by: odanrc <odanrc@yahoo.com.br>
Instead of accessing the global constants, use the board-specific
parameters so that we can eventually replace the constants by
variables.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Make it compatible with TTT, so that it can call TTT´s respective
functions instead of duplicating them.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Call the parent function instead of reimplementing it, to avoid
accidentally introducing bugs and to reduce the dependency on
the constants.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Rewrite this function to avoid reimplementing TTT::ToString.
To do so we create a Display class that is able to manipulate
strings that represent objects in a 2D space.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Use the functions that extract the dimensions of the board
instead of relying on global constants.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Generalize the code to support a different number of
rows and columns.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
This will allow us to convert the board to string in any
class that uses a board, which is the case of PhantomTTT.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Create a function that returns what are the available legal
actions for a given board. Notice that this is likely a
workaround, and it is possible that what we need is to keep
track of the view of each player as a state instead of a board.
For the time being this works to reduce code duplication.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
This is a tiny step to generalize the GridBoard class to make
it easier to be used by other games.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
This will help reduce the use of CellState.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
This will allow avoid using CellState directly.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Prefer using a more generic framework.

Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Copy link

google-cla bot commented Feb 23, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@odanrc
Copy link
Author

odanrc commented Feb 23, 2025

I am confused by this section of the CLA check: ' Uncheck it and re-create the offending commit, ´. What does re-create mean in this context? Force push, or delete the PR and push again?

@lanctot
Copy link
Collaborator

lanctot commented Feb 24, 2025

Hi @odanrc,

Thanks!

Can I double-check that you have followed the link at the top of this screenshot and then, once you've signed the CLA, followed the link at the bottom of this screenshot (After "New contributors": ...)

image

You can find that page by clicking on the "failed invocation" link in this message.

@odanrc
Copy link
Author

odanrc commented Feb 24, 2025

Hey, @lanctot . It looks like my CLA was voided because I didn't make clear my position in the company. Once I get a confirmation of acceptance I will get back to this PR.

@lanctot
Copy link
Collaborator

lanctot commented Feb 27, 2025

Hi @odanrc ,

I had to fix a breakage in the wheel tests. Could you pull changes from master and push the merge commit?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants