# Writing Goals (Python)

## Overview <a href="#writing-goals" id="writing-goals"></a>

A *Goal* in Tychos is a short piece of code in a *scenario* which can check a student's work. Goals are written by the scenario's author, usually an instructor. To the student, the goals appear as a sentence describing something the student should do. At a time defined within the goal, the goal is "checked" and if the goal is satisfied, it turns green. Otherwise it turns red. If the goal's state has not yet been "checked" it will display a question mark.

![Goals that are achieved and those that are not.](https://2165864134-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LCBQtB7AkKJtVQIbOdo%2F-M2E9fmT1VXM0cJ2MHuQ%2F-M2EA37d5y5gW60wkxQ5%2FScreen%20Shot%202020-03-06%20at%206.56.27%20PM.png?alt=media\&token=8847bf05-aeda-4430-80e5-33ccb6097979)

## Writing a Goal

In order to write a goal, you need to be logged in as an Instructor. Only instructors see blue pencil edit buttons at the right side of the goal. Goals can be dragged up or down to reorder the goals. This does not affect when they are checked, but just as a way for you to change how they re being presented to the students.

When you click the pencil button to edit a goal, the goal turns into three edit boxes. The blue pencil button changes to three buttons:

* A "check" button for saving the goal
* An "x" for closing the edit boxes without saving them.
* A "trashcan" button for deleting the goal.

Each edit box represents the three parts of a goal - (1) a **description** which the student sees, (2) a **when condition** which specifies at what time the goal will be checked, and (3) the **victory condition** which specifies what value the student is supposed to create. Here is a simple Goal:

<figure><img src="https://2165864134-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LCBQtB7AkKJtVQIbOdo%2Fuploads%2FL7oUko3vC1pNVS6YCfWU%2FScreen%20Shot%202023-12-31%20at%209.08.01%20AM.png?alt=media&#x26;token=aecedc95-48a5-4285-8dbb-4845a3448544" alt=""><figcaption></figcaption></figure>

In this case the Goal is:

**Description***:* Create a Circle object called c1 with a position of (10, 10), a radius of 5, and a color of "green"

**When Condition:** `"frame_count == 0`*`"`*

**Success Condition**:&#x20;

```python
def test1():
  if "c1" in globals():
    return equals(c1.pos, vec(10, 10)) and c1.radius==5 and c1.color == "green"
  else:
    return False

test1()
```

The above goal's **when condition** is fired when the  `frame_count` is 0, which causes the **success condition** to be checked right after the *initial state* code is run, and before the first *calculations* code is run.&#x20;

The code in the success condition first defines a function called `test1`.  The name of the function does not matter, but the function must return either `True` or `False`.&#x20;

The very last line of code calls this function. So the general format for the success condition is like this:

```python
# Define a function
def my_function()
    if condition:
        return True
    else:
        return False

# Now call the function
my_function()
```

In our example, the `test1()` function uses a conditional statement that first tests to see if the variable c1 exists in the global scope:

```python
if "c1" in globals():
```

If the variable exists, it then evaluates the following:

```python
equals(c1.pos, vec(10, 10)) and c1.radius==5 and c1.color == "green"
```

If any of the comparisons do not evaluate to `True`, then the function will return `False`, but if they are all true, then the function will return `True`

To satisfy this goal, the student can write this:

```python
# Intial State
c1 = circle(pos=vec(10, 10), radius=5, color="green")
```

The initial position of the circle is \[0, 0] before the simulation begins - this is frame 0. The `frame_count` variable allows you to track the frame of the simulation.

{% hint style="info" %}
In the above Goal's **victory condition** code, you can see that we used the function `equals` to see if the position of the circle is (`0, 0)`. When comparing vectors for equivalency, you need to use `equals`.
{% endhint %}

If the student were to then write this code in the **Loop Code** pane:

```python
# Calculations
c1.pos = vec(1, 1)
```

The **success condition** would still be met because this would change the circle's position after the initial conditions have already been tested at frame 0.&#x20;

## Testing *Future* Conditions:

Here is another goal that will check that a student has moved the circle to a new position at a time other than at the beginning of the simulation:

<figure><img src="https://2165864134-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LCBQtB7AkKJtVQIbOdo%2Fuploads%2Fg6y3sFSbhnKjvnzkGazj%2FScreen%20Shot%202023-12-31%20at%209.26.39%20AM.png?alt=media&#x26;token=579a7182-d910-49b6-a8a5-6a2b940db0ea" alt=""><figcaption></figcaption></figure>

In this case the Goal is:

**Description***:* "Move the circle to a new position so that it is at (20, 20) at time t = 2 second&#x73;*."*

**When Condition:** "*`t == 2`"*

**Success Condition**:&#x20;

```python
def test2():
  try:
    if equals(c1.pos, vec(20,20)):
      return True
    else:
      return False
  except:
    return False

test2()
```

The above goal's ***when condition*** is fired when `t` is 2, which causes the **success condition** to be checked at the moment the simulation reaches a time of 2 seconds. This example demonstrates that you can choose either to trigger the Goal test using a specific frame, or a time in seconds.

You could also set the **when condition** using a comparison operator. This would allow you to test your goal state every frame as long as the **when condition** was set:

```python
# When Condition
t > 2
```

Notice in the **Success Condition** that we use a `try - except` statement in order to catch any errors that might occur during the execution of the tests. This can be helpful because in this case, if they have not even defined a variable called `c1`, Tychos will generate an error, and the simulation will not run. Using this method, catches the error, and simply returns a `False` value to the goal checking mechanism which results in the goal not passing.

## Tips When Writing Goals

* Use the logical operators `and` and `or` to combine conditions. This can be helpful in making sure that something is meeting two different conditions, or could be meeting one of two (or three, etc.)
* If you are referencing variable names, its a good idea to see if the exist first in the global scope, using the built in `globals()` function.
* Use a `try-except` statement if you suspect the testing of the success condition might generate/throw an error.
* Make sure that you test your own goals. You can also test your success conditions in the **Loop Code** pane as a way to see if the condition code is working.
* You could also use `print` statements in your **Success Conditions** as a way to print out messages to the **Console** when the goal is tested. This might be used to provide hints to your students.
