prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  [Bug Report] AttributeError: 'Discrete' object has no attribute 'start'
  **Describe the bug**
  Change in https://github.com/openai/gym/pull/2470 introduced a bug when loading pre-trained agents with previous version of gym.
  
  Fix is probably similar to https://github.com/DLR-RM/stable-baselines3/issues/573 ...
  
  
  **Code example**
  from RL Zoo CI
  
  See https://github.com/DLR-RM/rl-baselines3-zoo/pull/210 (note: the CI now passes because I downgraded to gym 0.21)
  and
  https://github.com/DLR-RM/rl-baselines3-zoo/runs/5305883843?check_suite_focus=true
  
  ```
  python enjoy --algo qrdqn --env Acrobot-v1
  ```
  
  traceback:
  ```
   Loading rl-trained-agents/qrdqn/Acrobot-v1_1/Acrobot-v1.zip
  ----------------------------- Captured stderr call -----------------------------
  /opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/save_util.py:166: UserWarning: Could not deserialize object exploration_schedule. Consider using `custom_objects` argument to replace this object.
    warnings.warn(
  Traceback (most recent call last):
    File "/home/runner/work/rl-baselines3-zoo/rl-baselines3-zoo/enjoy.py", line 248, in <module>
      main()
    File "/home/runner/work/rl-baselines3-zoo/rl-baselines3-zoo/enjoy.py", line 178, in main
      model = ALGOS[algo].load(model_path, env=env, custom_objects=custom_objects, **kwargs)
    File "/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/base_class.py", line 709, in load
      check_for_correct_spaces(env, data["observation_space"], data["action_space"])
    File "/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/utils.py", line 224, in check_for_correct_spaces
      if action_space != env.action_space:
    File "/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/gym/spaces/discrete.py", line 50, in __eq__
      and self.start == other.start
  AttributeError: 'Discrete' object has no attribute 'start'
  ```
  
  **System Info**
  Gym 0.22
  
  **Additional context**
  Add any other context about the problem here.
  
  ### Checklist
  
  - [x] I have checked that there is no similar [issue](https://github.com/openai/gym/issues) in the repo (**required**)
  
  
  </issue>
  <code>
  [start of gym/spaces/discrete.py]
  1 from typing import Optional
  2 
  3 import numpy as np
  4 from .space import Space
  5 
  6 
  7 class Discrete(Space[int]):
  8     r"""A discrete space in :math:`\{ 0, 1, \\dots, n-1 \}`.
  9 
  10     A start value can be optionally specified to shift the range
  11     to :math:`\{ a, a+1, \\dots, a+n-1 \}`.
  12 
  13     Example::
  14 
  15         >>> Discrete(2)
  16         >>> Discrete(3, start=-1)  # {-1, 0, 1}
  17 
  18     """
  19 
  20     def __init__(self, n: int, seed: Optional[int] = None, start: int = 0):
  21         assert n > 0, "n (counts) have to be positive"
  22         assert isinstance(start, (int, np.integer))
  23         self.n = int(n)
  24         self.start = int(start)
  25         super().__init__((), np.int64, seed)
  26 
  27     def sample(self) -> int:
  28         return self.start + self.np_random.randint(self.n)
  29 
  30     def contains(self, x) -> bool:
  31         if isinstance(x, int):
  32             as_int = x
  33         elif isinstance(x, (np.generic, np.ndarray)) and (
  34             x.dtype.char in np.typecodes["AllInteger"] and x.shape == ()
  35         ):
  36             as_int = int(x)  # type: ignore
  37         else:
  38             return False
  39         return self.start <= as_int < self.start + self.n
  40 
  41     def __repr__(self) -> str:
  42         if self.start != 0:
  43             return "Discrete(%d, start=%d)" % (self.n, self.start)
  44         return "Discrete(%d)" % self.n
  45 
  46     def __eq__(self, other) -> bool:
  47         return (
  48             isinstance(other, Discrete)
  49             and self.n == other.n
  50             and self.start == other.start
  51         )
  52
  [end of gym/spaces/discrete.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/gym/spaces/discrete.py b/gym/spaces/discrete.py
  --- a/gym/spaces/discrete.py
  +++ b/gym/spaces/discrete.py
  @@ -12,7 +12,7 @@
   
       Example::
   
  -        >>> Discrete(2)
  +        >>> Discrete(2)            # {0, 1}
           >>> Discrete(3, start=-1)  # {-1, 0, 1}
   
       """
  @@ -49,3 +49,17 @@
               and self.n == other.n
               and self.start == other.start
           )
  +
  +    def __setstate__(self, state):
  +        super().__setstate__(state)
  +
  +        # Don't mutate the original state
  +        state = dict(state)
  +
  +        # Allow for loading of legacy states.
  +        # See https://github.com/openai/gym/pull/2470
  +        if "start" not in state:
  +            state["start"] = 0
  +
  +        # Update our state
  +        self.__dict__.update(state)
  
verification_info: {"golden_diff": "diff --git a/gym/spaces/discrete.py b/gym/spaces/discrete.py\n--- a/gym/spaces/discrete.py\n+++ b/gym/spaces/discrete.py\n@@ -12,7 +12,7 @@\n \n     Example::\n \n-        >>> Discrete(2)\n+        >>> Discrete(2)            # {0, 1}\n         >>> Discrete(3, start=-1)  # {-1, 0, 1}\n \n     \"\"\"\n@@ -49,3 +49,17 @@\n             and self.n == other.n\n             and self.start == other.start\n         )\n+\n+    def __setstate__(self, state):\n+        super().__setstate__(state)\n+\n+        # Don't mutate the original state\n+        state = dict(state)\n+\n+        # Allow for loading of legacy states.\n+        # See https://github.com/openai/gym/pull/2470\n+        if \"start\" not in state:\n+            state[\"start\"] = 0\n+\n+        # Update our state\n+        self.__dict__.update(state)\n", "issue": "[Bug Report] AttributeError: 'Discrete' object has no attribute 'start'\n**Describe the bug**\r\nChange in https://github.com/openai/gym/pull/2470 introduced a bug when loading pre-trained agents with previous version of gym.\r\n\r\nFix is probably similar to https://github.com/DLR-RM/stable-baselines3/issues/573 ...\r\n\r\n\r\n**Code example**\r\nfrom RL Zoo CI\r\n\r\nSee https://github.com/DLR-RM/rl-baselines3-zoo/pull/210 (note: the CI now passes because I downgraded to gym 0.21)\r\nand\r\nhttps://github.com/DLR-RM/rl-baselines3-zoo/runs/5305883843?check_suite_focus=true\r\n\r\n```\r\npython enjoy --algo qrdqn --env Acrobot-v1\r\n```\r\n\r\ntraceback:\r\n```\r\n Loading rl-trained-agents/qrdqn/Acrobot-v1_1/Acrobot-v1.zip\r\n----------------------------- Captured stderr call -----------------------------\r\n/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/save_util.py:166: UserWarning: Could not deserialize object exploration_schedule. Consider using `custom_objects` argument to replace this object.\r\n  warnings.warn(\r\nTraceback (most recent call last):\r\n  File \"/home/runner/work/rl-baselines3-zoo/rl-baselines3-zoo/enjoy.py\", line 248, in <module>\r\n    main()\r\n  File \"/home/runner/work/rl-baselines3-zoo/rl-baselines3-zoo/enjoy.py\", line 178, in main\r\n    model = ALGOS[algo].load(model_path, env=env, custom_objects=custom_objects, **kwargs)\r\n  File \"/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/base_class.py\", line 709, in load\r\n    check_for_correct_spaces(env, data[\"observation_space\"], data[\"action_space\"])\r\n  File \"/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/stable_baselines3/common/utils.py\", line 224, in check_for_correct_spaces\r\n    if action_space != env.action_space:\r\n  File \"/opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/gym/spaces/discrete.py\", line 50, in __eq__\r\n    and self.start == other.start\r\nAttributeError: 'Discrete' object has no attribute 'start'\r\n```\r\n\r\n**System Info**\r\nGym 0.22\r\n\r\n**Additional context**\r\nAdd any other context about the problem here.\r\n\r\n### Checklist\r\n\r\n- [x] I have checked that there is no similar [issue](https://github.com/openai/gym/issues) in the repo (**required**)\r\n\n", "before_files": [{"content": "from typing import Optional\n\nimport numpy as np\nfrom .space import Space\n\n\nclass Discrete(Space[int]):\n    r\"\"\"A discrete space in :math:`\\{ 0, 1, \\\\dots, n-1 \\}`.\n\n    A start value can be optionally specified to shift the range\n    to :math:`\\{ a, a+1, \\\\dots, a+n-1 \\}`.\n\n    Example::\n\n        >>> Discrete(2)\n        >>> Discrete(3, start=-1)  # {-1, 0, 1}\n\n    \"\"\"\n\n    def __init__(self, n: int, seed: Optional[int] = None, start: int = 0):\n        assert n > 0, \"n (counts) have to be positive\"\n        assert isinstance(start, (int, np.integer))\n        self.n = int(n)\n        self.start = int(start)\n        super().__init__((), np.int64, seed)\n\n    def sample(self) -> int:\n        return self.start + self.np_random.randint(self.n)\n\n    def contains(self, x) -> bool:\n        if isinstance(x, int):\n            as_int = x\n        elif isinstance(x, (np.generic, np.ndarray)) and (\n            x.dtype.char in np.typecodes[\"AllInteger\"] and x.shape == ()\n        ):\n            as_int = int(x)  # type: ignore\n        else:\n            return False\n        return self.start <= as_int < self.start + self.n\n\n    def __repr__(self) -> str:\n        if self.start != 0:\n            return \"Discrete(%d, start=%d)\" % (self.n, self.start)\n        return \"Discrete(%d)\" % self.n\n\n    def __eq__(self, other) -> bool:\n        return (\n            isinstance(other, Discrete)\n            and self.n == other.n\n            and self.start == other.start\n        )\n", "path": "gym/spaces/discrete.py"}]}