Actions

Difference between revisions of "Implementation"

From Future Skill

Line 1: Line 1:
 
This article goes through most of the information that one needs to write an implementation for executor version 3. It contains sections about API details, sections about best practices, and some example code tests and challenges to get a complete picture. It does not cover the challenge editor and its options, neither does it cover the canvas API.
 
This article goes through most of the information that one needs to write an implementation for executor version 3. It contains sections about API details, sections about best practices, and some example code tests and challenges to get a complete picture. It does not cover the challenge editor and its options, neither does it cover the canvas API.
 +
Read more general information about the freecode creator here: [[Freecode creator]]
  
Read more general information about the freecode creator here: [[Freecode creator]]
 
 
== The Challenge class ==
 
== The Challenge class ==
 +
 
=== The context object ===
 
=== The context object ===
 
The context object given in the Challenge constructor contains data for the current run and has some additional useful functionality. This section goes through them in detail.
 
The context object given in the Challenge constructor contains data for the current run and has some additional useful functionality. This section goes through them in detail.
Line 17: Line 18:
 
==== living_solutions ====
 
==== living_solutions ====
 
A method that generates index-solution pairs for each living solution (solutions that have not crashed or timed out). This is the recommended way to iterate through solutions in the step method.
 
A method that generates index-solution pairs for each living solution (solutions that have not crashed or timed out). This is the recommended way to iterate through solutions in the step method.
 +
 
=== The solution objects ===
 
=== The solution objects ===
 
The solution objects contain information about the solutions partaking in the challenge level and is a way to call candidate methods on the solutions. The solutions objects have the candidate methods specified in the API specification which is used to call the solution and get a result. Calling a solution may result in a SolutionException (imported from lib.exceptions) which must be caught (the solution is no longer alive at that point). Note that the challenge must not call a candidate method on a crashed solution.
 
The solution objects contain information about the solutions partaking in the challenge level and is a way to call candidate methods on the solutions. The solutions objects have the candidate methods specified in the API specification which is used to call the solution and get a result. Calling a solution may result in a SolutionException (imported from lib.exceptions) which must be caught (the solution is no longer alive at that point). Note that the challenge must not call a candidate method on a crashed solution.
Line 28: Line 30:
 
==== alive: bool ====
 
==== alive: bool ====
 
A flag indicating if the solution is still running or has crashed/timed out.
 
A flag indicating if the solution is still running or has crashed/timed out.
 +
 
=== What to do in the Challenge constructor ===
 
=== What to do in the Challenge constructor ===
 
The challenge constructor should do the following things (preferably in this order):
 
The challenge constructor should do the following things (preferably in this order):
Line 45: Line 48:
 
*If appropriate, mark the challenge as finished.
 
*If appropriate, mark the challenge as finished.
 
It is important that the step method catches any SolutionExceptions raised when calling the solutions. The examples include best practices for handling solution calls (especially note how the “Code test” example handles multiple calls on the same solution).
 
It is important that the step method catches any SolutionExceptions raised when calling the solutions. The examples include best practices for handling solution calls (especially note how the “Code test” example handles multiple calls on the same solution).
=== Score strategy ===
+
 
How to score a contest: write the part where you should use a 70/30/0 system for three participants. This is to avoid the issue that otherwise the ELO doesn’t change if the scores are very close.
+
== Making parallel solution calls ==
 +
Calling the solutions in parallel is preferable if the challenge supports it (i.e. the actions of one solution does not affect any other solution until all solutions have acted). To call solutions in parallel the context.parallel object should be used instead of the solution objects themselves.
 +
The results of a parallel call is a dictionary with solution indices as keys and the solution result as value. There is no need to catch SolutionException when making parallel calls. Only solutions that lived before making the call are included in the dictionary. The solution result is either a the return value from the solution or a SolutionException if the solution crashed, therefore it is necessary to make an isinstance check on the result (unless the return value is not needed).
 +
