Skip to content
Snippets Groups Projects
Commit c5bb4230 authored by Christian Eichenberger's avatar Christian Eichenberger :badminton:
Browse files

Merge branch '174-sphinx' into 'master'

Resolve "Refactoring: unification of apidoc of parameter / return"

Closes #174, #33, #149, and #31

See merge request !192
parents adfe99be 5f2af068
No related branches found
No related tags found
No related merge requests found
Showing
with 132 additions and 171 deletions
......@@ -61,20 +61,10 @@ test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
coverage run --source flatland -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
python make_coverage.py
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/flatland*.rst
rm -f docs/modules.rst
sphinx-apidoc --force -a -e -o docs/ flatland -H "Flatland Reference"
$(MAKE) -C docs clean
cp *.md docs
$(MAKE) -C docs html
pydeps --no-config --noshow flatland -o docs/_build/html/flatland.svg
$(BROWSER) docs/_build/html/index.html
python make_docs.py
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
......
......@@ -12,7 +12,7 @@ def swap_attr(obj, attr, new_val):
...
This will set obj.attr to 5 for the duration of the with: block,
restoring the old value at the end of the block. If `attr` doesn't
restoring the old value at the end of the block. If `attr` doesn`t
exist on `obj`, it will be created and then deleted at the end of the
block.
......
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
# TODO fix sphinx warnings instead of suppressing them...
SPHINXOPTS = -Q
SPHINXBUILD = python -msphinx
SPHINXPROJ = flatland
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Changes
=======
.. toctree::
:maxdepth: 2
changelog.md
flatland_2.0.md
......@@ -33,7 +33,7 @@ sys.path.insert(0, os.path.abspath('..'))
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['recommonmark', 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx']
extensions = ['recommonmark', 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', 'numpydoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......@@ -48,7 +48,6 @@ source_suffix = {
'.md': 'markdown',
}
# The master toctree document.
master_doc = 'index'
......@@ -159,3 +158,6 @@ texinfo_documents = [
'One line description of project.',
'Miscellaneous'),
]
# https://stackoverflow.com/questions/12206334/sphinx-autosummary-toctree-contains-reference-to-nonexisting-document-warnings
numpydoc_show_class_members = False
=====
===============
Getting Started
=====
===============
Overview
--------------
--------
Following are three short tutorials to help new users get acquainted with how
to create RailEnvs, how to train simple DQN agents on them, and how to customize
......@@ -17,7 +17,7 @@ To use flatland in a project:
Part 1 : Basic Usage
--------------
--------------------
The basic usage of RailEnv environments consists in creating a RailEnv object
endowed with a rail generator, that generates new rail networks on each reset,
......@@ -120,7 +120,7 @@ The complete code for this part of the Getting Started guide can be found in
Part 2 : Training a Simple an Agent on Flatland
--------------
-----------------------------------------------
This is a brief tutorial on how to train an agent on Flatland.
Here we use a simple random agent to illustrate the process on how to interact with the environment.
The corresponding code can be found in examples/training_example.py and in the baselines repository
......@@ -153,7 +153,7 @@ The difficulty of a railway network depends on the dimensions (`width` x `height
By varying the number of start and goal connections (nr_start_goal) and the number of extra railway elements added (nr_extra)
the number of alternative paths of each agents can be modified. The more possible paths an agent has to reach its target the easier the task becomes.
Here we don't specify any observation builder but rather use the standard tree observation. If you would like to use a custom obervation please follow
the instructions in the next tutorial.
the instructions in the next tutorial.
Feel free to vary these parameters to see how your own agent holds up on different setting. The evalutation set of railway configurations will
cover the whole spectrum from easy to complex tasks.
......@@ -188,7 +188,7 @@ The environment returns an array of new observations, reward dictionary for all
This information can be used to update the policy of your agent and if done['__all__'] == True the episode terminates.
Part 3 : Customizing Observations and Level Generators
--------------
------------------------------------------------------
Example code for generating custom observations given a RailEnv and to generate
random rail maps are available in examples/custom_observation_example.py and
......@@ -257,6 +257,7 @@ random (but consistent) agents along with their targets and initial directions,
given a rail map (GridTransitionMap object) and the desired number of agents:
.. code-block:: python
agents_position, agents_direction, agents_target = get_rnd_agents_pos_tgt_dir_on_rail(
rail_map,
num_agents)
......@@ -10,13 +10,13 @@ Welcome to flatland's documentation!
about_flatland
gettingstarted
intro_observationbuilder
specifications/specifications.md
intro_observation_actions
specifications_index
modules
FAQ
localevaluation
contributing
changelog.md
flatland_2.0.md
changelog_index
authors
......
File moved
=====
==============================================================
Getting Started with custom observations and custom predictors
=====
==============================================================
Overview
--------------
--------
One of the main objectives of the Flatland-Challenge_ is to find a suitable observation (relevant features for the problem at hand) to solve the task. Therefore **Flatland** was built with as much flexibility as possible when it comes to building your custom observations: observations in Flatland environments are fully customizable.
Whenever an environment needs to compute new observations for each agent, it queries an object derived from the :code:`ObservationBuilder` base class, which takes the current state of the environment and returns the desired observation.
......@@ -12,7 +12,7 @@ Whenever an environment needs to compute new observations for each agent, it que
.. _Flatland-Challenge: https://www.aicrowd.com/challenges/flatland-challenge
Example 1 : Simple (but useless) observation
--------------------------------------------------------
--------------------------------------------
In this first example we implement all the functions necessary for the observation builder to be valid and work with **Flatland**.
Custom observation builder objects need to derive from the `flatland.core.env_observation_builder.ObservationBuilder`_
base class and must implement two methods, :code:`reset(self)` and :code:`get(self, handle)`.
......@@ -300,9 +300,9 @@ When building your custom observation builder, you might want to aggregate and d
Transitions maps
~~~~~~~~~~~~~~~~
The transition maps build the base for all movement in the environment. They contain all the information about allowed transitions for the agent at any given position. Because railway movement is limited to the railway tracks, these are important features for any controller that want to interact with the environment. All functionality and features of a transition map can be found here_
The transition maps build the base for all movement in the environment. They contain all the information about allowed transitions for the agent at any given position. Because railway movement is limited to the railway tracks, these are important features for any controller that want to interact with the environment. All functionality and features of a transition map can be found here_.
.. _here:https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/core/transition_map.py
.. _here: https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/core/transition_map.py
**Get Transitions for cell**
......@@ -312,7 +312,7 @@ To access the possible transitions at any given cell there are different possibi
2. When more detailed information about the cell in general is necessary you can also get the full transitions of a cell by calling :code:`transition_int = env.rail.get_full_transitions(*position)`. This will return an :code:`int16` for the cell representing the allowed transitions. To understand the transitions returned it is best to represent it as a binary number :code:`bin(transition_int)`, where the bits have to following meaning: :code:`NN NE NS NW EN EE ES EW SN SE SS SW WN WE WS WW`. For example the binary code :code:`1000 0000 0010 0000`, represents a straigt where an agent facing north can transition north and an agent facing south can transition south and no other transitions are possible. To get a better feeling what the binary representations of the elements look like go to this Link_
.. _Link:https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/core/grid/rail_env_grid.py#L29
.. _Link: https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/core/grid/rail_env_grid.py#L29
These two objects can be used for example to detect switches that are usable by other agents but not the observing agent itself. This can be an important feature when actions have to be taken in order to avoid conflicts.
......@@ -350,9 +350,11 @@ All the agent in the initiated environment can be found in the :code:`env.agents
Beyond the basic agent information we can also access more details about the agents type by looking at speed data:
- Agent max speed :code:`agent.speed_data["speed"]` wich defines the traveling speed when the agent is moving.
- Agent position fraction :code:``agent.speed_data["position_fraction"]` which is a number between 0 and 1 and indicates when the move to the next cell will occur. Each speed of an agent is 1 or a smaller fraction. At each :code:`env.step()` the agent moves at its fractional speed forwards and only changes to the next cell when the cumulated fractions are :code:`agent.speed_data["position_fraction"] >= 1.`
- Agent can move at different speed which can be set up by modifying the agent.speed_data within the schedule_generator. For example refer this Link_
.. _Link:https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/envs/schedule_generators.py#L59
- Agent position fraction :code:`agent.speed_data["position_fraction"]` which is a number between 0 and 1 and indicates when the move to the next cell will occur. Each speed of an agent is 1 or a smaller fraction. At each :code:`env.step()` the agent moves at its fractional speed forwards and only changes to the next cell when the cumulated fractions are :code:`agent.speed_data["position_fraction"] >= 1.`
- Agent can move at different speed which can be set up by modifying the agent.speed_data within the schedule_generator. For example refer this _Link_Schedule_Generators.
.. _Link_Schedule_Generators: https://gitlab.aicrowd.com/flatland/flatland/blob/master/flatland/envs/schedule_generators.py#L59
**Agent malfunction information**
Similar to the speed data you can also access individual data about the malfunctions of an agent. All data is available through :code:`agent.malfunction_data` with:
......
=====
================
Local Evaluation
=====
================
This document explains you how to locally evaluate your submissions before making
an official submission to the competition.
Requirements
--------------
------------
* **flatland-rl** : We expect that you have `flatland-rl` installed by following the instructions in :doc:`installation`.
* **redis** : Additionally you will also need to have `redis installed <https://redis.io/topics/quickstart>`_ and **should have it running in the background.**
Test Data
--------------
---------
* **test env data** : You can `download and untar the test-env-data <https://www.aicrowd.com/challenges/flatland-challenge/dataset_files>`_,
at a location of your choice, lets say `/path/to/test-env-data/`. After untarring the folder, the folder structure should look something like :
* **test env data** : You can `download and untar the test-env-data <https://www.aicrowd.com/challenges/flatland-challenge/dataset_files>`, at a location of your choice, lets say `/path/to/test-env-data/`. After untarring the folder, the folder structure should look something like:
.. code-block:: console
......@@ -48,11 +47,10 @@ Evaluation Service
flatland-evaluator --tests /path/to/test-env-data/
RemoteClient
------------------
------------
* **run client** : Some `sample submission code can be found in the starter-kit <https://github.com/AIcrowd/flatland-challenge-starter-kit/>`_, but before you can run your code locally using `FlatlandRemoteClient`, you will have to set the `AICROWD_TESTS_FOLDER` environment variable to the location where you previous untarred the folder with `the test-env-data`:
* **run client** : Some `sample submission code can be found in the starter-kit <https://github.com/AIcrowd/flatland-challenge-starter-kit/>`_,
but before you can run your code locally using `FlatlandRemoteClient`, you will have to set the `AICROWD_TESTS_FOLDER` environment variable to the location where you
previous untarred the folder with `the test-env-data`:
.. code-block:: console
......@@ -64,3 +62,4 @@ previous untarred the folder with `the test-env-data`:
# and then finally run your code
python run.py
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=python -msphinx
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=flatland
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
echo.then set the SPHINXBUILD environment variable to point to the full
echo.path of the 'sphinx-build' executable. Alternatively you may add the
echo.Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
......@@ -4,8 +4,8 @@
This doc specifies the software to meet the requirements in the Visualization requirements doc.
## References
- [Visualization Requirements](Specifications/Visualization)
- [Core Spec](Specifications/Core)
- [Visualization Requirements](visualization)
- [Core Spec](./core)
## Interfaces
### Interface with Environment Component
......@@ -72,4 +72,4 @@ To-be-filled
#### Overlay dynamic primitives over the background at each time step.
No point trying to figure out changes. Need to explicitly draw every primitive anyways (that’s how these renders work).
\ No newline at end of file
No point trying to figure out changes. Need to explicitly draw every primitive anyways (that’s how these renders work).
......@@ -11,7 +11,7 @@ In a humand-readable language, they provide
## Overview
![UML_flatland.png](img/UML_flatland.png)
[Diagram Source](https://confluence.sbb.ch/x/pQfsSw)
## [Core](core)
## Rail Generators and Schedule Generators
......@@ -330,6 +330,3 @@ RailEnv.step()
self.get()
...
```
## [Rendering](rendering)
## [Railway](railway)
Flatland Specs
==============
.. toctree::
:maxdepth: 2
specifications/specifications.md
specifications/core.md
specifications/railway.md
specifications/rendering.md
specifications/specifications.md
specifications/visualization.md
......@@ -15,6 +15,7 @@ class Environment:
Agents are identified by agent ids (handles).
Examples:
>>> obs = env.reset()
>>> print(obs)
{
......@@ -40,6 +41,7 @@ class Environment:
"train_0": {}, # info for train_0
"train_1": {}, # info for train_1
}
"""
def __init__(self):
......@@ -51,7 +53,8 @@ class Environment:
"""
Resets the env and returns observations from agents in the environment.
Returns:
Returns
-------
obs : dict
New observations for each agent.
"""
......@@ -66,7 +69,7 @@ class Environment:
The returns are dicts mapping from agent_id strings to values.
Parameters
-------
----------
action_dict : dict
Dictionary of actions to execute, indexed by agent id.
......
......@@ -2,10 +2,11 @@
ObservationBuilder objects are objects that can be passed to environments designed for customizability.
The ObservationBuilder-derived custom classes implement 2 functions, reset() and get() or get(handle).
+ Reset() is called after each environment reset, to allow for pre-computing relevant data.
+ `reset()` is called after each environment reset, to allow for pre-computing relevant data.
+ `get()` is called whenever an observation has to be computed, potentially for each agent independently in case of \
multi-agent environments.
+ Get() is called whenever an observation has to be computed, potentially for each agent independently in
case of multi-agent environments.
"""
import numpy as np
......@@ -14,7 +15,7 @@ class ObservationBuilder:
"""
ObservationBuilder base class.
Derived objects must implement and `observation_space' attribute as a tuple with the dimensions of the returned
Derived objects must implement and `observation_space` attribute as a tuple with the dimensions of the returned
observations.
"""
......@@ -32,19 +33,19 @@ class ObservationBuilder:
def get_many(self, handles=[]):
"""
Called whenever an observation has to be computed for the `env' environment, for each agent with handle
in the `handles' list.
Called whenever an observation has to be computed for the `env` environment, for each agent with handle
in the `handles` list.
Parameters
-------
handles : list of handles (optional)
----------
handles : list of handles, optional
List with the handles of the agents for which to compute the observation vector.
Returns
-------
function
A dictionary of observation structures, specific to the corresponding environment, with handles from
`handles' as keys.
`handles` as keys.
"""
observations = {}
for h in handles:
......@@ -53,12 +54,12 @@ class ObservationBuilder:
def get(self, handle=0):
"""
Called whenever an observation has to be computed for the `env' environment, possibly
for each agent independently (agent id `handle').
Called whenever an observation has to be computed for the `env` environment, possibly
for each agent independently (agent id `handle`).
Parameters
-------
handle : int (optional)
----------
handle : int, optional
Handle of the agent for which to compute the observation vector.
Returns
......
......@@ -3,9 +3,9 @@ PredictionBuilder objects are objects that can be passed to environments designe
The PredictionBuilder-derived custom classes implement 2 functions, reset() and get([handle]).
If predictions are not required in every step or not for all agents, then
+ Reset() is called after each environment reset, to allow for pre-computing relevant data.
+ `reset()` is called after each environment reset, to allow for pre-computing relevant data.
+ Get() is called whenever an step has to be computed, potentially for each agent independently in
+ `get()` is called whenever an step has to be computed, potentially for each agent independently in \
case of multi-agent environments.
"""
......@@ -33,11 +33,11 @@ class PredictionBuilder:
Called whenever get_many in the observation build is called.
Parameters
-------
----------
custom_args: dict
Implementation-dependent custom arguments, see the sub-classes.
handle : int (optional)
handle : int, optional
Handle of the agent for which to compute the observation vector.
Returns
......
......@@ -24,9 +24,9 @@ class Grid4Transitions(Transitions):
"""
Grid4Transitions class derived from Transitions.
Special case of `Transitions' over a 2D-grid (FlatLand).
Special case of `Transitions` over a 2D-grid (FlatLand).
Transitions are possible to neighboring cells on the grid if allowed.
GridTransitions keeps track of valid transitions supplied as `transitions'
GridTransitions keeps track of valid transitions supplied as `transitions`
list, each represented as a bitmap of 16 bits.
Whether a transition is allowed or not depends on which direction an agent
......@@ -67,8 +67,8 @@ class Grid4Transitions(Transitions):
"""
Get the 4 possible transitions ((N,E,S,W), 4 elements tuple
if no diagonal transitions allowed) available for an agent oriented
in direction `orientation' and inside a cell with
transitions `cell_transition'.
in direction `orientation` and inside a cell with
transitions `cell_transition`.
Parameters
----------
......@@ -90,9 +90,9 @@ class Grid4Transitions(Transitions):
"""
Set the possible transitions (e.g., (N,E,S,W), 4 elements tuple
if no diagonal transitions allowed) available for an agent
oriented in direction `orientation' and inside a cell with transitions
`cell_transition'. A new `cell_transition' is returned with
the specified bits replaced by `new_transitions'.
oriented in direction `orientation` and inside a cell with transitions
`cell_transition'. A new `cell_transition` is returned with
the specified bits replaced by `new_transitions`.
Parameters
----------
......@@ -107,8 +107,8 @@ class Grid4Transitions(Transitions):
-------
int
An updated bitmap that replaces the original transitions validity
of `cell_transition' with `new_transitions', for the appropriate
`orientation'.
of `cell_transition' with `new_transitions`, for the appropriate
`orientation`.
"""
mask = (1 << ((4 - orientation) * 4)) - (1 << ((3 - orientation) * 4))
......@@ -127,8 +127,8 @@ class Grid4Transitions(Transitions):
def get_transition(self, cell_transition, orientation, direction):
"""
Get the transition bit (1 value) that determines whether an agent
oriented in direction `orientation' and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction'
oriented in direction `orientation` and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction`
relative to the current cell.
Parameters
......@@ -151,8 +151,8 @@ class Grid4Transitions(Transitions):
def set_transition(self, cell_transition, orientation, direction, new_transition, remove_deadends=False):
"""
Set the transition bit (1 value) that determines whether an agent
oriented in direction `orientation' and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction'
oriented in direction `orientation` and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction`
relative to the current cell.
Parameters
......@@ -171,8 +171,8 @@ class Grid4Transitions(Transitions):
-------
int
An updated bitmap that replaces the original transitions validity
of `cell_transition' with `new_transitions', for the appropriate
`orientation'.
of `cell_transition' with `new_transitions`, for the appropriate
`orientation`.
"""
if new_transition:
......@@ -196,7 +196,7 @@ class Grid4Transitions(Transitions):
16 bits used to encode the valid transitions for a cell.
rotation : int
Angle by which to clock-wise rotate the transition bits in
`cell_transition' by. I.e., rotation={0, 90, 180, 270} degrees.
`cell_transition` by. I.e., rotation={0, 90, 180, 270} degrees.
Returns
-------
......
......@@ -20,9 +20,9 @@ class Grid8Transitions(Transitions):
"""
Grid8Transitions class derived from Transitions.
Special case of `Transitions' over a 2D-grid (FlatLand).
Special case of `Transitions` over a 2D-grid (FlatLand).
Transitions are possible to neighboring cells on the grid if allowed.
GridTransitions keeps track of valid transitions supplied as `transitions'
GridTransitions keeps track of valid transitions supplied as `transitions`
list, each represented as a bitmap of 64 bits.
0=North, 1=North-East, etc.
......@@ -82,8 +82,8 @@ class Grid8Transitions(Transitions):
-------
int
An updated bitmap that replaces the original transitions validity
of `cell_transition' with `new_transitions', for the appropriate
`orientation'.
of `cell_transition' with `new_transitions`, for the appropriate
`orientation`.
"""
mask = (1 << ((8 - orientation) * 8)) - (1 << ((7 - orientation) * 8))
......@@ -106,8 +106,8 @@ class Grid8Transitions(Transitions):
def get_transition(self, cell_transition, orientation, direction):
"""
Get the transition bit (1 value) that determines whether an agent
oriented in direction `orientation' and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction'
oriented in direction `orientation` and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction`
relative to the current cell.
Parameters
......@@ -131,8 +131,8 @@ class Grid8Transitions(Transitions):
"""
Set the transition bit (1 value) that determines whether an agent
oriented in direction `orientation' and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction'
oriented in direction `orientation` and inside a cell with transitions
`cell_transition' can move to the cell in direction `direction`
relative to the current cell.
Parameters
......@@ -150,8 +150,8 @@ class Grid8Transitions(Transitions):
-------
int
An updated bitmap that replaces the original transitions validity
of `cell_transition' with `new_transitions', for the appropriate
`orientation'.
of `cell_transition' with `new_transitions`, for the appropriate
`orientation`.
"""
if new_transition:
......@@ -172,7 +172,7 @@ class Grid8Transitions(Transitions):
64 bits used to encode the valid transitions for a cell.
rotation : int
Angle by which to clock-wise rotate the transition bits in
`cell_transition' by. I.e., rotation={0, 45, 90, 135, 180,
`cell_transition` by. I.e., rotation={0, 45, 90, 135, 180,
225, 270, 315} degrees.
Returns
......
import numpy as np
def position_to_coordinate(depth, positions):
"""Converts coordinates to positions:
[ (0,0) (0,1) .. (0,w-1)
(1,0) (1,1) (1,w-1)
...
(d-1,0) (d-1,1) (d-1,w-1)
]
def position_to_coordinate(depth: int, positions):
"""Converts coordinates to positions::
[ (0,0) (0,1) .. (0,w-1)
(1,0) (1,1) (1,w-1)
...
(d-1,0) (d-1,1) (d-1,w-1)
]
-->
[ 0 d .. (w-1)*d
1 d+1
...
d-1 2d-1 w*d-1
]
[ 0 d .. (w-1)*d
1 d+1
...
d-1 2d-1 w*d-1
]
:param depth:
:param positions:
:return:
Parameters
----------
depth : int
positions : List[Tuple[int,int]]
"""
coords = ()
for p in positions:
......@@ -29,7 +31,8 @@ def position_to_coordinate(depth, positions):
def coordinate_to_position(depth, coords):
"""
Converts positions to coordinates:
Converts positions to coordinates::
[ 0 d .. (w-1)*d
1 d+1
...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment