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

Make structures, waypoints, and tagmembers commands return lists #2260

Merged
merged 13 commits into from
Jan 6, 2025

Conversation

byorgey
Copy link
Member

@byorgey byorgey commented Jan 4, 2025

Closes #1997.

Change structure, waypoint, and tagmembers to return lists; also make waypoint, tagmembers and hastag pure functions, since their output within a given scenario will never change.

More specifically:

  • Changes the type of waypoint : Text -> Int -> (Int * Int) to just return the waypoint with the given index (wrapping around), or throw an exception if there are no waypoints with the given name.
  • Adds a new waypoints : Text -> (rec l. Unit + Text * l) function that returns the list of all waypoints with a given name.
  • Change structure to structures : Text -> Cmd (rec l. Unit + (Int * Int) * l), returning the list of all structure locations of the given name
  • Change tagmembers to have type tagmembers : Text -> (rec l. Unit + Text * l)
  • Change hastag to have type hastag : Text -> Text -> Bool

In the vast majority of cases, this greatly simplified the code for various scenario setups and solutions, though there is still a bit of code duplication for things like calculating the length of a list. But even this can easily be improved once we have #495 and can make a standard library of list functions and import it within scenario code.

The reason I kept an indexing function for waypoints but not for structures or tags is that iterating through waypoints incrementally while doing other stuff in between seems like a common thing to want to do, and passing around a list of waypoints and manually indexing into it sounds tedious. However, for structures and tags this is much less common; typically we just want to get a list and then do something with all of them right away.

@byorgey
Copy link
Member Author

byorgey commented Jan 4, 2025

@kostmo There's obviously still a bunch of work to do to fix up more failing tests, but I'm curious if you have any feedback at this point. Does this seem like a reasonable direction?

One thing I'm realizing is that this makes a lot more sense for structures and tagmembers than it does for waypoints. Being able to request individual waypoints by index seems a lot more useful since you frequently want to iterate through them.

@byorgey
Copy link
Member Author

byorgey commented Jan 4, 2025

However, I still don't really like the conceit of always returning a pair of the total number of waypoints and the waypoint with the requested index. What about providing two functions: waypoints : Text -> List (Int * Int) and waypoint : Text -> Int -> Int * Int which does wrap-around indexing into the list for you (and crashes if the list is empty)?

Relatedly, @kostmo, do you know of a good reason why tagmembers and waypoint need to be in the Cmd monad? structures I understand --- the structures you get can change depending on what entities get placed, so the sequencing matters. However, aren't the results of waypoint and tagmembers fixed and deterministic within a given scenario? It seems to me like they could just be pure functions.

@kostmo
Copy link
Member

kostmo commented Jan 4, 2025

do you know of a good reason why tagmembers and waypoint need to be in the Cmd monad?

Looks like I didn't make any notes in #1635 or #1356, so I suppose the choice was arbitrary. I'd be open to making them pure functions.

isOrganism <- hastag item "organism";
return $ inR item;
);
scan down;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kostmo the existing code called hastag item "organism" but then ignored the result. Was that a mistake?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it probably is a mistake. It should return inL if it is not an organism.

@byorgey byorgey marked this pull request as ready for review January 5, 2025 22:24
@byorgey byorgey requested a review from kostmo January 5, 2025 22:24
Copy link
Member

@kostmo kostmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite a feat!


if (idx < total) {
if (idx < force bustCount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does force do here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I first converted this scenario it was failing, and running it with --autoplay revealed that it was failing because the base started running its program before the level was set up. The problem was that evaluating the definition of bustCount actually took multiple ticks, before the judge robot ever got around to executing its instant setup. So I wrapped it in a delay so it wouldn't be evaluated at definition time.

I'm just realizing now, however, that this means it's going to be re-evaluated every time we force it (IIRC we don't have memoizing delay). Perhaps a better idea would just be to wrap the entire program (including all the defs) in instant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For word-search (#999), I trapped the player behind a boulder until the playfield was set up :) Though I think that may have been before the instant command was available.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strangely, wrapping the entire program in instant doesn't seem to work! Not sure if this is a bug or what.

@byorgey byorgey added the merge me Trigger the merge process of the Pull request. label Jan 5, 2025
@mergify mergify bot merged commit e26bfe5 into main Jan 6, 2025
15 checks passed
@mergify mergify bot deleted the feature/use-lists branch January 6, 2025 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge me Trigger the merge process of the Pull request.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change tagmembers to return a list
2 participants