The differences between sequential and parallel solution calls are highlighted in the “Challenge” and “Parallel challenge” examples.
 +
 
 +
== The API methods ==
 +
The challenge should have methods matching the API methods in the API specification. These methods should take a solution object as its second argument. This solution object corresponds to the solution that called this API method.
 +
Sometimes an API method has additional restrictions on its arguments. If this is the case then they should be thoroughly documented in the challenge/test description. In the API method a specific check should be put in place where a SolutionException (imported from lib.exceptions) with an appropriate message should be raised. This will terminate that solution, taking it out from the challenge from then on.
 +
 
 +
== The Challenge attributes ==
 +
There are a couple of required attributes for a challenge, these must be set in the constructor as they are used continuously throughout the challenge run. They are listed here, together with the required type and a short summary of how it is used.
 +
=== finished: bool ===
 +
Indicates whether the challenge run is completed or not, once it is set to true the step method won’t be called any more and the run will end. Note that the run will also end if all solutions have crashed.
 +
=== level_name: str ===
 +
The name of the level. For a code test it should be descriptive and echo what is being tested. For challenges it is not as important to be descriptive, but it doesn’t hurt. Usually taken from the configuration.
 +
=== max_score: int ===
 +
The total possible score for the level. For a code test this should usually be 10. For challenges this value might not make sense, but it is currently still required. Usually taken from the configuration.
 +
=== scores: [int] ===
 +
A list of scores corresponding to each solution. Should be updated in each call to the step method.
 +
==== Score strategy ====
 +
How to score a tournament: tournaments should use a 70/30/0 scoring system for three participants. This is to avoid the issue that otherwise the ELO doesn’t change if the scores are very close.
 +
 
 +
== The configurations ==
 +
The challenge usually has a _configuration list containing a dictionary for each level. This dictionary can be used to store the level configuration (constants, initial values, flags, etc) and usually contain the following items.
 +
=== name (str) ===
 +
The level name (used to set level_name).
 +
=== show_canvas (bool) ===
 +
A flag indicating if the canvas should be rendered or not. The canvas should always be rendered for public levels, and preferably also for hidden levels. The flag is often False for performance levels in code tests due to the large input size.
 +
=== max_score (int) ===
 +
The maximum score for the level (used to set max_score).
 +
 
 +
= Examples =

Revision as of 14:44, 3 February 2021

This article goes through most of the information that one needs to write an implementation for executor version 3. It contains sections about API details, sections about best practices, and some example code tests and challenges to get a complete picture. It does not cover the challenge editor and its options, neither does it cover the canvas API. Read more general information about the freecode creator here: Freecode creator

The Challenge class

The context object

The context object given in the Challenge constructor contains data for the current run and has some additional useful functionality. This section goes through them in detail.

level: int

The current challenge level.

canvas

An object that is used to interact with the canvas. It is used to add new graphical elements, more details on them are covered by another document. It is best practice to only modify the canvas in dedicated setup and update methods (by default _setup_canvas and _update_canvas).

console

An object that is used to interact with the console. It has two methods: log and debug. The log method acts similar to print and prints the arguments to the console for all players. The debug method acts identically except it only prints when inside the challenge editor.

solutions: list

The list of solutions partaking in the challenge together for this level. There are more details on the solution objects later in this document. This list will always be the same length as the number of solutions. However, they will all be set to None when generating the initial state of the canvas (this affects the Challenge constructor, not the step method).

parallel

An object that acts as a proxy solution for making parallel solution calls. It has the candidate methods specified in the API specification, but not the solution attributes. More details about calling solutions in parallel is available in a later section.

living_solutions

A method that generates index-solution pairs for each living solution (solutions that have not crashed or timed out). This is the recommended way to iterate through solutions in the step method.

The solution objects

