Create an interactive task

In an interactive task, the participant needs to implement code that interacts with a program (interactor) and to solve the task based on data from the interactor.

For example, the task may be a game of chess, checkers, tic-tac-toe, or higher lower.

1. Create a problem

  1. Go to Problems and click Create problem.
  2. Enter a name and click Create. The name will be displayed in the participant interface.
  3. Enter a short name. You can also add the name in English.
  4. In the Task type box, select INTERACTIVE_PROBLEM.
  5. Set up the basic parameters the same way as when you set up the programming task.
  6. In the Interactor settings section, select Interactor type: TESTLIB_EXITCODE or EJUDGE_EXITCODE. This setting determines which exitcodes lead to which submission verdict. With different exitcodes, the system behaves the same way as checkers.

2. Add an interactor

Use one of the following options:

  • Upload and add the interactor file.
  • Compile the interactor file from the C++ source with the testlib.h library that's built into Yandex Contest.

Interaction with the test file

In an interactive task, the interactor has access to the test file (for example, tests/01). The file name is passed in the first argument of the interactor launch.

Interaction with the participant's solution

The interactor interacts with the participant's solution using the stdin and stdout streams:

  • The interactor output in stdout is passed to stdin (input.txt) of the participant's solution.
  • The output of the participant's solution that was sent to stdout (or output.txt) is received by the interactor's stdin.

The participant's solution interacts with the standard input and output streams (and/or the input.txt and output.txt files depending on the task settings, the same as in the programming task).

The interaction between the interactor and the participant's solution can be started by either of them.

The interactor and the participant's solution must finish working in sync. Both programs must wait for data on the input stream until certain conditions are met and then finish execution on a control signal from one of the programs. For example, the following options are possible:

  • The interactor uses a special command to inform the participant's solution that it's arrived at the final result.
  • The participant's solution independently understands that the task is solved, sends the final result (a message to the interactor), and finishes the execution.

Interaction with the checker

The interactor interacts with the checker using a file that's passed in the second argument when the interactor is started. When the interactor and the participant's solution finish working, the checker reads the value written to the file and checks whether it matches the response file (for example, tests/01.a).

Learn more about the checker.

Example. The Guessing gametask.

The purpose is to guess a number in a limited interval using less than a particular number of attempts.

The participant's solution must give a number to the interactor and receive a response (less/more/success depending on whether the program guessed the number or gave a larger or a smaller one). The interactor counts the number of attempts and passes it to the checker before finishing work.

The interactor is implemented for the exitcode of the TESTLIB_EXITCODE type.

Sample test data:

  • tests/01 contains the number 15.
  • tests/01.a contains the maximum allowed number of attempts: 50.

Note

The checker file should only contain line breaks in the form \n (Unix line breaks). If you use a different kind of line break (for example, \r\n — Windows line breaks), the system will not be able to run the file.

Sample interactor code
#!/usr/local/bin/python3.7
import sys

class Verdict:
    OK = 0
    WA = 1
    PE = 2
    FAIL = 10

def calculate(attempt, answer):
    if attempt < answer:
        result = 'more'
    elif attempt > answer:
        result = 'less'
    else:
        result = 'success'

    return result

try:
    with open(sys.argv[1], "r") as input_file:
        answer = input_file.readline().strip()

    with open(sys.argv[2], "w") as output_file:
        tries = 0

        while True:
            tries += 1

            try:
                attempt = input().strip()
            except EOFError:
                print("EOF from participant", file=sys.stderr)
                sys.exit(Verdict.PE)

            if not attempt.isdigit():
                print("Invalid attempt: %s" % attempt, file=sys.stderr)
                sys.exit(Verdict.PE)

            result = calculate(attempt, answer)

            print(result, flush=True)
        
            if result == 'success':
                print(tries, file=output_file)

                print("Found number: %s" % attempt, file=sys.stderr)
                sys.exit(Verdict.OK)
except Exception:
    sys.exit(Verdict.FAIL)
Checker code
#!/usr/local/bin/python3.7
import sys

class Verdict:
    OK = 0
    WA = 1
    PE = 2
    FAIL = 10

try:
    with open(sys.argv[2], "r") as output_file:
        tries = int(output_file.read())

    with open(sys.argv[3], "r") as answer_file:
        max_tries = int(answer_file.read())

    if tries > max_tries:
        print("Limit exceeded: used %s attempts, max = %s" % (tries, max_tries), file=sys.stderr)
        sys.exit(Verdict.WA)

    print("Used %s attempts of %s" % (tries, max_tries), file=sys.stderr)
    sys.exit(Verdict.OK)
except Exception:
    sys.exit(Verdict.FAIL)
Sample solution
import random
import sys

max = 100
min = 0

while True:
    attemptNumber = int((max - min) / 2) + min

    print(attemptNumber, flush=True)

    readInput = input()

    if readInput == 'less':
        max = attemptNumber
    elif readInput == 'more':
        min = attemptNumber
    else:
        sys.exit(0)
Sample solution in JavaScript
let max = 100;
let min = 0;

let attemptNumber = parseInt((max - min) / 2);

console.log(attemptNumber);

nextInt = (response) => {
    if (response.indexOf('less') > -1) {
        max = attemptNumber     
    } else if (response.indexOf('more') > -1) {
        min = attemptNumber;
    } else {
        process.exit(0);
    }
    attemptNumber = parseInt((max - min) / 2 + min);

    return attemptNumber;
};

process.stdin.on('data', response => {
    attemptResponse = response.toString();
    attempt = nextInt(attemptResponse);
    console.log(attempt);
});
Write to Support