By John Lekberg on February , .
This week’s post will cover a command line tool that helps you play the video game
Stardew Valley .
Stardew Valley is a farming game (like Harvest Moon . You can manually water your crops, or you can use sprinklers to automate the process.
I wrote a Python script, sprinkler-layout
, that designs a layout of sprinklers for me, for a given number of sprinklers (eg sprinklers). The goals of the layout are:
water as much land as possible. have a reasonably small perimeter.
sprinkler-layout
#! / usr / bin / env python3 import itertools class Layout: “A layout of sprinklers on a grid.” def __init __ (self): self._sprinklers=set () self._watered_squares=set () @classmethod def generate (cls, *, num_sprinklers, coordinates): Generate a layout, given: - how many sprinklers to place. - which positions to attempt to place them at. “” layout=cls () while layout.count_sprinklers () -radius: yield x, y y -=1 while x> -radius: yield x, y x -=1 while y $ sprinkler-layout --help Usage: sprinkler-layout [-h] --sprinklers N generate a layout of sprinklers for Stardew Valley. optional arguments: -h, --help show this help message and exit --sprinklers N the number of sprinklers to place I'm starting a new farming season in Stardew Valley and I have sprinklers available. I use sprinkler-layout to design a layout:
$ sprinkler-layout --sprinklers 32 sprinklers watered squares (x) squares, including perimeter wall square perimeter map of sprinklers (3 by 3 blocks) ... ... ... ... .. ... ... ... #. .. # .. # ... ... .. ... ... #. .. # .. ... # .. ... # .. .. #. .. # ... ... .. ... ... .. # .. # .. ... # .. # .. ... .. #. ... ... #. .. ... .. # .. # ... .. ... # .. ... ... #. ... ... # .. # .. .. .. # ... ... .. # .. .... #. ... ... ... ... ... .. Then:
I construct the required materials squares of walls for the perimeter). I clear out enough space for the layout (a grid of by (squares). I place sprinklers as shown in the layout ( # ). I place the walls around the perimeter. I use a custom class, Layout , to represent a sprinkler layout. Layout manages the internal state of:
Where sprinklers have been placed. Which positions are watered by the placed sprinklers. -
Layout (has a) (class method) , generate , that attempts to position sprinklers by choosing from given positions. generate uses a greedy strategy to place the sprinklers:
Loop until I have placed enough sprinklers: Get the next position to try.
If I can place a sprinkler at this position, do it.
-
I check if I can place a sprinkler by using sets of coordinates and checking that these sets are disjoint :
the set of the new sprinkler and its watered squares. the set of already placed sprinklers and their watered squares.
I have a generator function, spiral_coordinates , the generates positions in a spiral that looks like this: (starting from the center)
( ^ ^ ^ v v>>> ^ ^ v>>>>> ^> ... I use this technique because it designs good enough layouts for me. spiral_coordinates is simple to implement and keeps the overall perimeter of the layout small.
The report function, print_report , computes a bounding box that encloses:
the sprinklers that have been placed. the squares that are watered by the placed sprinklers. Then, I take into account a 1 square thick perimeter wall and report:
The dimensions of the bounding box. The perimeter of the bounding box. The report generates a map of the placed sprinklers and partitions it into chunks:
... ... ... ... ... #. .. # .. # ... ... .. ... ... #. .. # .. ... # .. ... # .. .. #. .. # ... ... .. ... ... .. # .. # .. ... # .. # .. ... .. #. ... ... #. .. ... .. # .. # ... .. ... # .. ... ... #. ... ... # .. # .. .. .. # ... ... .. # .. .... #. ... ... ... ... ... .. I find the map harder to read without the partitioning:
...... ............ #. .. # .. # ........ ....... # ... # .. ... # ..... # .... # ... # ........ ........ # .. # .. ... # .. # ....... # ........ # ... ..... # .. # ..... ... # ........ #. ...... # .. # .... .. # ........ # .. .... # .. # ...... .............. This week's post covered a Python script that assists people playing Stardew Valley by designing a layout of sprinklers. You learned about:
Using Python classes to manage internal state. Using Python sets to check if two sets of positions are disjoint.
Using a simple greedy strategy to make decisions (placing the sprinklers). My challenge to you:
Create a different way to generate coordinates than spiral_coordinates .
For example, here's what a placement of 8 sprinklers looks like with spiral_coordinates :
(Layout.generate) num_sprinklers=8, coordinates=spiral_coordinates () ) .print_report () 8 sprinklers 42 watered squares (x) squares, including perimeter wall 62 square perimeter map of sprinklers (3 by 3 blocks) ... #. .... ... # .. ... ... ... # .. #. #. ... ... ... # .. # .. ... And here's a placement of 8 sprinklers that tries positions only in a horizontal line:
from itertools import count Layout.generate ( num_sprinklers=8, coordinates=((i, 0) for i in count ()) ) .print_report () 8 sprinklers 42 watered squares 32 x 5 squares, including perimeter wall 66 square perimeter map of sprinklers (3 by 3 blocks) ... ... ... ... ... ... ... #. #. #. #. #. #. #. #. ... ... ... ... ... ... ... If you enjoyed this week's post, share it with your friends and stay tuned for next week's post. See you then!
GIPHY App Key not set. Please check settings