The solution objects contain information about the solutions partaking in the challenge level and is a way to call candidate methods on the solutions. The solutions objects have the candidate methods specified in the API specification which is used to call the solution and get a result. Calling a solution may result in a SolutionException (imported from lib.exceptions) which must be caught (the solution is no longer alive at that point). Note that the challenge must not call a candidate method on a crashed solution. The solution objects also have the following attributes.

name: str

The name of the solution. This will either be the player name or a placeholder name.

index: int

The index of the solution. This should be used to identify a solution.

console

An individual console for the solution. The interface is identical to the global console except that it limits the output to the console of the specific solution.

alive: bool

A flag indicating if the solution is still running or has crashed/timed out.

What to do in the Challenge constructor

The challenge constructor should do the following things (preferably in this order):

  • Store the context and select the appropriate level configuration.
  • Initialise the required challenge attributes.
  • Initialise any additional variables used for the run.
  • Setup the canvas.

The constructor should not:

  • Call any solution methods (neither individual, nor in sequence or in parallel).

Note that the step method is not guaranteed to be called before the solutions call the API methods on the challenge, so any preparations needed for the API methods must be done in the constructor.

What to do in the step method

The step method should do the following things:

  • Call any solution methods (either individual, in sequence, or in parallel).
  • Update any variables, etc.
  • Update the scores.
  • Update the canvas.
  • If appropriate, mark the challenge as finished.

It is important that the step method catches any SolutionExceptions raised when calling the solutions. The examples include best practices for handling solution calls (especially note how the “Code test” example handles multiple calls on the same solution).

Making parallel solution calls

Calling the solutions in parallel is preferable if the challenge supports it (i.e. the actions of one solution does not affect any other solution until all solutions have acted). To call solutions in parallel the context.parallel object should be used instead of the solution objects themselves. The results of a parallel call is a dictionary with solution indices as keys and the solution result as value. There is no need to catch SolutionException when making parallel calls. Only solutions that lived before making the call are included in the dictionary. The solution result is either a the return value from the solution or a SolutionException if the solution crashed, therefore it is necessary to make an isinstance check on the result (unless the return value is not needed). The differences between sequential and parallel solution calls are highlighted in the “Challenge” and “Parallel challenge” examples.

The API methods

The challenge should have methods matching the API methods in the API specification. These methods should take a solution object as its second argument. This solution object corresponds to the solution that called this API method. Sometimes an API method has additional restrictions on its arguments. If this is the case then they should be thoroughly documented in the challenge/test description. In the API method a specific check should be put in place where a SolutionException (imported from lib.exceptions) with an appropriate message should be raised. This will terminate that solution, taking it out from the challenge from then on.

The Challenge attributes

There are a couple of required attributes for a challenge, these must be set in the constructor as they are used continuously throughout the challenge run. They are listed here, together with the required type and a short summary of how it is used.

finished: bool

Indicates whether the challenge run is completed or not, once it is set to true the step method won’t be called any more and the run will end. Note that the run will also end if all solutions have crashed.

level_name: str

The name of the level. For a code test it should be descriptive and echo what is being tested. For challenges it is not as important to be descriptive, but it doesn’t hurt. Usually taken from the configuration.

max_score: int

The total possible score for the level. For a code test this should usually be 10. For challenges this value might not make sense, but it is currently still required. Usually taken from the configuration.

scores: [int]

A list of scores corresponding to each solution. Should be updated in each call to the step method.

Score strategy

How to score a tournament: tournaments should use a 70/30/0 scoring system for three participants. This is to avoid the issue that otherwise the ELO doesn’t change if the scores are very close.

The configurations

The challenge usually has a _configuration list containing a dictionary for each level. This dictionary can be used to store the level configuration (constants, initial values, flags, etc) and usually contain the following items.

name (str)

The level name (used to set level_name).

show_canvas (bool)

A flag indicating if the canvas should be rendered or not. The canvas should always be rendered for public levels, and preferably also for hidden levels. The flag is often False for performance levels in code tests due to the large input size.

max_score (int)

The maximum score for the level (used to set max_score).

Examples