├── .gitignore ├── GPT4_game.ipynb ├── LICENSE ├── README.md ├── app.py ├── packages.txt └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Sasha Rush 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GPTWorld 3 | emoji: 🌎 4 | colorFrom: blue 5 | colorTo: green 6 | sdk: gradio 7 | app_file: app.py 8 | pinned: false 9 | --- 10 | 11 | # GPTWorld - Prompt Golf 12 | 13 |

14 | Open In Colab\ 15 |

16 | 17 | GPTWorld is an educational environment to learn about Prompting. 18 | It consists of a grid-world environment to test the ability of language models to follow instructions in a grounded environment. 19 | You instruct the model to generate code to play the game. 20 | 21 |

22 | 23 |

24 | 25 | ## Goal 26 | 27 | The goal of the puzzle is to construct a prompt that can get GPT-4 to solve a complex game. You can watch in real-time as GPT plays the game. 28 | 29 | Use this link to get started: 30 | 31 |

32 | Open In Colab\ 33 |

34 | 35 | 36 | 37 | ## Leaderboard 38 | 39 | I was able to solve the big puzzle using roughly 2000 tokens (input/output). Can you do better? I'll post the best ones here. 40 | 41 | ## Other Puzzles 42 | 43 | If you find this fun also check out. 44 | 45 | * https://github.com/srush/GPU-Puzzles 46 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import gradio as gr 4 | from dataclasses import dataclass 5 | from chalk import * 6 | from colour import Color 7 | import inspect 8 | import os 9 | import openai 10 | from typing import List, Tuple, Optional 11 | from enum import Enum 12 | import io 13 | from contextlib import redirect_stdout 14 | import imageio 15 | import tiktoken 16 | import time 17 | import pandas as pd 18 | import csv 19 | from huggingface_hub import HfApi, Repository 20 | DATASET_REPO_URL = "https://huggingface.co/datasets/srush/gptworld-leaderboard" 21 | HF_TOKEN = os.environ.get("HF_API") 22 | DATA_FILENAME = "data.csv" 23 | DATA_FILE = os.path.join("data", DATA_FILENAME) 24 | 25 | openai.api_key = "" 26 | tab = " " 27 | repo = Repository(git_user="srush", 28 | local_dir="data", clone_from=DATASET_REPO_URL, use_auth_token=HF_TOKEN 29 | ) 30 | repo.git_pull() 31 | def start2(prompt, board, api_key): 32 | out = "" 33 | # for chunk in openai.ChatCompletion.create( 34 | # model="gpt-4", 35 | # messages=[{ 36 | # "role": "user", 37 | # "content": prompt, 38 | 39 | # }], 40 | # stream=True, 41 | # temperature= 0 42 | # ): 43 | board = board#Game(boundary=(9, 9), key=(1, 1), flag=(2, 2), init=(0, 0), walls=[(2, 0)]) 44 | actions = [Actions.DOWNRIGHT, Actions.RIGHT, Actions.DOWNRIGHT, Actions.PICKUP, Actions.DOWNRIGHT] 45 | contents = example(board, actions) 46 | print(contents) 47 | # encoding = tiktoken.encoding_for_model("gpt-4") 48 | # num_tokens = encoding.encode(string) 49 | 50 | for content in contents: 51 | time.sleep(0.005) 52 | content = content 53 | if content is not None: 54 | out += content 55 | print(content, end="") 56 | yield out 57 | yield out 58 | 59 | def start(prompt, board, api_key): 60 | out = "" 61 | # encoding = tiktoken.encoding_for_model("gpt-4") 62 | # num_tokens = encoding.encode(string) 63 | content = "" 64 | openai.api_key = api_key 65 | for chunk in openai.ChatCompletion.create( 66 | model="gpt-4", 67 | messages=[{ 68 | "role": "user", 69 | "content": prompt, 70 | 71 | }], 72 | stream=True, 73 | temperature= 0 74 | ): 75 | 76 | # for content in contents: 77 | time.sleep(0.005) 78 | content = chunk["choices"][0].get("delta", {}).get("content") 79 | if content is not None: 80 | out += content 81 | print(content, end="") 82 | yield out 83 | yield out 84 | 85 | def num_tokens_from_string(string: str, encoding_name: str="gpt-4") -> int: 86 | """Returns the number of tokens in a text string.""" 87 | encoding = tiktoken.encoding_for_model(encoding_name) 88 | num_tokens = len(encoding.encode(string)) 89 | return num_tokens 90 | 91 | 92 | # + [markdown] id="LMTjwXdD7v-I" 93 | # ## Game Code 94 | # 95 | # This code creates a mini-game to play. It takes place on a hexagon. You are represented by a circle. You need to first pick up a key represented by a triangle. You finally need to make it to the cross to finish the game. The actions show each of the directions you can move. 96 | # 97 | # 98 | 99 | # + id="Fv3eTRKiV2ZB" cellView="form" 100 | #@title Game Code 101 | 102 | # Possible Actions 103 | class Actions(Enum): 104 | UPRIGHT = "UR" 105 | RIGHT = "R" 106 | DOWNRIGHT = "DR" 107 | DOWNLEFT = "DL" 108 | LEFT = "L" 109 | UPLEFT = "UL" 110 | PICKUP = "Pickup" 111 | 112 | # Movements 113 | change = { 114 | Actions.UPRIGHT : (-1, 1), 115 | Actions.RIGHT : (0, 2), 116 | Actions.DOWNRIGHT : (1, 1), 117 | Actions.DOWNLEFT : (1, -1), 118 | Actions.LEFT : (0, -2), 119 | Actions.UPLEFT : (-1, -1), 120 | Actions.PICKUP : (0, 0), 121 | } 122 | change_str = {action.value: change[action] for action in Actions} 123 | def add(a, b): 124 | return a[0] + b[0], a[1] + b[1] 125 | 126 | @dataclass 127 | class Board: 128 | grid: List[str] 129 | player_pos: Tuple[int, int] 130 | flag_pos: Tuple[int, int] 131 | wall_pos:List[Tuple[int, int]] 132 | key_pos:Optional[Tuple[int, int]] 133 | 134 | def move(self, action: Actions) -> 'Board': 135 | "Move by creating a new board." 136 | d_m = change[action] 137 | if action == Actions.PICKUP: 138 | if self.player_pos == self.key_pos: 139 | return Board(self.grid, self.player_pos, self.flag_pos, self.wall_pos, None) 140 | else: 141 | return self 142 | 143 | new_player_pos = add(self.player_pos, d_m) 144 | # Out of bounds 145 | if new_player_pos[0] < 0 or new_player_pos[0] >= len(self.grid): 146 | return self 147 | if new_player_pos[1] < 0 or new_player_pos[1] >= len(self.grid[0]): 148 | return self 149 | # Can't move through walls 150 | if self.grid[new_player_pos[0]][new_player_pos[1]] == 'W': 151 | return self 152 | 153 | new_grid = [row[:] for row in self.grid] # Create a copy of the grid 154 | new_grid[self.player_pos[0]][self.player_pos[1]] = '.' 155 | new_grid[new_player_pos[0]][new_player_pos[1]] = '@' 156 | return Board(new_grid, new_player_pos, self.flag_pos, self.wall_pos, self.key_pos) 157 | 158 | def __str__(self) -> str: 159 | return '\n'.join(''.join(row) for i, row in enumerate(self.grid)) 160 | 161 | @classmethod 162 | def create_empty_board(cls, size: Tuple[int, int], key_pos, flag_pos, init, wall_pos) -> 'Board': 163 | grid = [['.' if i % 2 == j % 2 else " " for i in range(size[1])] for j in range(size[0])] 164 | player_pos = init 165 | flag_pos = flag_pos 166 | grid[player_pos[0]][player_pos[1]] = '@' 167 | grid[flag_pos[0]][flag_pos[1]] = 'P' 168 | grid[key_pos[0]][key_pos[1]] = 'K' 169 | for pos in wall_pos: 170 | grid[pos[0]][pos[1]] = 'W' 171 | return cls(grid, player_pos, flag_pos, wall_pos, key_pos) 172 | 173 | class Game: 174 | def __init__(self, init, flag, walls, key, boundary): 175 | "Create the version of the game that the AI sees." 176 | self.boundary = boundary 177 | self.board = Board.create_empty_board(boundary, key, flag, init, walls) 178 | self.original = self.board 179 | self.actions = [] 180 | 181 | def move(self, action): 182 | self.board = self.board.move(action) 183 | self.actions.append(action) 184 | 185 | @property 186 | def walls(self): 187 | return self.board.wall_pos 188 | 189 | def won(self): 190 | final = self.board 191 | return final.key_pos is None and final.player_pos == final.flag_pos 192 | 193 | def __repr__(self) -> str: 194 | walls = ",".join(map(str, self.board.wall_pos)) 195 | return f"Game(init={self.board.player_pos}, flag={self.board.flag_pos}, walls={self.board.wall_pos}, boundary={self.boundary}, key={self.board.key_pos})" 196 | 197 | # This is the version of move that the AI can see. 198 | def move(game, action, old_pos): 199 | # ACTIONS (must be legal) 200 | game.move(Actions(action)) 201 | offset = change_str[action] 202 | pos = (old_pos[0] + offset[0], old_pos[1] + offset[1]) 203 | 204 | assert 0 <= pos[0] < game.boundary[0], "Row position out of bounds" 205 | assert 0 <= pos[1] < game.boundary[1], "Col position out of bounds" 206 | assert pos not in game.walls, f"Walked into wall {pos}" 207 | if action == "PU": 208 | assert pos == game.key, f"Not over key" 209 | return pos 210 | 211 | 212 | # + [markdown] id="PDOcPiQq8u_Y" 213 | # We can look at the board by drawing it. 214 | 215 | # + colab={"base_uri": "https://localhost:8080/", "height": 221} id="Ic7WgOTi8uF1" outputId="4dc07cb9-9e5f-4d28-d4ea-470ad4b13141" 216 | #@title Drawing code 217 | def draw_board(grid, num=0): 218 | hex = regular_polygon(6, 1).rotate_by(1/12).line_width(0.5).fill_color(Color("white")) 219 | w = hex.get_envelope().width 220 | canvas = empty() 221 | for r, b in enumerate(grid): 222 | def show(v): 223 | if v == ".": 224 | return hex 225 | if v == "@": 226 | return hex + circle(0.35).fill_color(Color("red")) 227 | if v == "P": 228 | x = rectangle(0.25, 0.7).fill_color(Color("blue")).line_width(0) 229 | return hex + (x.rotate_by(0.25/2) + x.rotate_by(-0.25/2)) 230 | if v == "K": 231 | return hex + triangle(0.75).fill_color(Color("purple")) 232 | if v == "W": 233 | return hex.fill_color(Color("black")) 234 | if v ==" ": 235 | return hex 236 | row = hcat(show(v) for i, v in enumerate(b[1 if r %2 else 0::2])) 237 | canvas += row.translate(w * 0.5 if r%2 else 0, 1.5 * r) 238 | canvas = canvas.center_xy().frame(0.5) 239 | canvas = rectangle(canvas.get_envelope().width, canvas.get_envelope().height).line_width(0.5).fill_color(Color("orange")) + canvas 240 | canvas.render_svg(f"pic{num}.svg", 256) 241 | canvas.render(f"pic{num}.png", 256) 242 | return canvas 243 | 244 | 245 | 246 | # + colab={"base_uri": "https://localhost:8080/", "height": 424} id="nqgPKLu0AMhU" outputId="19e4c6d0-b792-4a34-f4c4-81902974c346" 247 | # game = Game(boundary=(5, 5), key=(0, 2), flag=(4, 4), init=(0, 0), walls=[(2, 2)]) 248 | # display(draw_board(game.board.grid)) 249 | # move(game, "DR", (0,0)) 250 | # display(draw_board(game.board.grid)) 251 | 252 | 253 | # + [markdown] id="PhqF9af5_jvh" 254 | # ## Prompt Code 255 | # 256 | # The puzzle is to write prompt code to make the model accomplish this task. We have provided some scaffolding code for you. The code creates: 257 | # 258 | # * A header for describing the game. 259 | # * A function `make_fun` that shows the AI how to move in code. 260 | # * A footer to describe the final game board that you want the mode to solve. 261 | # 262 | # You can fill this in a watch how the model moves around. 263 | 264 | # + id="jFf7TCOJaVHX" 265 | #@title Make the Prompt 266 | def make_fun(board, actions): 267 | "This function generates python code for few-shot examples" 268 | out = tab + "p = " + str(board.player_pos) 269 | for i, action in enumerate(actions): 270 | new_board = board.move(action) 271 | out += f""" 272 | # TODO ADD CODE 273 | p = move(b, "{action.value}", p) # TODO ADD CODE""" 274 | board = new_board 275 | return out 276 | 277 | def example(game, actions): 278 | """ 279 | This code makes a few shot example. You don't need to edit it. 280 | """ 281 | return f""" 282 | def my_example(): 283 | b = {repr(game)} 284 | {make_fun(game.board, actions)} 285 | return b 286 | """ 287 | 288 | 289 | ex = 0 290 | def prompt(game): 291 | """ 292 | You should fill these sections out to teach the AI how to play the game. 293 | 294 | Or you may do your own thing :) 295 | """ 296 | print(f""" 297 | # TODO: DESCRIBE THE GAME 298 | 299 | # TODO: DESCRIBE THE ACTIONS 300 | change_str = {change_str} 301 | 302 | {inspect.getsource(move)} 303 | """) 304 | 305 | def example(game, actions): 306 | """ 307 | This code makes a few shot example. You don't need to edit it. 308 | """ 309 | global ex 310 | ex += 1 311 | print(f""" 312 | def example{ex}(): 313 | b = {repr(game)} 314 | {make_fun(game.board, actions)} 315 | return b 316 | # ------------ 317 | """) 318 | 319 | # Create a few shot example (you may not need this) 320 | board = Game(boundary=(3, 3), key=(1, 1), flag=(2, 2), init=(0, 0), walls=[(2, 0)]) 321 | actions = [Actions.DOWNRIGHT, Actions.PICKUP, Actions.DOWNRIGHT] 322 | example(board, actions) 323 | 324 | # Test case 325 | print(f""" 326 | # ---- 327 | # TODO: ADD any custom example code 328 | #--- 329 | # TODO: FINAL description. 330 | 331 | # Contraints for this function:", {repr(game)} 332 | # Please fill this in with code like the examples above (do not provide a description): 333 | # 334 | # The following function `my_example` instantiates a GameBoard called b with these constraints. 335 | 336 | """) 337 | 338 | 339 | 340 | # + [markdown] id="-iecyV7nAbFT" 341 | # This code lets you make a game and see the output for a prompt for that game. There are easy, medium, and hard games. 342 | 343 | # + colab={"base_uri": "https://localhost:8080/"} id="cOneYFok_OMe" outputId="97080186-7322-4ba9-b500-095fb39071aa" 344 | # Easy 345 | easy_game = Game(boundary=(3, 3), key=(1, 1), flag=(2, 2), init=(0, 0), walls=[]) 346 | 347 | # Medium 348 | medium_game = Game(boundary=(5, 5), key=(3, 1), flag=(4, 4), init=(0, 0), walls=[(1, 1)]) 349 | 350 | # Hard (This is the main one) 351 | hard_game = Game(boundary=(8, 15), key=(3, 1), flag=(7, 13), init=(0, 0), walls=[(2, 2), (1, 1), (5, 3), (1, 11), (5, 5), (6, 6), (6, 10), (2, 6), (4, 12)]) 352 | 353 | # Evil 354 | evil_game = Game(boundary=(8, 15), key=(5, 1), flag=(7, 13), init=(0, 0), walls=[(2, 2), (3, 3), (4, 2), (1, 1), (2, 4), (7, 11), (5, 3), (1, 11), (5, 5), (6, 6), (6, 10), (2, 6), (4, 12)]) 355 | 356 | games = {"Easy": easy_game, "Medium": medium_game, "Hard": hard_game, "Evil": evil_game} 357 | 358 | # Anima 359 | def animate(game): 360 | cur = game.original 361 | i = 0 362 | images = [] 363 | draw_board(cur.grid, i) 364 | images.append(imageio.v2.imread(f"pic{i}.png")) 365 | for act in game.actions: 366 | cur = cur.move(act) 367 | i += 1 368 | draw_board(cur.grid, i) 369 | images.append(imageio.v2.imread(f"pic{i}.png")) 370 | 371 | return imageio.v2.mimsave('movie.gif', images, **{ 'duration': 1000, 'loop': 100}) 372 | 373 | 374 | def load(inp): 375 | if inp in games: 376 | board = games[inp] 377 | else: 378 | board = eval(inp) 379 | draw_board(board.board.grid, 0).render_svg("tmp.svg") 380 | 381 | return ["tmp.svg"], repr(board) 382 | 383 | draw_board(hard_game.board.grid, 0).render_svg("hard.svg") 384 | draw_board(easy_game.board.grid, 0).render_svg("easy.svg") 385 | with gr.Blocks() as app: 386 | 387 | # test = gr.Code(label="test") 388 | # im2 = gr.Gallery() 389 | # im2.style(preview=True) 390 | gr.HTML(""" 391 |
392 |

