General logic and flow
I recommend removing
not x and instead just originally setting
x = LOW_NO-1 for your
x = LOW_NO - 1
while HIGH_NO < x or x < LOW_NO:
Next, I recommend you just keep the
while loop instead of recursively calling
getno if the user enters and invalid
int. You could just use
pass to tell the loop to skip onto the next loop. The old value of
x will be preserved so you the condition is still true. Though I do recommend informing the user why their input was rejected.
x = int(x)
print ("That's not a valid number")
return x, no need for brackets.
approxhalf, there's no need for
HIGH_NO values should prevent wildly off numbers, and if you ever want to use negative numbers there's no need to prevent it like this. I do recommend using
int() here just so that it prints without decimal places, since the actual result is based on whole numbers. You also don't need to assign
x just to
return it. Return the value directly.
def approxhalf(lowno, highno):
# Find integer approx halfway point between two values.
The reason rounding has confused you is probably to do with how floats work. For example
0.1 is actually
0.1000000000000000055511151231257827021181583404541015625. This can affect rounding in cases where you think a number is
x.5 but it's actually represented in memory as
x.49942342341, leading to a number that rounds down instead of up.
In your checking system, I think you should rearrange the flow.
It's confusing to check if
compguess is right and at the same time check if it's more than 2 off. You should do each distinct condition as it comes, my preference is to start with the correct answer and broaden out from there:
if compguess == userno:
print('%s. I guess %s' % (count, compguess))
A note, you used
while compguess != userno. But you break out of the loop for other conditions later down. I'd recommend instead using
while True and then use
break for the various points you actually want the loop to be over.
if abs(no2-no1) <= 2:
# For when the low and high numbers are consecutive
if no1 == userno:
print('%s. I guess %s' % (count, no1))
elif no2 == userno:
print('%s. I guess %s' % (count, no2))
print("ERROR: Neither %s nor %s == %s" % (no1, no2, userno))
About that last else. If you're going to have a condition for a seemingly impossible situation, then you should at least output some relevant data to understand what went wrong. Also I put the break outside the
if branches because it should break regardless of which condition is
True. Note that now we don't need an if for the next part, we know it has to evaluate since no other condition (which would end the loop) was
if compguess > userno:
no2 = compguess
elif compguess < userno:
no1 = compguess
Reading PEP0008 will tell you all about what I'm saying here and more. It's highly recommended reading.
You should name your functions using underscores, as that's the recommendation. So you'd have
approx_half(). As for variable names, CamelCase is better for
You almost but not quite have docstrings. You have comments explaining what each function does but formatting as an actual docstring has a practical usage.
def approx_half(lowno, highno):
""" Find integer approx halfway point between two values."""
Enclosing the text in triple quotes when it's at the start of a function will make it a docstring, which means that people can access it in code or in the interpreter to investigate your description of it.
Help on function approx_half in module __main__:
Find integer approx halfway point between two values.