[Python] TUI Python program using the Blessed module only displays correctly in URXVT terminal...

Discussão em 'Python' iniciado por Stack, Março 5, 2025.

  1. Stack

    Stack Membro Participativo

    I wrote this little chase game using the Blessed module. While writing, I tested it with URXVT. It works exactly how I want in that terminal emulator. However, when I try to run the game in Powershell on Windows, the raw Linux TTY, or even other Linux terminal emulators like Xterm or Alacritty, the tiles/squares don't form a grid how they should, and instead pile up at the left side of the screen. The terminal emulators which incorrectly display the grid provide 'True' for blessed.term.does_styling and .is_a_tty, and the opening and closing text prompts are printed to the screen in their proper places. Code below:

    from random import randrange
    from blessed import *

    term = blessed.Terminal()

    # --- MISCELLANEOUS VARIABLES ---

    direction = ''

    gameon = True

    tilelist = []

    #name = ''

    # --- CLASSES ---

    class Tile(object):
    '''A map tile.'''

    def __init__(self, name, number, xpos, ypos):
    '''Constructor
    pre: x/y position on terminal, whether a unit occupies the space, and the space's status e.g. wall, explosion, empty, etc
    post: tile object created with above variables defined'''

    self._name = name
    self._number = number
    self._xpos = xpos
    self._ypos = ypos

    def __str__(self):

    return self._name


    class Player(object):
    '''player'''
    def __init__(self, name, ontile, hp, color, gold):
    self._name = name
    self._ontile = ontile
    self._hp = hp
    self._color = color
    self._gold = gold

    def __str__(self):
    return self._name

    def setupPlayer(self):
    playerinitpos = randrange(0, 4)
    if playerinitpos == 0:
    self._ontile = 1
    if playerinitpos == 1:
    self._ontile = 7
    if playerinitpos == 2:
    self._ontile = 43
    if playerinitpos == 3:
    self._ontile = 49
    self._hp = randrange(900, 1200)

    def movePlayer(self, direction):
    if self._ontile > 49:
    raise ValueError

    if direction == 'quit':
    self._hp = 0

    if direction == 'u':
    if self._ontile < 8:
    return
    else:
    self._ontile = self._ontile - 7
    return self._ontile

    if direction == 'r':
    if self._ontile >= 49:
    return
    if self._ontile % 7 == 0:
    return
    else:
    self._ontile = self._ontile + 1
    return self._ontile

    if direction == 'd':
    if self._ontile > 42:
    return
    else:
    self._ontile = self._ontile + 7
    return self._ontile

    if direction == 'l':
    if self._ontile <= 1:
    return
    elif (self._ontile -1) % 7 == 0:
    return
    else:
    self._ontile = self._ontile - 1
    return self._ontile

    if direction == 'none':
    return self._ontile

    def drawPlayer(self):
    for i in tilelist:
    if i._number == self._ontile:
    drawTileColor(i, self._color)
    print(term.move_xy(i._xpos + 1, i._ypos - 1) + term.bold(self._name))

    def enemyGhostSeek(self, other):

    ghostlist = []
    smart = 1 + (getCounter() // 2)
    for i in range(smart):
    name = str('ghost' + str(i))
    ghostlist.append(Player(name, self._ontile, 0, [], 0))
    for i in ghostlist:

    count = 0
    color = []
    for c in range(20):
    while i._ontile != other._ontile:
    direc = randrange(0, 4)

    if direc == 3:
    direction = 'u'
    if direc == 2:
    direction = 'l'
    if direc == 1:
    direction = 'd'
    if direc == 0:
    direction = 'r'

    i.movePlayer(direction)
    i._color.append(direction)
    count += 1
    # for t in tilelist:
    # if self._ontile == t._number:
    # drawTileColor(t, term.red)
    # print(term.move_xy(t._xpos + 2, t._ypos - 1) + term.bold + term.red('!'))
    i._hp = count
    cand = 100
    for i in ghostlist:
    if i._hp < cand:
    cand = i._hp
    for i in ghostlist:
    if i._hp == cand and cand > 0:
    i._color.sort
    direction = i._color[0]
    return direction
    elif cand == 0:
    direction = 'none'
    return direction

    # enemy deals damage

    if cand == 2:
    other._hp -= 40
    if cand == 1:
    other._hp -= 700

    # gold stuff

    def drawGold(self):
    for i in tilelist:
    if self._ontile == i._number:
    print(term.move_xy(i._xpos + 1, i._ypos - 1) + term.goldenrod(' ● '))

    def moveGold(self):
    self._ontile = randrange(1, 49)

    def goldFoundCheck(self, other):
    if self._ontile == other._ontile:
    other._gold += randrange(1, 10)
    self.moveGold()


    def gethp(self):
    scale = ' '
    if self._hp >= 1100 and self._hp < 1300:
    scale = '██████'
    elif self._hp >= 1000 and self._hp < 1100:
    scale = '█████▌'
    elif self._hp >= 900 and self._hp < 1000:
    scale = '█████ '
    elif self._hp >= 800 and self._hp < 900:
    scale = '████▌ '
    elif self._hp >= 700 and self._hp < 800:
    scale = '████ '
    elif self._hp >= 600 and self._hp < 700:
    scale = '███▌ '
    elif self._hp >= 500 and self._hp < 600:
    scale = '███ '
    elif self._hp >= 400 and self._hp < 500:
    scale = '██▌ '
    elif self._hp >= 300 and self._hp < 400:
    scale = '██ '
    elif self._hp >= 200 and self._hp < 300:
    scale = '█▌ '
    elif self._hp >= 100 and self._hp < 200:
    scale = '█ '
    elif self._hp >= 50 and self._hp < 100:
    scale = '▌ '
    elif self._hp > 49:
    scale = ' '
    return scale

    # --- FUNCTIONS ---


    # player stuff

    def getPlayerName():
    eraseAllTiles()
    term.clear()
    enterstr = 'please enter your name'
    d = 4
    for i in range(22):
    print(term.move_xy(d, 2) + term.bold(enterstr))
    d += 1
    wait = .001 * randrange(1, 30)
    time.sleep(wait)
    print(term.move_xy(26, 2) + term.blink(':'))

    # fun formatting / ani

    def deleteLine(l, x, y):
    c = 0
    for i in range(l + 1):
    print(term.move_xy((x + l) - c, y) + term.bold(' '))
    c += 1
    wait = .001 * randrange(1, 10)
    time.sleep(wait)

    def deleteMultiLine(l, d, x, y):
    c = 0
    dc = 0
    for i in range((l + 1) * d + 1):
    print(term.move_xy((x + l) - c, y + dc) + term.bold(' '))
    dc += 1
    if dc == d:
    dc = 0
    c+= 1
    wait = .001 * randrange(1, 15)
    time.sleep(wait)

    def deleteFastMultiLine(l, d, x, y):
    c = 0
    dc = 0
    for i in range((l + 1) * d + 1):
    print(term.move_xy((x + l) - c, y + dc) + term.bold(' '))
    dc += 1
    if dc == d:
    dc = 0
    c+= 1
    wait = .0005
    time.sleep(wait)

    # tile stuff

    def makeTiles():
    xplace = 70
    yplace = 0
    for i in range(1, 50):
    if (i - 1) % 7 == 0:
    yplace -= 3
    xplace -= 42
    tilename = ('tile' + str(i))
    tilelist.append(Tile(tilename, i, xplace, yplace))
    xplace += 6

    def drawTile(i):
    print(term.move_xy(i._xpos, i._ypos) + term.bold('╭───╮'))
    print(term.move_xy(i._xpos, (i._ypos - 1)) + term.bold('│ │'))
    print(term.move_xy(i._xpos, (i._ypos - 2)) + term.bold('╰───╯'))

    def drawTileColor(i, color):
    print(term.move_xy(i._xpos, i._ypos) + color + ('╭───╮'))
    print(term.move_xy(i._xpos, (i._ypos - 1)) + color + ('│ │'))
    print(term.move_xy(i._xpos, (i._ypos - 2)) + color + ('╰───╯'))


    def drawAllTiles():
    for i in tilelist:
    drawTile(i)
    time.sleep(0.005)

    def drawFastAllTiles():
    for i in tilelist:
    drawTile(i)

    def eraseTile(i):
    print(term.move_xy(i._xpos, i._ypos) + term.bold(' '))
    print(term.move_xy(i._xpos, (i._ypos - 1)) + term.bold(' '))
    print(term.move_xy(i._xpos, (i._ypos - 2)) + term.bold(' '))

    def eraseAllTiles():
    for i in tilelist:
    eraseTile(i)
    time.sleep(0.005)


    # input

    def getNameInput():
    p = 0
    name = ''
    while True:
    print(term.move_xy(28, 2) + term.blink('▂▂▂'))
    for i in range(4):
    if len(name) >= 3:
    print(term.move_xy(26, 2) + term.bold(':'))
    print(term.move_xy(11, 3) + term.blink('press any key'))
    inp = term.inkey()
    if inp == '\n':
    break
    p += 1
    if len(name) <= 3:
    name = name + inp
    print(term.move_xy(28, 2) + term.bold(name))
    print(term.move_xy(28, 2) + term.bold(' '))
    name = name[0:3]
    if len(name) == 3 and type(name) == str:
    return name.lower()
    break
    def getInputWait():
    inp = ''
    while inp != 'q':
    inp = term.inkey()
    if inp == 'n':
    return inp
    if inp == 'y':
    return inp
    if inp == 'q':
    return 'n'
    if inp == 'Q':
    return 'n'
    if inp == '\x1b':
    return 'n'
    def getMoveInput():
    inp = term.inkey()
    dire = ''
    if inp == '\x1b[B':
    dire = 'd'
    return dire
    if inp == '\x1b[A':
    dire = 'u'
    return dire
    if inp == '\x1b[C':
    dire = 'r'
    return dire
    if inp == '\x1b[D':
    dire = 'l'
    return dire
    if inp == 'q':
    dire = 'quit'
    return dire
    if inp == '\x1b':
    dire = 'quit'
    return dire
    if inp == 'Q':
    dire = 'quit'
    return dire
    else:
    dire = 'none'
    return dire


    # turn counter

    def incCounter():
    global counter
    counter += 1

    def getCounter():
    global counter
    return counter


    # game setup

    def main():

    #quitgame = False
    gameon = True
    global counter
    counter = 0
    with term.fullscreen(), term.cbreak(), term.hidden_cursor():

    term.clear()
    getPlayerName()
    playername = getNameInput()


    # game loop

    while True:
    print(term.clear())
    gameon = True
    makeTiles()
    player1 = Player(playername, 0, 0, 0, 0)
    player1.setupPlayer()
    player1._color = term.purple
    print(term.clear)
    drawFastAllTiles()
    player1.drawPlayer()
    enemy = Player(' ! ', 0, 0, 0, 0)
    enemy.setupPlayer()
    enemy._color = term.red
    while enemy._ontile == player1._ontile:
    enemy.setupPlayer()
    enemy.drawPlayer()
    deleteMultiLine(23, 2, 4, 2)
    counter = 0
    Gold = Player('Gold', randrange(1, 49), 0, 0, 0)
    Gold.drawGold()
    while True:
    incCounter()
    print(term.move_xy(1, 1) + term.bold(' ' + term.move_xy(1, 2), ' '))
    print(term.move_xy(1, 1) + 'hp:' + term.purple(player1.gethp()) + term.move_xy(1, 2) + term.normal + 'gold:' + term.goldenrod(str(player1._gold)))
    Gold.goldFoundCheck(player1)
    if gameon == False:
    break
    player1.movePlayer(getMoveInput())
    Gold.goldFoundCheck(player1)
    Gold.drawGold()
    drawFastAllTiles()
    player1.drawPlayer()
    enemy.movePlayer(enemy.enemyGhostSeek(player1))
    drawFastAllTiles()
    Gold.drawGold()
    enemy.drawPlayer()
    player1.drawPlayer()
    if player1._hp <= 0:
    print(term.move_xy(1, 1) + term.bold(' ' + term.move_xy(1,2), ' '))
    deleteFastMultiLine(55, 26, 20, 0)
    gameon = False
    # play again?
    print(term.clear(), term.move_xy(2, 3), term.bold(str(player1._name),', you lost after ', str(counter), ' moves. you had ', str(player1._gold), ' gold.'), term.move_down(5), term.move_left(41), term.blink(' play again? (y/n)'))
    yorno = getInputWait()
    if yorno == 'n':
    break
    sys.exit()

    if __name__ == '__main__':
    main()


    Program displaying correctly in URXVT Program displaying incorrectly in Alacritty

    I'm stumped. Any assistance you can provide I appreciate!

    Thank you

    I wrote a text-based game and expected it to run similarly in different terminals, but it's only running correctly in the one I used while testing/writing the game.

    Continue reading...

Compartilhe esta Página