🌎 GPTWorld 🌍

393 | 394 |

395 | GPTWorld is a prompting game. Your goal is to get an LLM to complete a maze. You are the red dot (🔴) need to first get the key (▲) and then reach the exit (x). The game takes place on a hexagonal grid with walls [Even rows are labeled (0,0), (0, 2), (0,4) and odd rows are labeled (1, 1), (1, 3), (1, 5)]. You play by prompting GPT to write code which solves the game on the right. 396 |

397 |
398 | """) 399 | 400 | with gr.Row(): 401 | with gr.Column(): 402 | game_desc = gr.Text(label="Game (Select one first or make your own)") 403 | examples = gr.Radio(show_label=False, 404 | choices=["Easy", "Medium", "Hard", "Evil"]) 405 | api_key = gr.Text(label="OpenAI Key", type="password", 406 | value=os.environ.get("OPENAI_API_KEY"), 407 | visible=not os.environ.get("OPENAI_API_KEY")) 408 | with gr.Row(): 409 | start_btn = gr.Button("Prompt >") 410 | cancel_btn = gr.Button("Cancel") 411 | 412 | prompt = gr.Code(label="Prompt (This is for you to fill out)", language="python", lines=40, value=f""" 413 | # A prompt to describe this game to the GPT model. 414 | 415 | # Ideas: 416 | # * Describe how the game works 417 | # * Give code examples that solve similar mazes. 418 | # * Give examples to explain the reasoning process 419 | 420 | # You might want to do this in a separate editor and paset in. 421 | 422 | # For example you might want to tell it how the moves work 423 | 424 | change_str = {change_str} 425 | 426 | # Or make up a clear implementation for the move function. 427 | 428 | def move(board, action, old_pos): 429 | # ACTIONS (must be legal) 430 | board.move(action) 431 | offset = change_str[action] 432 | pos = (old_pos[0] + offset[0], old_pos[1] + offset[1]) 433 | assert 0 <= pos[0] < board.boundary[0] 434 | assert 0 <= pos[1] < board.boundary[1] 435 | assert pos not in board.walls 436 | if action == "Pickup": 437 | assert pos == board.key 438 | return pos 439 | 440 | # You can also test your code on the right side to make few-shot examples. 441 | 442 | # Finally use %GAME% to inject the game description above. 443 | """) 444 | with gr.Column(): 445 | im = gr.Gallery(label="Gallery of the Game") 446 | im.style(preview=True, object_fit="scale-down", columns=1, container=True) 447 | msg_box = gr.HTML(label="", show_label=False) 448 | 449 | output = gr.Code(label="Generating Game Code (You can also edit and rerun)", language="python", value="""def my_example(): 450 | b = Game(init=(0, 0), flag=(2, 2), walls= [], boundary= (3, 3), key= (1, 1)) 451 | p = (0, 0) 452 | # This is the code you want it to generate. 453 | p = move(b, "DR", p) 454 | p = move(b, "Pickup", p) 455 | p = move(b, "DL", p) 456 | p = move(b, "R", p) 457 | return b 458 | """, lines=50) 459 | 460 | counter = gr.Slider(label="length", minimum=0, maximum=3000) 461 | run_btn = gr.Button("Rerun ^") 462 | state = gr.State() 463 | 464 | 465 | examples.change(load, inputs=[examples], outputs=[im, game_desc]) 466 | game_desc.submit(load, inputs=[game_desc], outputs=[im, game_desc]) 467 | def run(data): 468 | 469 | board = eval(data[game_desc]) #games[data[examples]] 470 | inp = data[prompt].replace("%GAME%", repr(board)) 471 | print(inp) 472 | q = {} 473 | i = 0 474 | count = 0 475 | im_ = [f"tmp.svg"] 476 | state_val = None 477 | yield {im: im_, counter: 0, output: "", msg_box: "", state: state_val} 478 | 479 | for prefix in start(inp, board, data[api_key]): 480 | ps = prefix.split("\n") 481 | count += 1 482 | 483 | if len(ps) > 3 and not ps[-2].strip().startswith("#") and prefix.endswith("\n"): 484 | print("rendering") 485 | try: 486 | exec(prefix + f"\n return b\nq['board'] = my_example({repr(board)})") 487 | except AssertionError as e: 488 | print("fail") 489 | yield {im: [f"pic{j}.svg" for j in range(i)], counter: count, output: prefix, msg_box: f"You made an illegal move: {e}"} 490 | return 491 | draw_board(q["board"].board.grid, i).render_svg("tmp.svg") 492 | i += 1 493 | im_ = [f"pic{j}.svg" for j in [i-1]] 494 | yield {im: im_, counter: count, output: prefix} 495 | else: 496 | yield {im: im_, counter: count, output: prefix} 497 | if q["board"].won(): 498 | final_msg = "🎇🎇🎇🎇🎇🎇Victory🎇🎇🎇🎇🎇🎇" 499 | state_val = (data[prompt], prefix, count, data[examples]) 500 | else: 501 | final_msg = "Didn't make it" 502 | animate(q["board"]) 503 | 504 | yield {im: ["movie.gif"], counter: count, output: prefix, 505 | msg_box: final_msg, state: state_val} 506 | 507 | 508 | start_prompt = start_btn.click(run, 509 | inputs={prompt, game_desc, api_key, examples}, 510 | outputs={im, output, counter, msg_box, state}) 511 | cancel_btn.click(None, cancels=[start_prompt]) 512 | def run2(data): 513 | c = data[output] 514 | print(c) 515 | i = 0 516 | q = {} 517 | for j in range(len(c)): 518 | 519 | prefix = c[:j] 520 | ps = prefix.split("\n") 521 | if len(ps) > 3 and not ps[-2].strip().startswith("#") and prefix.endswith("\n"): 522 | print("rendering", prefix) 523 | exec(prefix + "\n return b\nq['board'] = my_example()") 524 | draw_board(q["board"].board.grid, i) 525 | i += 1 526 | animate(q["board"]) 527 | out = {im: [f"movie.gif"], msg_box: ""} 528 | print(out) 529 | return out 530 | run_btn.click(run2, inputs={output}, outputs={im, msg_box}) 531 | 532 | gr.HTML("""

