My Racetrack is just that. A Racetrack. You can't race it (yet) because I had trouble with collision detection, but I wanted to share it anyway.It creates a base polygon by using numpy and shapely. matplotlib (together with descartes) does the plotting and cPickle is used to write states to file so the exact same track can be plotted later.This is my first Python script using argparse instead of sys for argument handling. I'm especially interested in whether the way I implemented it is up to par.The way it's structured is probably not the best either and as always I'm not too fond of my naming. I stuck to -r and -w for reading and writing because it seemed intuitive, but deeper in the code load_state and save_state are used. I'm not sure this is acceptable and which of both I should stick with (if any of those at all).Under the argument parsing I have a couple of BOLD_SNAKE_CASE variables which are pseudo constants. There's probably a better way to do this. Some of those can be freely changed by the user, others shouldn't. I think it's self explanatory enough, but feel free to comment.As said, it was supposed to be part of an actual Racetrack-game. So extendability is important. I like extra features, but those are a pain in the behind to implement if the code isn't modular.import numpy as npimport matplotlib.pyplot as pltimport shapely.geometry as sgfrom argparse import ArgumentParserfrom descartes.patch import PolygonPatchfrom cPickle import load, dump# Argument handlingparser = ArgumentParser(description='Racetrack')parser.add_argument(    'InnerAmplitude',    type=float,    help='For example 0.1'    )parser.add_argument(    'OuterAmplitude',    type=float,    help='For example 0.2, should be higher than InnerAmplitude'    )parser.add_argument(    -v,    --verbose,    action=store_true,    help=increase output verbosity    )mutex = parser.add_mutually_exclusive_group()mutex.add_argument(    -r,    --read,    action=store_true,    help=read state from file    )mutex.add_argument(    -w,    --write,    action=store_true,    help=write state from file    )args = parser.parse_args()# Define size of inner and outer bounds, between those is the RacetrackINNER_AMPLITUDE = args.InnerAmplitudeOUTER_AMPLITUDE = args.OuterAmplitudeDIAMETER = OUTER_AMPLITUDE - INNER_AMPLITUDESIZE = 1.5OUTER_WIDTH = 2MINIMUM_POINTS = 5MAXIMUM_POINTS = 15LOAD_FILE = state_fileSAVE_FILE = LOAD_FILEdef load_state():    with open(LOAD_FILE, r) as file:        np.random.set_state(load(file))def save_state():    with open(SAVE_FILE, w) as file:        dump(np.random.get_state(), file)# Possibility to fix seedif args.verbose:    print (np.random.get_state())if args.read:    load_state()elif args.write:    save_state()# A function to produce a pseudo-random polygondef random_polygon():    nr_points = np.random.randint(MINIMUM_POINTS, MAXIMUM_POINTS)    angle = np.sort(np.random.rand(nr_points) * 2 * np.pi)    dist = 0.3 * np.random.rand(nr_points) + 0.5    return np.vstack((np.cos(angle)*dist, np.sin(angle)*dist)).T# Base polygonpoly = random_polygon()# Create a shapely ring object from base polygoninner_ring = sg.LinearRing(poly)outer_ring_inside = inner_ring.parallel_offset(DIAMETER, 'right', join_style=2, mitre_limit=10.)outer_ring_outside = inner_ring.parallel_offset(OUTER_WIDTH * DIAMETER, 'right', join_style=2, mitre_limit=10.)# Revert the third ring. This is necessary to use it to produce a holeouter_ring_outside.coords = list(outer_ring_outside.coords)[::-1]# Inner and outer polygoninner_poly = sg.Polygon(inner_ring)outer_poly = sg.Polygon(outer_ring_inside, [outer_ring_outside])# Create the figurefig, ax = plt.subplots(1)# Convert inner and outer polygon to matplotlib patches and add them to the axesax.add_patch(PolygonPatch(inner_poly, facecolor=(0, 1, 0, 0.4),    edgecolor=(0, 1, 0, 1), linewidth=3))ax.add_patch(PolygonPatch(outer_poly, facecolor=(1, 0, 0, 0.4),    edgecolor=(1, 0, 0, 1), linewidth=3))# Finalizationax.set_aspect(1)plt.title(Racetrack)plt.axis([-SIZE, SIZE, -SIZE, SIZE])plt.grid()plt.show()Example usage:python racetrack.py -w 0.1 0.25Example output:Not all tracks are playable, since there is nothing checking whether the angles are too sharp. This isn't considered a problem at the moment.
Racetrack plotter
python;python 2.7;numpy;community challenge;matplotlib
This is my first Python script using argparse instead of sys for argument handling. I'm especially interested in whether the way I implemented it is up to par.You nailed it :-)Under the argument parsing I have a couple of BOLD_SNAKE_CASE variables which are pseudo constants. There's probably a better way to do this.That's the common practice in Python, and it's fine like that.Except for these:INNER_AMPLITUDE = args.InnerAmplitudeOUTER_AMPLITUDE = args.OuterAmplitudeDIAMETER = OUTER_AMPLITUDE - INNER_AMPLITUDEAs these are values derived from the command line arguments.The parsing logic would be better in a main() function,which will determine the value of diameter,and pass it to a plot(diameter) function that will take care of the plotting logic.The biggest issue I see is with the layout:ImportsArgument parserConstantsSome functionsArgument handlingAnother functionThe main plotting logicI suggest to reorganize like this:ImportsConstantsHelper functionsdef plot(): The main plotting logicdef main():Argument parserArgument handlingif __name__ == '__main__': guard that simply calls main()After this change, I think it will look a lot better and clearer.