Problems with Printing While Loop

why doesn’t it work?

1 Like

Hello, Welcome to the Replit Community!

Within the code provided, the play function seemed defined as such:

def play():
    sandwiches = 0
    sps = 1
    while True:
        kp = readchar()
        clear()
        sandwiches += sps
        colorprint("Brendonio's Big Belly", 'red')
        colorprint(f"Your Sandwiches: {round(sandwiches)}")
        colorprint(f"Sandwiches Per Second: {sps}")
        if kp == '1':

Instead, try to move kp = readchar() variable before if kp == '1': statement.
Your new code should look something like this:

def play():
    sandwiches = 0
    sps = 1
    while True:
        clear()
        sandwiches += sps
        colorprint("Brendonio's Big Belly", 'red')
        colorprint(f"Your Sandwiches: {round(sandwiches)}")
        colorprint(f"Sandwiches Per Second: {sps}")
        kp = readchar()
        if kp == '1':

I have gone ahead and forked your replit to test my changes to insure they do work, please be sure to let me know though :slight_smile:

Also I would recommend some changes:

Your clear function is defined as such:

def clear(s=0):
    time.sleep(s)
    print("\033c", end='', flush = True)

You can use something like:

def c():
  os.system('cls' if os.name == 'nt' else 'clear')

then do

c()

(for example)

I would personally recommend creating classes, and organizing functions into modules to keep things clean :slight_smile:

Also please mark as Solution :white_check_mark: if I was able to help you, it would also help me a lot :smiley:

Which works just fine, why should they change it to os? os is actually slower than printing the escape.

3 Likes

…but why?

  1. c is much worse naming
  2. os.system is slower
  3. you just removed the wait functionality…?
3 Likes

Because you likely won’t clear more than once.

Still? It removes functionality and again, is bad naming. A lot of coding is reading code, using single letter names such as c makes this harder.

2 Likes

If that were the case, you wouldn’t even need the function. I personally do clear a lot, check how often Yeehaw clears.

2 Likes

Ok, so a couple of things here:

Why bro. I don’t see why I would use os.system when it is slower than my current function - also people reading my code are never going to understand what c() means.

In addition, I don’t see why changing that order would help (and it doesn’t) so still looking for a solution here. . .

3 Likes

could you explain why putting the clear function after readchar now breaks your program – we cannot know how to fix the problem unless we know what you intend to do

2 Likes

I think the modifications I made solve the issue, repl here, the issue (afaik) was that the message wasn’t being displayed because it got cleared after being shown.

2 Likes

huh I mean… I literally fixed that before but he said he changed it again?

I dunno what you changed, so… :person_shrugging:

I left notes on my fork to show what I changed.

1 Like

Please explain how os.system is slower than clearing a console using a sleep method combined with an escape sequence :rofl: :rofl:

If you’re so worried about “speed and efficiency” when it comes to your console you should realize os.system directly calls system command cls to clear console.

Anyways you do you I suppose…

c()

is for convenience, which is ironic considering you value speed and efficiency over just that.

def c():
  os.system('cls' if os.name == 'nt' else 'clear')

Directly calls cls from system to clear console.

def clear(s=0):
    time.sleep(s)
    print("\033c", end='', flush = True)

Combines time.sleep method with escape sequence, quite literally over-complicating things…

Hello all,
I think the real problem that the OP is describing is that the sandwiches counter does not continuously update because the readchar call is blocking.
I made some code that solves this issue, give me a while to finalize this.

Also, here’s an unsolved topic on this issue:

2 Likes

edit: I realize you were talking about code efficiency or something but \033c is both more efficient and faster

wait do you genuinely believe that just because something has less lines means it’s faster? Does that mean the following code is necessarily faster?

while True: pass

than

for i in range(10):
     print(i)

Moreoever, the time sleeps for 0 seconds so it does nothing and clearing using ansi is simply… about 10x as fast at that. You can check yourself by running a time check program on clearing 100 times each with both methods

3 Likes

I would like to point out that os.system runs a shell command; a command which in turns prints the same escape sequence. That’s irrefutably slower than directly printing the same escape sequence, since os.system (although directly calling the system) has one extra step as compared to doing what the “clear” command would do directly in the code.

2 Likes

Dude… I’m not even going to say anything. Just read others’ replies.

clear() is one more keystroke (heck, might even be the same, I forgot or it might depend on the IDE), as any modern IDE (including Replit) has this feature called “Code Intelligence” where it predicts what you’re about to type next.

As I said before, most of programming is reading code. clear is much more obvious than c, and that would improve convenience.

At the end of the day, it’s what makes OP a more productive programmer that matters. None of us are to question them, as it’s their program.

3 Likes

Hey @CCodes, here’s my implementation of printing while receiving input, to get you started:

from math import inf
from queue import Queue
import threading
import time

from readchar import readchar


class TimedOutput:
  """A message to be displayed to the user.

  message: the message to be displayed.
  duration: how long the message should be displayed for.
  end: the end of the message (like in print), defaults to a newline.
  """

  def __init__(self, message, duration=inf, *, end="\n"):
    self.message = message
    self.timer = time.time() + duration
    self.end = end


# Using a class for the game is very convenient,
# and avoids the use of mutable global variables
class Game:
  def __init__(self):
    self.input_queue = Queue()  # A queue that receives input
    self.stop_event = threading.Event()  # If set, the game exits
    self.sandwiches = 0
    self.sps = 1
    self.output = [
      TimedOutput("\033c", end=""),
      TimedOutput(f"My sandwiches: {self.sandwiches}"),
    ]  # A list of TimeOutput to be displayed
    self.fps = 30  # The number of the times the loop is run per second
    # The FPS must be high enough to keep up with input

  def input_thread(self):
    """Thead that continously receives user input."""
    try:
      while not self.stop_event.is_set():
        char = readchar()
        if char:
          self.input_queue.put(char)
    except Exception as e:
      print("An error occured:", e)
      self.exit()

  def run(self):
    threading.Thread(target=self.input_thread, daemon=True).start()
    update_timer = time.time()  # The time the last update was made
    while not self.stop_event.is_set():
      output = "".join(o.message+o.end for o in self.output).rstrip()
      print(output, flush=True)
      time.sleep(1 / self.fps)
      if not self.input_queue.empty():
        char = self.input_queue.get()
        self.handle_input(char)

      while update_timer + 1 < time.time():
        update_timer += 1
        self.sandwiches += self.sps
      self.update()

  def handle_input(self, char):
    if char == "q":
      self.exit()
    elif char == "1":
      self.sps += 1
      self.sandwiches -= 50
      self.output.append(TimedOutput(
        "You bought some bread at Trader Brendonio's!",
        2.5
      ))

  def update(self):
    """Updates the game, once per loop."""
    current_time = time.time()
    for output in self.output[:]:
      if current_time >= output.timer:
        self.output.remove(output)
    self.output[1].message = f"My sandwiches: {self.sandwiches}"

  def exit(self):
    self.stop_event.set()


if __name__ == "__main__":
  game = Game()
  game.run()

If you have any questions, feel free to ask.

NOTES:
You should clear the Console between runs.
I was unable to fix the rapid flickering issue in the Console, where the line with the input cursor kept on getting half hidden. (Maybe someone else could fix it?)
I would recommend running the program in the Shell instead, as it does not have that issue. However, I experienced problems with Shell commands being invisible.

4 Likes

fps above 15 will litearlly break on replit lmao

1 Like

How so?
If the FPS was too low, then input wasn’t processed fast enough (though I guess that could be fixed).

1 Like