Leaderboard

533 | 534 |
535 | To submit, first run a model that gets to the end. It will output "Victory"! 536 | Then come down to the bottom, type in your team name, and then click submit. 537 | The score is the number of output tokens your solution takes. 538 |
539 | 540 | """) 541 | with gr.Row() as row: 542 | team_name = gr.Text(label="Team Name") 543 | leaderboard = gr.Button(value="Submit") 544 | msg = gr.Text(label="Status") 545 | leader = gr.Dataframe(pd.read_csv(DATA_FILE)[["team", "board", "count"]]) 546 | def leaderfn(data): 547 | if data[state] is None: 548 | return {msg: "Nothing to submit"} 549 | if not data[team_name]: 550 | return {msg: "No team name"} 551 | prompt, code, count, board = data[state] 552 | repo.git_pull() 553 | with open(DATA_FILE, "a") as csvfile: 554 | writer = csv.DictWriter(csvfile, fieldnames=["team", "prompt", "code", "count", "board"]) 555 | writer.writerow( 556 | {"team": data[team_name], "prompt": prompt, "code": code, "count": count, "board": board} 557 | ) 558 | commit_url = repo.push_to_hub() 559 | leader_df = pd.read_csv(DATA_FILE)[["team", "board", "count"]] 560 | leader_df = leader_df.sort_values(["board", "count"]) 561 | return {msg: f"Sucess: Final score: {count} {board}", leader: leader_df} 562 | 563 | leaderboard.click(fn=leaderfn, inputs={state, team_name}, outputs={msg, leader}) 564 | 565 | app.queue().launch() 566 | 567 | 568 | # f = io.StringIO() 569 | # with redirect_stdout(f): 570 | # ex = 0 571 | # prompt(game) 572 | # my_prompt = f.getvalue() 573 | # print(my_prompt) 574 | 575 | # # + id="LONWUsBLjOHo" colab={"base_uri": "https://localhost:8080/", "height": 1000} outputId="472afd19-48c1-4924-cabd-639b5e2ad298" 576 | # # Run an LLM and execute it as it runs. 577 | # q = {} 578 | # i = 0 579 | # for prefix in start(my_prompt): 580 | # ps = prefix.split("\n") 581 | # if len(ps) > 3 and not ps[-2].strip().startswith("#") and prefix.endswith("\n"): 582 | # exec(prefix + "\n return b\nq['board'] = my_example()") 583 | # display(draw_board(q["board"].board.grid, i)) 584 | # i += 1 585 | 586 | 587 | # animate(i) 588 | # display(Image("movie.gif")) 589 | 590 | 591 | # # Print the number of tokens used 592 | # print("Input Tokens:", num_tokens_from_string(my_prompt)) 593 | # print("Output Tokens:", num_tokens_from_string(prefix)) 594 | 595 | -------------------------------------------------------------------------------- /packages.txt: -------------------------------------------------------------------------------- 1 | libcairo2-dev 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gradio 2 | git+https://github.com/chalk-diagrams/chalk 3 | openai 4 | pycairo 5 | tiktoken 6 | imageio 7 | pandas 8 | 9 | --------------------------------------------------------------------------------