Created
December 20, 2024 00:35
-
-
Save gerred/abddc667d11cf368c1c8cbb256ee599a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
❯ curl 'https://gist.githubusercontent.com/gerred/ae5074a928f5ef29265dc468093b0a64/raw/e1621a1575d189c18112c586ede3e8176648f813/doom.ts' | uvx llm -m gemini-2.0-flash-thinking-exp-1219 -s 'convert to python' | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 5364 100 5364 0 0 121k 0 --:--:-- --:--:-- --:--:-- 121k | |
The user wants to convert the provided JavaScript code to Python. This looks like a simple 2D raycasting engine. | |
Here's a plan to convert the code: | |
1. **Imports:** The `readline` import from Node.js needs to be replaced with Python's `asyncio` and `readline` (or potentially just input for simplicity). | |
2. **Constants:** Translate the JavaScript `const` declarations to Python constants (uppercase variable names). | |
3. **Game World (Map):** The map array can be directly translated to a Python list of strings. | |
4. **Game State:** `let` variables become regular Python variables. | |
5. **Helper Functions:** Convert the `getMap` and `distance` functions to Python. Note the slight differences in how string indexing and exponentiation work. | |
6. **Ray Casting:** Translate the `castRay` function, paying attention to the loop structure and how math functions are called. | |
7. **Rendering:** The `renderScreen` function is more involved due to string concatenation. Python's string formatting or joining methods will be useful. | |
8. **Input Handling:** The asynchronous input handling using `readline` in Node.js needs to be adapted using Python's `asyncio` and `input`. | |
9. **Game Loop:** The recursive `gameLoop` function needs to be adapted to Python's asynchronous structure. | |
10. **Main:** The `main` function needs to create the `readline` interface in Python and start the game loop.MAX_DEPTH = 20 | |
# --- Game World --- | |
MAP_DATA = [ | |
"################################", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#.......########.......########.#", | |
"#اريات.#..............#.......#", | |
"#.......#..............#.......#", | |
"#####...#.......##.......#...####", | |
"#.......#.......##.......#.......#", | |
"#.......#..............#.......#", | |
"#.......########.......########.#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"################################", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#.......########.......########.#", | |
"#.......#..............#.......#", | |
"#.......#..............#.......#", | |
"#####...#.......##اريات.#...####", | |
"#.......#.......##.......#.......#", | |
"#.......#..............#.......#", | |
"#.......########.......########.#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"#..............#...............#", | |
"################################", | |
"################################", | |
"################################", | |
"################################", | |
] | |
# --- Game State --- | |
player_x = 2.0 | |
player_y = 2.0 | |
player_angle = 0.0 | |
# --- Helper Functions --- | |
def get_map(x: float, y: float) -> str: | |
if x < 0 or x >= MAP_WIDTH or y < 0 or y >= MAP_HEIGHT: | |
return "#" # Treat out of bounds as a wall | |
return MAP_DATA[int(y)][int(x)] | |
def distance(x1: float, y1: float, x2: float, y2: float) -> float: | |
return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) | |
# --- Ray Casting --- | |
def cast_ray(angle: float) -> float: | |
ray_x = player_x | |
ray_y = player_y | |
sin_a = math.sin(angle) | |
cos_a = math.cos(angle) | |
for depth in range(MAX_DEPTH): | |
ray_x += cos_a * 0.1 | |
ray_y += sin_a * 0.1 | |
if get_map(ray_x, ray_y) == '#': | |
return depth * 0.1 | |
return MAX_DEPTH | |
# --- Rendering --- | |
def render_screen() -> str: | |
screen_buffer = "" | |
for y in range(SCREEN_HEIGHT): | |
for x in range(SCREEN_WIDTH): | |
ray_angle = player_angle - FOV / 2 + (x / SCREEN_WIDTH) * FOV | |
dist = cast_ray(ray_angle) | |
# Ceiling and Floor | |
if y < SCREEN_HEIGHT / 2: | |
screen_buffer += ' ' # Ceiling | |
else: | |
screen_buffer += '.' # Floor | |
# Walls | |
wall_height = int(SCREEN_HEIGHT / dist) | |
wall_top = int((SCREEN_HEIGHT - wall_height) / 2) | |
if y >= wall_top and y < wall_top + wall_height: | |
if dist < 5: | |
screen_buffer = screen_buffer[:-1] + '#' # Closer wall | |
elif dist < 10: | |
screen_buffer = screen_buffer[:-1] + '=' | |
else: | |
screen_buffer = screen_buffer[:-1] + '-' # Farther wall | |
screen_buffer += '\n' | |
return screen_buffer | |
# --- Input Handling --- | |
async def handle_input(): | |
answer = await asyncio.get_event_loop().run_in_executor(None, input, '> ') | |
answer = answer.lower() | |
global player_x, player_y, player_angle | |
if answer == 'w': | |
move_x = math.cos(player_angle) * 0.5 | |
move_y = math.sin(player_angle) * 0.5 | |
if get_map(player_x + move_x, player_y) != '#': | |
player_x += move_x | |
if get_map(player_x, player_y + move_y) != '#': | |
player_y += move_y | |
elif answer == 's': | |
move_back_x = math.cos(player_angle) * 0.5 | |
move_back_y = math.sin(player_angle) * 0.5 | |
if get_map(player_x - move_back_x, player_y) != '#': | |
player_x -= move_back_x | |
if get_map(player_x, player_y - move_back_y) != '#': | |
player_y -= move_back_y | |
elif answer == 'a': | |
player_angle -= 0.1 | |
elif answer == 'd': | |
player_angle += 0.1 | |
elif answer == 'q': | |
print('Exiting...') | |
exit(0) | |
else: | |
print('Invalid input.') | |
# --- Game Loop --- | |
async def game_loop(): | |
while True: | |
print("\033c", end="") # Clear screen in terminal | |
print(render_screen()) | |
await handle_input() | |
await asyncio.sleep(0.05) # Add a small delay to avoid busy-waiting | |
# --- Main --- | |
async def main(): | |
print('Welcome to the Doom-like FPS!') | |
print('Controls: W (forward), S (backward), A (turn left), D (turn right), Q (quit)') | |
await game_loop() | |
if __name__ == "__main__": | |
asyncio.run(main()) | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment