From 2af13c0c494e3fcd8033f55d9b43ec9f9d4ca437 Mon Sep 17 00:00:00 2001 From: "D. EM" Date: Sat, 19 Oct 2024 05:43:46 +0530 Subject: [PATCH 1/4] cache optimised update 1 --- boom.py | 32 +++++++-- boom_test_file.py | 175 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 boom_test_file.py diff --git a/boom.py b/boom.py index c5e6e87..4bf6e41 100644 --- a/boom.py +++ b/boom.py @@ -5,6 +5,26 @@ floor_texture_path = 'floor.png' sky_texture_path = 'sky.png' +sin_cache_dict = {} +cos_cache_dict = {} +tan_cache_dict = {} + +# 3 functions to cache the calculated trig values +def cached_sin(angle): + if angle not in sin_cache_dict: + sin_cache_dict[angle] = math.sin(angle) + return sin_cache_dict[angle] + +def cached_cos(angle): + if angle not in cos_cache_dict: + cos_cache_dict[angle] = math.cos(angle) + return cos_cache_dict[angle] + +def cached_tan(angle): + if angle not in tan_cache_dict: + tan_cache_dict[angle] = math.tan(angle) + return tan_cache_dict[angle] + world = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], @@ -40,8 +60,8 @@ def lighting(screen, doomguy_pos, doomguy_vector): main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 for ray in range(800): - sin_a = math.sin(main_vector) - cos_a = math.cos(main_vector) + sin_a = cached_sin(main_vector) + cos_a = cached_cos(main_vector) y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) @@ -80,9 +100,9 @@ def lighting(screen, doomguy_pos, doomguy_vector): else: depth = depth_hor - depth *= math.cos(doomguy_vector - main_vector) + depth *= cached_cos(doomguy_vector - main_vector) - proj_height = 800 / math.tan((math.pi / 3) / 2) / (depth + 0.0001) + proj_height = 800 / cached_tan((math.pi / 3) / 2) / (depth + 0.0001) color = [255 / (1 + depth ** 5 * 0.00002)] * 3 pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) @@ -108,8 +128,8 @@ def check_wall_collision(x, y): if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q): pygame.quit() - sin_a = math.sin(doomguy_vector) - cos_a = math.cos(doomguy_vector) + sin_a = cached_sin(doomguy_vector) + cos_a = cached_cos(doomguy_vector) dx, dy = 0, 0 speed = doomguy_speed * dt speed_sin = speed * sin_a diff --git a/boom_test_file.py b/boom_test_file.py new file mode 100644 index 0000000..2677257 --- /dev/null +++ b/boom_test_file.py @@ -0,0 +1,175 @@ +import pygame +import math +import timeit + +wall_texture_path = 'wall.png' +floor_texture_path = 'floor.png' +sky_texture_path = 'sky.png' + +world = [ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], + [1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +] + +walls = {} + +for l, row in enumerate(world): + for n, value in enumerate(row): + if value: + walls[(n, l)] = value + + +doomguy_pos = 1.5, 5 +doomguy_vector = 0 +doomguy_speed = 2 +doomguy_sens = 2 +fov = math.pi / 3 +scale = 1600 // 600 + +code_without_cache = """ +def lighting(screen, doomguy_pos, doomguy_vector): + ox, oy = doomguy_pos + x_map, y_map = int(ox), int(oy) + + main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 + for ray in range(800): + sin_a = math.sin(main_vector) + cos_a = math.cos(main_vector) + + y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) + + depth_hor = (y_hor - oy) / sin_a + x_hor = ox + depth_hor * cos_a + + delta_depth = dy / sin_a + dx = delta_depth * cos_a + + for i in range(20): + tile_hor = int(x_hor), int(y_hor) + if tile_hor in walls: + break + x_hor += dx + y_hor += dy + depth_hor += delta_depth + + x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1) + + depth_vert = (x_vert - ox) / cos_a + y_vert = oy + depth_vert * sin_a + + delta_depth = dx / cos_a + dy = delta_depth * sin_a + + for i in range(20): + tile_vert = int(x_vert), int(y_vert) + if tile_vert in walls: + break + x_vert += dx + y_vert += dy + depth_vert += delta_depth + + if depth_vert < depth_hor: + depth = depth_vert + else: + depth = depth_hor + + depth *= math.cos(doomguy_vector - main_vector) + + proj_height = 800 / math.tan((math.pi / 3) / 2) / (depth + 0.0001) + + color = [255 / (1 + depth ** 5 * 0.00002)] * 3 + pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) + + main_vector += (math.pi / 3) / 800 +""" + +code_setup_with_cache = """ +def cached_sin(angle): + if angle not in sin_cache_dict: + sin_cache_dict[angle] = math.sin(angle) + return sin_cache_dict[angle] + +def cached_cos(angle): + if angle not in cos_cache_dict: + cos_cache_dict[angle] = math.cos(angle) + return cos_cache_dict[angle] + +def cached_tan(angle): + if angle not in tan_cache_dict: + tan_cache_dict[angle] = math.tan(angle) + return tan_cache_dict[angle] +""" + +code_with_cache = """ +def lighting(screen, doomguy_pos, doomguy_vector): + ox, oy = doomguy_pos + x_map, y_map = int(ox), int(oy) + + main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 + for ray in range(800): + sin_a = cached_sin(main_vector) + cos_a = cached_cos(main_vector) + + y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) + + depth_hor = (y_hor - oy) / sin_a + x_hor = ox + depth_hor * cos_a + + delta_depth = dy / sin_a + dx = delta_depth * cos_a + + for i in range(20): + tile_hor = int(x_hor), int(y_hor) + if tile_hor in walls: + break + x_hor += dx + y_hor += dy + depth_hor += delta_depth + + x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1) + + depth_vert = (x_vert - ox) / cos_a + y_vert = oy + depth_vert * sin_a + + delta_depth = dx / cos_a + dy = delta_depth * sin_a + + for i in range(20): + tile_vert = int(x_vert), int(y_vert) + if tile_vert in walls: + break + x_vert += dx + y_vert += dy + depth_vert += delta_depth + + if depth_vert < depth_hor: + depth = depth_vert + else: + depth = depth_hor + + depth *= cached_cos(doomguy_vector - main_vector) + + proj_height = 800 / cached_tan((math.pi / 3) / 2) / (depth + 0.0001) + + color = [255 / (1 + depth ** 5 * 0.00002)] * 3 + pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) + + main_vector += (math.pi / 3) / 800 +""" + + +# performance before cache implementation +print("performance before cache implementation:\n") +print(timeit.timeit(stmt=code_without_cache), number=1) +# performance after cache implementation +print("\nperformance after cache implementation:\n") +print(timeit.timeit(setup=code_setup_with_cache, stmt=code_with_cache, number=1)) \ No newline at end of file From 820f1b8eb067b136b4d5829c8ac55b71aaf4fb1b Mon Sep 17 00:00:00 2001 From: "D. EM" Date: Sat, 19 Oct 2024 06:16:05 +0530 Subject: [PATCH 2/4] cache optimised update 2 --- boom_test_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boom_test_file.py b/boom_test_file.py index 2677257..3837987 100644 --- a/boom_test_file.py +++ b/boom_test_file.py @@ -169,7 +169,7 @@ def lighting(screen, doomguy_pos, doomguy_vector): # performance before cache implementation print("performance before cache implementation:\n") -print(timeit.timeit(stmt=code_without_cache), number=1) +print(timeit.timeit(stmt=code_without_cache, number=1)) # performance after cache implementation print("\nperformance after cache implementation:\n") print(timeit.timeit(setup=code_setup_with_cache, stmt=code_with_cache, number=1)) \ No newline at end of file From 7d917e54505809b334f627f1373bcc13fb231edc Mon Sep 17 00:00:00 2001 From: "D. EM" Date: Sat, 19 Oct 2024 06:35:41 +0530 Subject: [PATCH 3/4] cache optimised update 3 --- boom_test_file.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/boom_test_file.py b/boom_test_file.py index 3837987..b9d303b 100644 --- a/boom_test_file.py +++ b/boom_test_file.py @@ -92,7 +92,7 @@ def lighting(screen, doomguy_pos, doomguy_vector): main_vector += (math.pi / 3) / 800 """ -code_setup_with_cache = """ +code_with_cache = """ def cached_sin(angle): if angle not in sin_cache_dict: sin_cache_dict[angle] = math.sin(angle) @@ -107,9 +107,7 @@ def cached_tan(angle): if angle not in tan_cache_dict: tan_cache_dict[angle] = math.tan(angle) return tan_cache_dict[angle] -""" -code_with_cache = """ def lighting(screen, doomguy_pos, doomguy_vector): ox, oy = doomguy_pos x_map, y_map = int(ox), int(oy) @@ -172,4 +170,4 @@ def lighting(screen, doomguy_pos, doomguy_vector): print(timeit.timeit(stmt=code_without_cache, number=1)) # performance after cache implementation print("\nperformance after cache implementation:\n") -print(timeit.timeit(setup=code_setup_with_cache, stmt=code_with_cache, number=1)) \ No newline at end of file +print(timeit.timeit(stmt=code_with_cache, number=1)) \ No newline at end of file From 76677b34d98058ab21da306bf0b3bf839d2cca12 Mon Sep 17 00:00:00 2001 From: "D. EM" Date: Sat, 19 Oct 2024 10:23:39 +0530 Subject: [PATCH 4/4] cache optimised update 4 --- boom.py | 22 ++++------------------ boom_test_file.py | 19 ++----------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/boom.py b/boom.py index 4bf6e41..b682a47 100644 --- a/boom.py +++ b/boom.py @@ -1,29 +1,15 @@ import pygame import math +import functools wall_texture_path = 'wall.png' floor_texture_path = 'floor.png' sky_texture_path = 'sky.png' -sin_cache_dict = {} -cos_cache_dict = {} -tan_cache_dict = {} - # 3 functions to cache the calculated trig values -def cached_sin(angle): - if angle not in sin_cache_dict: - sin_cache_dict[angle] = math.sin(angle) - return sin_cache_dict[angle] - -def cached_cos(angle): - if angle not in cos_cache_dict: - cos_cache_dict[angle] = math.cos(angle) - return cos_cache_dict[angle] - -def cached_tan(angle): - if angle not in tan_cache_dict: - tan_cache_dict[angle] = math.tan(angle) - return tan_cache_dict[angle] +cached_sin = functools.cache(math.sin) +cached_cos = functools.cache(math.cos) +cached_tan = functools.cache(math.tan) world = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], diff --git a/boom_test_file.py b/boom_test_file.py index b9d303b..70a7819 100644 --- a/boom_test_file.py +++ b/boom_test_file.py @@ -93,21 +93,6 @@ def lighting(screen, doomguy_pos, doomguy_vector): """ code_with_cache = """ -def cached_sin(angle): - if angle not in sin_cache_dict: - sin_cache_dict[angle] = math.sin(angle) - return sin_cache_dict[angle] - -def cached_cos(angle): - if angle not in cos_cache_dict: - cos_cache_dict[angle] = math.cos(angle) - return cos_cache_dict[angle] - -def cached_tan(angle): - if angle not in tan_cache_dict: - tan_cache_dict[angle] = math.tan(angle) - return tan_cache_dict[angle] - def lighting(screen, doomguy_pos, doomguy_vector): ox, oy = doomguy_pos x_map, y_map = int(ox), int(oy) @@ -166,8 +151,8 @@ def lighting(screen, doomguy_pos, doomguy_vector): # performance before cache implementation -print("performance before cache implementation:\n") +print("\nperformance before cache implementation:") print(timeit.timeit(stmt=code_without_cache, number=1)) # performance after cache implementation -print("\nperformance after cache implementation:\n") +print("\nperformance after cache implementation:") print(timeit.timeit(stmt=code_with_cache, number=1)) \ No newline at end of file