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

New ranching scenario #835

Merged
merged 2 commits into from
Nov 14, 2022
Merged

New ranching scenario #835

merged 2 commits into from
Nov 14, 2022

Conversation

kostmo
Copy link
Member

@kostmo kostmo commented Nov 5, 2022

Demo with:

stack run -- --scenario Challenges/Ranching/gated-paddock --autoplay

The primary element of this scenario is "testing for a closed loop" in the objective condition. As written, this test is performed every "tick", and introduces noticeable rendering lag at higher "ticks / s" speeds.

What may be better is for the player to "ask" for the condition to be checked, perhaps by standing somewhere specific, picking up a particular object, or even with say "Ready!".

@byorgey
Copy link
Member

byorgey commented Nov 5, 2022

I understand why you want to have a gated-paddock subdirectory to hold all the .sw files for the scenario. But currently this means the test suite spits out a ton of warnings about not finding an 00-ORDER.txt file in that directory. We should either add an empty 00-ORDER.txt file in gated-paddock just to make it shut up, or (probably the better long-term solution) make the scenario loading code ignore any directories that don't contain any .yaml files.

@byorgey
Copy link
Member

byorgey commented Nov 5, 2022

One of the first things I did was make a logger and install it on myself so I could see errors. Is that intended, or should we install a logger on the base robot to start?

@kostmo
Copy link
Member Author

kostmo commented Nov 5, 2022

We should either add an empty 00-ORDER.txt file in gated-paddock just to make it shut up, or (probably the better long-term solution) make the scenario loading code ignore any directories that don't contain any .yaml files.

I think we'll have to go with the latter; I tried creating an empty data/scenarios/Challenges/Ranching/gated-paddock/00-ORDER.txt file, and the warnings are still there:

Warning: while processing Ranching/00-ORDER.txt: files not listed in 00-ORDER.txt will be ignored
- gated-paddock

@kostmo
Copy link
Member Author

kostmo commented Nov 5, 2022

One of the first things I did was make a logger and install it on myself so I could see errors. Is that intended, or should we install a logger on the base robot to start?

Good idea, will add it.

@byorgey
Copy link
Member

byorgey commented Nov 5, 2022

Completed in 4m37s! 😁 Two of the stupid sheep had drowned themselves by the time I finished making fences but one was still around.

Based on the goal description I was kind of surprised that there wasn't another step after building the fence (like harvesting wool or something). Are you intending to extend the scenario in the future?

@kostmo
Copy link
Member Author

kostmo commented Nov 5, 2022

Are you intending to extend the scenario in the future?

Yes, good catch. Figured I'd get some early feedback first.

Copy link
Member

@byorgey byorgey left a comment

Choose a reason for hiding this comment

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

I love it!

@xsebek
Copy link
Member

xsebek commented Nov 5, 2022

@kostmo if you wait a little, I can look into optimizing the goal condition. 😉

But I would like to play it first without getting spoiled by having seen the solution. 😅

@byorgey
Copy link
Member

byorgey commented Nov 6, 2022

Does it require you to have all the sheep inside the fence, or at least one? I played again and made a small fence around one sheep but nothing happened... so I went to make a screenshot to report a bug, and when I was done making the screenshot it suddenly congratulated me on winning. @noahyor suggested it might be because all the other sheep died. Seems a little strange that you can win when a sheep dies rather than winning when you have actually completed something.

Copy link
Member

@xsebek xsebek left a comment

Choose a reason for hiding this comment

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

It took me a while to finish, but I enjoyed it a lot. 👨‍🌾 🐑

I have a lot of small suggestions for improvement, if you disagree with any of them please explain why so that I can understand the challenge better. 😉

data/scenarios/Challenges/Ranching/gated-paddock.yaml Outdated Show resolved Hide resolved
data/scenarios/Challenges/Ranching/gated-paddock.yaml Outdated Show resolved Hide resolved
data/scenarios/Challenges/Ranching/gated-paddock.yaml Outdated Show resolved Hide resolved
display:
invisible: false
char: '@'
system: true
Copy link
Member

Choose a reason for hiding this comment

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

If the sheep were not system robots, I would be able to see them in the robot panel.

I don't think there is any way to exploit sheep as normal robots.

If it's about all the devices that they would require, just create one device that has all the capabilities. You could call it the "golden fleece".

Copy link
Member Author

@kostmo kostmo Nov 6, 2022

Choose a reason for hiding this comment

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

If the sheep were not system robots, I would be able to see them in the robot panel.

I think I would prefer that they don't appear in the robot panel; they are "NPCs".

Copy link
Member

Choose a reason for hiding this comment

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

Sure, but system robots have the powers of gods... such sheep could literally walk through walls. 🤣

Besides they belong to the farmer who owns the island, so they are more pets than NPCs. 🙂

Comment on lines 21 to 23
b <- blocked;
if b {} {
move;
Copy link
Member

Choose a reason for hiding this comment

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

The sheep could crash in rare cases, consider atomic:

Suggested change
b <- blocked;
if b {} {
move;
atomic (b <- blocked; if b {} {move});

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried adding atomic, but now the blocked-checking logic is larger, and the compiler refuses to allow atomic around it.

Copy link
Member

Choose a reason for hiding this comment

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

@kostmo AFAIK, we do not allow definitions. If you inline it then it should be fine, because only the move is observable.

Copy link
Member

Choose a reason for hiding this comment

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

@kostmo did you try inlining the functions? I don't care as much about the sheep crashing into a fence as I would like to know if the atomic command is usable. 😉

@xsebek
Copy link
Member

xsebek commented Nov 6, 2022

@kostmo I wrote #836 which could be used to speed up the objective checking if we used Haskell for pathfinding. 🙂

It could be useful in other situations too, but it would be a bit harder to implement.

Also, it would allow us to taunt sheep with food like in Minecraft if that is something you are interested in. 😄

@kostmo
Copy link
Member Author

kostmo commented Nov 6, 2022

Does it require you to have all the sheep inside the fence, or at least one?

@byorgey The buggy behavior is an artifact of using robotnamed, which is kind of a hack:

  r <- robotnamed "sheep";

Perhaps it would have worked if robotnamed did a dynamic lookup based on the currently existing robots, but as is, the name is fixed to an (arbitrary) sheep's robot ID upon scenario initialization.

I explored using r <- robotnumbered i and iterating up to an a-priori-known index (hard-coded to how many robots I've defined in the scenario), and checking if whoami is "sheep". However, then I was no longer able to satisfy the typechecker with the run command.

@xsebek
Copy link
Member

xsebek commented Nov 6, 2022

@kostmo maybe you could name the individual sheep? Either funny names like "Shaun" or just use the dull "sheep #1".

With the latter, you can use "sheep #" ++ format i.

@kostmo
Copy link
Member Author

kostmo commented Nov 6, 2022

maybe you could name the individual sheep?

Yes, that's one workaround. I guess I am being stubborn because I feel I should not have to create a new robot entry in the scenario for each sheep---I prefer to have just one sheep template robot.

- [1, hinge]
- [1, fence]
out:
- [1, gate]
Copy link
Member

Choose a reason for hiding this comment

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

👍

mergify bot pushed a commit that referenced this pull request Nov 6, 2022
Such subdirectories can be used to e.g. organize `.sw` files, and will be ignored when recursively loading scenarios.

This resolves an issue we noticed while reviewing #835, which uses a subdirectory to hold multiple `.sw` files for a scenario and was generating a lot of spurious warnings.
@byorgey
Copy link
Member

byorgey commented Nov 6, 2022

@kostmo I just merged #837 which means if you rename your gated-paddock subdirectory to _gated-paddock it will no longer generate warnings. Any subdirectory starting with _ is ignored for the purposes of loading scenarios.

seed: 0
solution: |
run "scenarios/Challenges/Ranching/gated-paddock/fence-construction.sw"
world:
Copy link
Member

Choose a reason for hiding this comment

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

@kostmo maybe add seed, so that the sheep always do the same thing.

I hope it is unlikely, but it could save us some headaches in the future if the sheep randomly came up with some clever escape plan. 🐑

Copy link
Member

@byorgey byorgey Nov 6, 2022

Choose a reason for hiding this comment

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

It would also make the solution more stable. Currently, there is always the unlikely possibility the sheep will all decide to run straight into the ocean before you build the fence. 😆

Copy link
Member Author

Choose a reason for hiding this comment

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

add seed

Actually I have seed: 0 already on line 136. But I wonder if there's global influence on the random number generation that causes the sheep to behave non-reproducibly? Perhaps robot-local random number generators would help?

Copy link
Member

Choose a reason for hiding this comment

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

@kostmo Oh, my mistake then. 👍 The only other source of nondeterminism I can think of would be the order of elements in an unordered container. That may or may not have an effect here.

You can check that by listing the sheep location at the end and then testing that they are always the same
using testSolution'.

Copy link
Member

Choose a reason for hiding this comment

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

But I wonder if there's global influence on the random number generation that causes the sheep to behave non-reproducibly?

If there is, it's a bug.

@xsebek
Copy link
Member

xsebek commented Nov 6, 2022

I guess I am being stubborn because I feel I should not have to create a new robot entry in the scenario for each sheep---I prefer to have just one sheep template robot.

@kostmo indeed we run into that before and there are issues discussing this:

If you want, you can add a TODO with those issue numbers so that once those are implemented we remember to also improve this scenario. 🙂

@xsebek
Copy link
Member

xsebek commented Nov 6, 2022

Perhaps it would have worked if robotnamed did a dynamic lookup based on the currently existing robots, but as is, the name is fixed to an (arbitrary) sheep's robot ID upon scenario initialization.

@kostmo are you sure? I was able to view the last surviving robotNamed "sheep" just fine.

It very much should do a dynamic lookup based on the current robot map in the game state. If not then that is a bug in my implementation of robotNamed. 😄

EDIT: this looks dynamic to me:

-- | Get the robot with a given name.
robotWithName :: (Has (State GameState) sig m) => Text -> m (Maybe Robot)
robotWithName rname = use (robotMap . to IM.elems . to (find $ \r -> r ^. robotName == rname))

@byorgey
Copy link
Member

byorgey commented Nov 6, 2022

I guess the point is that each time step, there is one specific "magic" sheep which has to be enclosed, but there is no way to know which one it is. If you guess wrong and enclose one of the other sheep, you will not win until such time as the magic sheep dies; then the next time the check runs a different sheep will be selected. If it is the one inside your fence, you win! Otherwise, you have to wait for that one to die too.

@kostmo
Copy link
Member Author

kostmo commented Nov 6, 2022

are you sure?
[...]
It very much should do a dynamic lookup

@xsebek You're right - I made the wrong inference about the behavior of robotWithName (should have read the code first). @byorgey explains it properly. When there still exist multiple sheep, the one retrieved with robotnamed "sheep" is arbitrary.

@kostmo kostmo self-assigned this Nov 12, 2022
@kostmo
Copy link
Member Author

kostmo commented Nov 12, 2022

Ok, my solution checker now accounts for all three sheep.
I also added two more goals and tweaked the map.

I'm pretty happy with the scenario now. Give it another try?

Copy link
Member

@xsebek xsebek left a comment

Choose a reason for hiding this comment

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

The game feels much more responsive now, great job @kostmo! 👍

Please just clarify the goal condition in the description or make it easier again.

I have a few other notes, but those are not blockers and I think we could merge this afterwards. 🙂

};

if (justFilledGap) {
allSheep checkIsEnclosed 3;
Copy link
Member

Choose a reason for hiding this comment

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

Well, that is a lot harder now, previously it was enough to save some of the sheep. 😕

Now if just one of the sheep drowns, I can no longer win.

Imagine the following scenario:

  1. Sheep number 1 randomly runs straight into the ocean
  2. The player does not notice
  3. Player successfully paddocks all remaining sheep
  4. Player waits for the checks to finish
  5. The game slows down as it checks the condition every tick
  6. Player wonders what is wrong

Please do at least one:

  1. note what is actually required in the goal description
  2. simplify the goal condition to require just anySheep
  3. move the goal condition to a helper "judge" robot
    • judge robot is loaded once so it can use run
    • judge robot could run the condition in as on each tick
    • the goal condition would check that judge has "win" or something
    • the judge can interact with the environment, in particular, it can say what the player is doing wrong
      • e.g. say "One sheep has drowned, please start over!"

Copy link
Member

Choose a reason for hiding this comment

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

Also, the judge robot could remember that it already checked the fence connection and not check again on the next tick until the player moves. This would be another speedup. 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Ohh, I ran into exactly this scenario. One sheep drowned and I did not realize that would prevent me from winning. What's worse, when I completed the fence but was still sitting on top of the last fence I placed, it pegged my CPU at 100% and the game at 30 ticks per frame, 0.1 fps. =( It was so sluggish I had to wait like 5-10 seconds just to switch to a different panel in the UI. As soon as I moved off the fence (with great difficulty, waiting 5-10 seconds in between each UI action) the game suddenly sped up again.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have now relaxed the goal to just save one sheep.

Copy link
Member Author

Choose a reason for hiding this comment

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

the judge robot could remember

Is there a way to have a persistent "judge" robot that can execute an entire program in one tick?
Also, my judge-algorithm modifies/destroys the environment, so it would have to execute in a "sandboxed" state that is rolled back/discarded upon completion of its program.

What may be useful (and would be facilitated by #795) is if there existed a god-capability command that can check if a specific (named) goal has been already achieved.

Copy link
Member

Choose a reason for hiding this comment

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

Is there a way to have a persistent "judge" robot that can execute an entire program in one tick?

We normally use system robots with the as command, which is as powerful as you can get.

@byorgey
Copy link
Member

byorgey commented Nov 12, 2022

I have now restarted four times and have not yet been able to get all the sheep in a fence before they drown. It seems like the only way to win is to write a program that will automatically do all the actions of harvesting trees, making fence, and placing the fence so that it can happen fast enough to catch the sheep. But this feels very irritating.

@byorgey
Copy link
Member

byorgey commented Nov 12, 2022

I also don't understand the point of the post puller and the fact that it leaves behind scrap wood that you cannot do anything with and cannot pick up. It means that once you have placed a fence somewhere you will never be able to use that spot for anything else. For example if you create an unbroken fence and then decide you want to place a gate in the fence, it is kind of difficult to do because you cannot place a gate on top of a pile of scrap wood.

Why not just let players pick up scrap wood?

@byorgey
Copy link
Member

byorgey commented Nov 12, 2022

Finally managed to beat it. The other two objectives are fun, though after the fence building the last objective seemed too easy. How about requiring a certain number of wool (say, 10?) instead of just one?

@xsebek
Copy link
Member

xsebek commented Nov 12, 2022

Btw. sorry for being so perfectionist @kostmo, please understand that I am simply trying to make this as good and fun as possible. 😅 I have limited time due to work and school, so my comments might seem a little brisk.

If you ever feel too tired to deal with all of my nitpicks, just comment which one you want to do and others I can do myself. 😉

@kostmo
Copy link
Member Author

kostmo commented Nov 12, 2022

It seems like the only way to win is to write a program

Ah that's a pitfall of "writing to the integration test" as a scenario designer. I tend to forget that the player will have to re-invent the program that I spent so long perfecting :)

I hope it's more reasonable now with the new single-sheep requirement.

don't understand the point of the post puller

Fixed. Using the post puller now lets one recover a board.

How about requiring a certain number of wool

I've modified the goal to knit sweater from 3 wool. I actually at first tried to code the goal to win directly on obtaining 3 wool, but the following goal evaluation code does not work. A bug, perhaps?

  as base {
    woolCount <- count "wool";
    return (woolCount >= 3);
  };

Finally, for code reviews which may become large, may we adopt a practice of making every comment a "threaded" comment to make the replies easier to follow? The way to do this in GitHub seems to be to attach the comment to a line of code (that line may have to be arbitrary). The toplevel (non-code-attached) comments do not facilitate long reply chains well.

@byorgey
Copy link
Member

byorgey commented Nov 12, 2022

I hope it's more reasonable now with the new single-sheep requirement.

Yes, indeed. The most recent time I played one sheep pretty much immediately drowned itself but I was able to fence the other two.

I think this also solves my issue with the CPU being pegged at 100%, since that would only happen when the base is sitting on top of a fence, we just closed a gap, but you haven't won. I guess that could still happen in theory if there are NO sheep inside the fence? But that seems less likely.

Fixed. Using the post puller now lets one recover a board.

Yes, that's much nicer, thanks!

I've modified the goal to knit sweater from 3 wool.

I like it.

I actually at first tried to code the goal to win directly on obtaining 3 wool, but the following goal evaluation code does not work.

Hmm, strange. Not sure what's going on there.

Finally, for code reviews which may become large, may we adopt a practice of making every comment a "threaded" comment to make the replies easier to follow? The way to do this in GitHub seems to be to attach the comment to a line of code (that line may have to be arbitrary). The toplevel (non-code-attached) comments do not facilitate long reply chains well.

Ah, good idea. I made top-level comments since they did not really pertain to a specific line of code, but you're right that the threading is much nicer for comments attached to lines of code.

Copy link
Member

@byorgey byorgey left a comment

Choose a reason for hiding this comment

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

I think it works great now and all my concerns have been addressed! Beat the most recent version in 6m 52s. 😄

@kostmo
Copy link
Member Author

kostmo commented Nov 12, 2022

@xsebek can you update the "requested changes" status of your review? As is, merging is blocked.

@kostmo
Copy link
Member Author

kostmo commented Nov 12, 2022

I actually at first tried to code the goal to win directly on obtaining 3 wool, but the following goal evaluation code does not work.

Hmm, strange. Not sure what's going on there.

Created #858

Copy link
Member

@xsebek xsebek left a comment

Choose a reason for hiding this comment

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

Thanks for the great challenge @kostmo!

image

I look forward to other ranching challenges. 🤠

@kostmo kostmo added the merge me Trigger the merge process of the Pull request. label Nov 14, 2022
@mergify mergify bot merged commit 8e98ddd into main Nov 14, 2022
@mergify mergify bot deleted the ranching branch November 14, 2022 03:23
@byorgey
Copy link
Member

byorgey commented Nov 14, 2022

🎉 🚀 ❤️

Pretty sure 118 comments is a new record. 😄

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.

3 participants