I started making a game in curses, but I feel like I am displaying the map inefficiently and ineffectively.
Here's the code (only the relevant parts):
import curses
world_map = [
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000011111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000011111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000011111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000111111111111111111110000000000000000000000000000000001111111111111111111111111000000000000000000000000000',
'00000000000000000111111111111111111111000000000000000000000000000001111111111111111111111111000000000000000000000000000',
'00000000000000000011111111111111111000000000000000000000000000000001111133333111111111111111000000000000000000000000000',
'00000000000000000000011111111111100000000000000000000000000000000001111133333111111111111111000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000011111111111110000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000011111111111110000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000']
def win(stdscr):
curses.init_color(255, 0, 0x64 * 1000 // 0xff, 0)
curses.init_color(254, 0xff * 1000 // 0xff, 0xff * 1000 // 0xff, 0xff * 1000 // 0xff)
curses.init_color(253, 0x82 * 1000 // 0xff, 0x8c * 1000 // 0xff, 0x51 * 1000 // 0xff)
curses.init_color(252, 0xff * 1000 // 0xff, 0xe4 * 1000 // 0xff, 0xb5 * 1000 // 0xff)
curses.init_color(251, 0xc0 * 1000 // 0xff, 0xc0 * 1000 // 0xff, 0xc0 * 1000 // 0xff)
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLUE) # water
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_GREEN) # grass
curses.init_pair(3, curses.COLOR_RED, 255) # trees
curses.init_pair(4, curses.COLOR_RED, 254) # mountains
curses.init_pair(5, curses.COLOR_RED, 253) # swamp
curses.init_pair(6, curses.COLOR_RED, 252) # desert
curses.init_pair(7, curses.COLOR_RED, 251) # village
colors = [curses.color_pair(1), curses.color_pair(2), curses.color_pair(3), curses.color_pair(4), curses.color_pair(5), curses.color_pair(6), curses.color_pair(7)]
while True:
for i in range(30):
for j in range(119):
stdscr.addch(i, j, ' ', colors[int(world_map[i][j])])
stdscr.refresh()
def main():
curses.wrapper(win)
if __name__ == '__main__':
main()
Running this produces this window: enter image description here (if you couldn't tell it's just a test)
Is there a better way I could be doing this?
-
\$\begingroup\$ If the water is the char that appears the most you can first fill the screen with it and than color only the things that are not water. You can also compare the prev frame to the curr frame and color only the differences, it might seem slow but actually most of the time here is wasted on IO and coloring operations. \$\endgroup\$Yonlif– Yonlif2021年07月23日 09:16:40 +00:00Commented Jul 23, 2021 at 9:16
1 Answer 1
Here's a slight refactoring of your code to improve readability and reduce repetitiveness. (I don't think anything I'm doing here will do much for you in terms of performance, sadly.)
import curses as c
from itertools import product
world_map = [
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000011111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000011111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000011111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000111111111111111111110000000000000000000000000000000001111111111111111111111111000000000000000000000000000',
'00000000000000000111111111111111111111000000000000000000000000000001111111111111111111111111000000000000000000000000000',
'00000000000000000011111111111111111000000000000000000000000000000001111133333111111111111111000000000000000000000000000',
'00000000000000000000011111111111100000000000000000000000000000000001111133333111111111111111000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000001111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111133333111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111222211000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000011111111111110000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000011111111111110000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001114444411111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111115555555111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000001111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
]
colors_for_initialising = [
(n, *((i * 1000 // 0xff) for i in rgb))
for n, *rgb in (
(255, 0, 0x64, 0),
(254, 0xff, 0xff, 0xff),
(253, 0x82, 0x8c, 0x51),
(252, 0xff, 0xe4, 0xb5),
(251, 0xc0, 0xc0, 0xc0)
)
]
RED, BLUE, GREEN = c.COLOR_RED, c.COLOR_BLUE, c.COLOR_GREEN
color_pairs = (
(1, RED, BLUE), # water
(2, RED, GREEN), # grass
(3, RED, 255), # trees
(4, RED, 254), # mountains
(5, RED, 253), # swamp
(6, RED, 252), # desert
(7, RED, 251) # village
)
def win(stdscr):
for color in colors_for_initialising:
c.init_color(*color)
for color_pair in color_pairs:
c.init_pair(*color_pair)
colors = [c.color_pair(i) for i in range(1, 8)]
while True:
for i, j in product(range(30), range(119)):
stdscr.addch(i, j, ' ', colors[int(world_map[i][j])])
stdscr.refresh()
def main():
c.wrapper(win)
if __name__ == '__main__':
main()
Summary of the changes I've made here:
- Introduced an alias for
curses
(c
) to make the code more concise. You can debate whether this change makes the code more or less readable — when you're using a module heavily, such as in this example, I generally prefer to use a shorter alias rather than having to type out the whole module name each time. - Also introduced aliases for
curses.COLOR_RED
,curses.COLOR_BLUE
andcurses.COLOR_GREEN
later on in the code, for the same reason. Out of these three, onlycurses.COLOR_RED
was used more than once, but I introduced aliases for the other two as well so as to keep the naming of colors consistent. - In your
win
function, you were callingcurses.init_color
andcurses.init_pair
repeatedly, which led to some repetitive code. I took the arguments for these calls out ofwin
and put them into the global namespace, then abstracted your series of calls toinit_color
andinit_pair
into two for-loops inwin
. - I changed your
colors
list inwin
from a list-literal to a list-comprehension, making the code less repetitive, more concise and more readable. - I took out your nested for-loop in
win
and replaced it with a call toitertools.product
, which does the same thing but is more concise and (arguably) more readable.