[
  {
    "name": "astar",
    "desc": "Route the specified connection with A-star. Removes existing tracks.",
    "args": [
      "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
      ["The connection as `('com-pin','com-pin')` or `('net', index: int)`",
       "A dictionary to customize the [A-star cost function](/doc/API.md#a-star-costs). Defaults are substituted for missing members. WARNING: Costs are remembered and used in subsequent calls without specified costs. Use `{}` to reset."]
    ],
    "demo": [
      "step(('astar', ('IC1-A', 'IC2-A')))",
      "step(('astar', (('IC1-A', 'IC2-A'), {'wd': 4, 'dir': 'xy yx'})))"
    ]
  },

  {
    "name": "astar_to",
    "desc": "Route from the current track endpoint to an arbitrary point with A-star.",
    "args": [[
      "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
      "The starting point as a `tuple(x,y,z)`, or None to use the connection's source point or the endpoint of the connection's track. Throws if there is more than 1 track.",
      "The target point as a `tuple(x,y,z)`.",
      "OPTIONAL: A dictionary to customize the A-star cost function. See 'astar' action."
    ]],
    "demo": [
      "step(('astar_to', (('IC1-A', 'IC2-A'),None,(5.0,-5.0,1))))",
      "step(('astar_to', (('IC1-A', 'IC2-A'),None,(5.0,-5.0,1), {'45': 0.125})))"
    ]
  },

  {
    "name": "segment_to",
    "desc": "Add a segment or via to the connection if it does not violate any clearance rules.",
    "args": [[
      "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
      "The starting point as a `tuple(x,y,z)`, or None to use the connection's source point or the endpoint of the connection's track. Throws if there is more than 1 track.",
      "The target point as a `tuple(x,y,z)`."
    ]],
    "demo": "step(('segment_to', (('IC1-A', 'IC2-A'),(5.0,-5.0,1))))",
    "rets": "Returns `success=False` if the segment violates clearance rules and does not add the segment. Returns the reward for the added segment (or 0)."
  },

  {
    "name": "unroute",
    "desc": "Unroute a connection.",
    "args": "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
    "demo": "env.step(('unroute', ('IC1-A', 'IC2-A')))"
  },

  {
    "name": "unroute_net",
    "desc": "Unroute an entire net.",
    "args": "The net's name",
    "demo": "env.step(('unroute_net', 'GND'))"
  },

  {
    "name": "unroute_segment",
    "desc": "Unroute the last segment or via (determined automatically) of a track.",
    "args": [[
      "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
      "The endpoint (+- 1 units in each coordinate) of the track as a `tuple(x,y,z)` or `None` (if there is no ambiguity). Cannot be omitted."
    ]],
    "demo": [
      "step(('unroute_segment', (('IC1-A', 'IC2-A'), None)))",
      "step(('unroute_segment', (('IC1-A', 'IC2-A'), (0.5,0.5,1))))"
    ],
    "rets": "Returns `success=False` if the track was empty or no track was found ending near the specified point."
  },

  {
    "name": "set_track",
    "desc": "Set the track for a connection. This will become its sole track, existing ones are erased.",
    "args": [[
      "The connection as `('com-pin','com-pin')` or `('net', index: int)`",
      "The track as a dictionary `{ 'segments': [(x0,y0,x1,y1,z,w), ...], 'vias': [((x,y),zmin,zmax,r), ...] }`. The lists may also be 2D float32 NumPy arrays of shape `(n,6)` and `(n,5)`, respectively, or 1D flattened versions. For Python lists of tuples, the z-values must be integers."
    ]],
    "demo": [
      "env.step(('set_track', (('IC1-A','IC2-A'), {'segments': [(0.5,0.5, 1.5,0.5, 0, 0.5),(1.5,0.5, 1.5,1.5, 2, 1.5)], 'vias': [((1.5,0.5), 0,2, 1.0)]})))",
      "env.step(('set_track', (('IC1-A','IC2-A'), {'vias': [((5.0,5.0), 0,3, 0.25)]})))",
      "env.step(('set_track', (('GND', 0), {'segments': np.array(segments, dtype=np.float32)})))"
    ]
  },

  {
    "name": "set_guard",
    "desc": "Set a routing guard path for A-star, i.e. a 1D curve that blocks grid cells (even when the violation cost is finite). Always clears the old guard path.",
    "args": "A path as a list of n 2.5D points as 3-tuples `(number,number,int)` or a 2D f32 NumPy array of size `(n,3)` or a 1D f32 NumPy array of size `3n`, or `None`. Changing layer starts a new path. Paths with only a single point are ignored.",
    "demo": [
      "env.step(('set_guard', None))",
      "env.step(('set_guard', [(0,0,0),(1,0,0),(0,0,1),(1,0,1)])",
      "env.step(('set_guard', np.array([0,0,0, 1,0,0, 0,0,1, 1,0,1], dtype=np.float32))",
      "env.step(('set_guard', np.array([[0,0,0],[1,0,0],[0,0,1],[1,0,1]], dtype=np.float32))",
      "env.step(('set_guard', [(0,0,0),(1,0,0),(0,0,-1),(0,1,0),(1,1,0)])"
    ]
  },

  {
    "name": "set_layer_mask",
    "desc": "Set the layer mask for a specific net. The layer mask is used in the grid cell cost calculation of A-star.",
    "args": "A bit mask as an integer or a list of booleans. Lengths > 64 are silently ignored. Cannot be a NumPy array.",
    "demo": [
      "env.step(('set_layer_mask', 0x6))",
      "env.step(('set_layer_mask', [False,True,True,False]))"
    ]
  },

  {
    "name": "set_costs",
    "desc": "Set the grid cell base costs for a section of the grid.",
    "args": [
      "None to set the cost to 1 everywhere",
      ["A 3D integer grid location as a `tuple(x,y,z)`",
       "A 3D NumPy float32 array"],
      ["A 3D NumPy float32 array with the dimensions of the grid, optionally flattened to 1D."],
      ["The scalar cost value to be assign to a region.",
       "The minimum point of a 3D integer bounding box defining the region as a `tuple(x,y,z)`",
       "The maximum point"]
    ],
    "demo": [
      "env.step(('set_costs', None))",
      "env.step(('set_costs', (0,0,1), np.array([[[1,1,1],[1,1,1]]], dtype=np.float32)))",
      "env.step(('set_costs', 1.1, (0,0,0), (10,10,1)))",
      "env.step(('set_costs', np.ones(grid_shape)))"
    ]
  },

  {
    "name": "lock_routed",
    "desc": "Set the lock status of all connections with tracks (even if incomplete) to `<argument>`, and of all others to `False`. This affects reset() but otherwise is only for use with custom agents.",
    "args": "`boolean`",
    "demo": "env.step(('lock_routed', True))"
  }
]
