When I run the main or eqparse file, the python terminal will not show any output. This applies to both the command prompt and visual studio code.
Here is my code from the main file. I am including some of the likely unrelated stuff just in case. It is labeled so you can skip all the potentially unrelated stuff.
from graphics import *
from eqparse import *
# NOTE: For equation mapping, it will input a string and convert the data to a table.
# After, you take in the table coords and map each point
# dump vars here #
xypm = 0
global patternFind
global count
global indexlist
# profile initialization #
def init(name, nxsize, nysize, noffset, nzoom):
global zoom
zoom = nzoom
global xsize
xsize = nxsize
global eqtype
eqtype = bool(1)
global ysize
ysize = nysize
global win
win = GraphWin(name, nxsize, nysize)
global offset
offset = noffset
global xymark
xymark = (nzoom * -1)/2
global txsize
txsize = nxsize/2
global tysize
tysize = nysize/2
global txymark
txymark = xymark * -1 + 1
global xp1
xp1 = Point(xypm,(txsize) + offset)
global yp1
yp1 = Point((tysize) + offset, xypm)
global xp2
xp2 = Point(xypm,(txsize) - offset)
global yp2
yp2 = Point((tysize) - offset, xypm)
# starting procedure #
def startUp():
# xy lines #
global xymark
global xp1
global xp2
global yp1
global yp2
global xypm
xtrace = Line(Point(0,tysize), Point(xsize,tysize))
ytrace = Line(Point(txsize,0), Point(txsize,ysize))
xtrace.draw(win)
ytrace.draw(win)
# grid drawer #
while xymark < txymark:
txline = Line(xp1, xp2)
tyline = Line(yp1, yp2)
txline.draw(win)
tyline.draw(win)
xypm = xypm + xsize/zoom
xp1 = Point(xypm,(tysize) + offset)
yp1 = Point((txsize) + offset, xypm)
xp2 = Point(xypm,(tysize) - offset)
yp2 = Point((txsize) - offset, xypm)
xymark = xymark + 1
# code for ending mark #
Line(Point(txsize - offset, ysize - 1), Point(txsize + offset, ysize - 1)).draw(win)
Line(Point(xsize - 1,tysize - offset), Point(xsize - 1, tysize + offset)).draw(win)
# point drawing #
def drawCo(nx, ny):
pCircle = Circle(Point(xsize/zoom * (nx) + xsize/2, ysize - (ysize/zoom * (ny) + ysize/2)), 3)
pCircle.setFill("black")
pCircle.draw(win)
# main #
print("Checkpoint 1")
init("test",500, 500, 10, 20)
print("Checkpoint 2")
startUp()
print("Checkpoint 3")
drawCo(3,5)
print("Checkpoint 4")
patternFind("Dung","DungBeatlesbeingadungbeetle")
print("Checkpoint 5")
print(count)
print("Checkpoint 6")
for x in range(len(indexlist)):
print(indexlist[x])
print("Checkpoint 7")
# exit function #
win.getMouse()
win.close()
and the eqparse file:
# eqparse will look for certain patterns in strings, generate an equation,
# and create a table that a drawing function can read
from main import *
global indexlist
global count
global patternFind
global convStr
# convert string to valid equation data
def convStr(input):
if input[0] == 'y':
print("Linear")
elif input[0] == 'r':
print("Polar")
else:
print("Use Equation type on left side")
# subroutine that will be used to find patterns in a sequence #
def patternFind(pattern, input):
indexlist = []
count = 0
l = len(pattern)
tstr =""
if l > len(input):
pass
else:
i = 0
j = len(input) - len(pattern) + 1
k=0
while j > 0:
tstr = ""
i=0
while len(tstr) < l:
tstr = tstr + input[i + k]
i = i + 1
if tstr == pattern:
count = count + 1
indexlist.append(i+k)
else:
continue
j = j - 1
k=k+1
The output when I run main:
Checkpoint 1
Checkpoint 2
Checkpoint 3
Checkpoint 4
(also the window that I run lags out)
On a related note: When I use the standard import syntax nothing happens. I have to use from (file) import * for it to work.
Yor problem is in def patternFind()
in Your second while loop your counter k and j is never increasing.
So you have a infinite loop.
your code never go beyond the continue statement and stuck there forever.
But maybe you can replace that whole function with a python built-in:
def patternFind(pattern, input):
return pattern in input #true if pattern is in the input
Related
I have a Q-Learning program trying to predict my stock simulated stock market where the price of the stock goes 1-2-3-1-2-3...
I have been trying to debug this for a few days and just can't get it. I even completely started from scratch and the problem persists. If you have extra time, I just need an extra set of eyes on this.
The getStock() function is what simulates the stock price.
The reducePricesToBinary() function takes the stocks and makes it into an put of [Whether the stock went up or down last, how many times it went down/up in a row, how many times the stock went up/down in a row]
The readAI() function just reads what should happen given the inputs
The checkGuess() function checks the previous guess and changes the policyGradient based on whether or not it was right.
Thank you so much!
import requests
import sys
import time
# Constants
learningRate = 0.5
stocksToBuy = 250
discountFactor = 0.5
# Variables declared:
# getStock()
currentStockPrice = 0
pastStockPrice = 0
# reducePricesToBinary()
binaryVersionOfPrices = ""
# Ai()
AI = dict()
# convertBinaryToInputs()
inputsForAI = [0,0,0]
# Ai
guess = 0
oldGuess = 0
reward = 0
pastInputsForAI = ['0',0,0]
firstTurnOver = False
# Buying and Selling stocks
money = 1000000
shares = 0
#
countToSaveEveryFifteen = 0
# Saving anything to a file.
def save(name, data):
with open(name, 'w') as f:
f.write(str(data))
def saveEverything():
save("AI", AI)
save("binaryStockPrices", binaryVersionOfPrices)
save("money", money)
save("shares", shares)
# Runs after an error.
def onExit():
saveEverything()
sys.exit()
# Prints and saves an error log if a function crashes.
def crashProgram(errorMessage):
print(errorMessage)
with open("crashLogs", 'w') as f:
f.write("{}\n\n".format(errorMessage))
onExit()
# Runs a function with try catches to catch an error.
def doFunction(function):
try:
function()
except Exception, e:
crashProgram("Fatal error running {}().\n{}".format(function.__name__, e))
# Gets the current stock value.
#def getStock():
# global currentStockPrice
# res = requests.get("https://markets.businessinsider.com/stocks/aapl-stock")
# stockCostString = ""
# for x in range (9):
# stockCostString += res.text[res.text.find('"price": "')+10 + x]
# currentStockPrice = float(stockCostString)
# print(currentStockPrice)
def getStock():
global currentStockPrice
currentStockPrice = 1 if currentStockPrice == 3 else (2 if currentStockPrice == 1 else 3)
# Turns the prices into 0's and 1's.
def reducePricesToBinary():
global pastStockPrice
global binaryVersionOfPrices
binaryString = "1" if currentStockPrice > pastStockPrice else "0" if currentStockPrice < pastStockPrice else ""
binaryVersionOfPrices += binaryString
pastStockPrice = currentStockPrice
# Converts the binaryStockPrices to inputs for the AI.
def convertBinaryToInputs():
global inputsForAI
inputsForAI[0] = binaryVersionOfPrices[len(binaryVersionOfPrices)-1]
counterOfFirstNumber = 1
counterOfSecondNumber = 1
while(binaryVersionOfPrices[len(binaryVersionOfPrices) - counterOfFirstNumber] == inputsForAI[0]):
counterOfFirstNumber+=1
counterOfFirstNumber-=1
while(binaryVersionOfPrices[len(binaryVersionOfPrices) - counterOfFirstNumber - counterOfSecondNumber]!=inputsForAI[0]):
counterOfSecondNumber += 1
counterOfSecondNumber-=1
inputsForAI[0] = binaryVersionOfPrices[len(binaryVersionOfPrices)-1]
inputsForAI[1] = counterOfFirstNumber
inputsForAI[2] = counterOfSecondNumber
# AI functions
def readAI():
global guess
try:
AIGuess = AI[inputsForAI[0], inputsForAI[1], inputsForAI[2]]
except:
AI[inputsForAI[0], inputsForAI[1], inputsForAI[2]] = 0.5
AIGuess = 0.5
guess = AIGuess
print("GUESS: {}".format(guess))
print("INPUTS: {}".format(inputsForAI))
return guess
def checkGuess():
global firstTurnOver
if(firstTurnOver):
global oldGuess
global reward
global pastInputsForAI
oldGuess = 0 if oldGuess == -1 else 1
print("Old guess: " + str(oldGuess) + " Input: " + str(int(round(float(inputsForAI[0])))))
reward = 1 if oldGuess == int(round(float(inputsForAI[0]))) else -1
AI[pastInputsForAI[0], pastInputsForAI[1], pastInputsForAI[2]] = (1-learningRate) * AI[pastInputsForAI[0], pastInputsForAI[1], pastInputsForAI[2]] + learningRate * (reward + discountFactor * 1)
oldGuess = int(round(float(guess)))
pastInputsForAI = inputsForAI
firstTurnOver = True
def buySellStocks():
global money
global shares
oldStocks = shares
if(guess > 0):
while(money > currentStockPrice and (shares - oldStocks) < stocksToBuy * guess):
money -= currentStockPrice
shares += 1
else:
while(shares > 0 and (oldStocks - shares) > stocksToBuy * guess):
money += currentStockPrice
shares -= 1
# Loads the binaryVersionOfPrices from a file.
def loadBinaryPrices():
global binaryVersionOfPrices
with open("binaryStockPrices", 'r') as f:
binaryVersionOfPrices = f.read()
def loadMoney():
global money
with open("money", 'r') as f:
money = int(f.read())
def loadShares():
global shares
with open("shares", 'r') as f:
shares = int(f.read())
# Loads the AI from a file.
def loadAI():
global AI
with open("AI", 'r') as f:
AI = eval(f.read())
#Prints relative information
def printStuff():
print("Stock price: {}\nCurrent balance: {}\nCurrent shares: {}\nTotal value: {}\nGuess: {}\n".format(currentStockPrice, money, shares, money + shares * currentStockPrice, guess))
# Loads all variables from files.
def onProgramStart():
doFunction(loadAI)
doFunction(loadBinaryPrices)
doFunction(loadMoney)
doFunction(loadShares)
# Saves every 15 checks
def saveEveryFifteen():
global countToSaveEveryFifteen
countToSaveEveryFifteen += 1
if(countToSaveEveryFifteen == 15):
saveEverything()
countToSaveEveryFifteen = 0
# Runs all functions.
def doAllFunctions():
doFunction(reducePricesToBinary)
doFunction(convertBinaryToInputs)
doFunction(readAI)
doFunction(checkGuess)
doFunction(buySellStocks)
doFunction(saveEveryFifteen)
doFunction(printStuff)
doFunction(getStock)
# Loads variables from files.
onProgramStart()
# Repeats the process.
while(1):
doAllFunctions()
time.sleep(0.5)
As I mentioned in my comment, here is a version of the program after some basic refactoring:
import sys
import time
# constants
learning_rate: float = 0.5
stocks_to_buy: float = 250
discount_factor: float = 0.5
# variables declared:
# get_stock()
current_stock_price: int = 0
past_stock_price: int = 0
# reduce_prices_to_binary()
binary_version_of_prices: str = ''
# ai()
a_i: dict = {}
# convert_binary_to_inputs()
inputs_for_a_i = [0, 0, 0]
# ai
guess = 0
old_guess = 0
reward = 0
past_inputs_for_a_i = ['0', 0, 0]
first_turn_over: bool = False
# buying and selling stocks
money: int = 1000000
shares: int = 0
#
count_to_save_every_fifteen: int = 0
# saving anything to a file.
def save(name, data):
with open(name, 'w') as f:
f.write(str(data))
def save_everything():
save("a_i", a_i)
save("binary_stock_prices", binary_version_of_prices)
save("money", money)
save("shares", shares)
# runs after an error.
def on_exit():
save_everything()
sys.exit()
# gets the current stock value.
# def get_stock():
# global current_stock_price
# res = requests.get("https://markets.businessinsider.com/stocks/aapl-stock")
# stock_cost_string = ""
# for x in range (9):
# stock_cost_string += res.text[res.text.find('"price": "')+10 + x]
# current_stock_price = float(stock_cost_string)
# print(current_stock_price)
def get_stock():
global current_stock_price
if current_stock_price == 3:
current_stock_price = 1
elif current_stock_price == 1:
current_stock_price = 2
else:
current_stock_price = 3
# turns the prices into 0's and 1's.
def reduce_prices_to_binary():
global past_stock_price
global binary_version_of_prices
if current_stock_price > past_stock_price:
binary_string = "1"
elif current_stock_price < past_stock_price:
binary_string = "0"
else:
binary_string = ""
binary_version_of_prices += binary_string
past_stock_price = current_stock_price
# converts the binary_stock_prices to inputs for the a_i.
def convert_binary_to_inputs():
global inputs_for_a_i
inputs_for_a_i[0] = binary_version_of_prices[len(binary_version_of_prices) - 1]
counter_of_first_number = 1
counter_of_second_number = 1
while binary_version_of_prices[len(binary_version_of_prices) - counter_of_first_number] == inputs_for_a_i[0]:
counter_of_first_number += 1
counter_of_first_number -= 1
while (binary_version_of_prices[
len(binary_version_of_prices) - counter_of_first_number - counter_of_second_number] !=
inputs_for_a_i[0]):
counter_of_second_number += 1
counter_of_second_number -= 1
inputs_for_a_i[0] = binary_version_of_prices[len(binary_version_of_prices) - 1]
inputs_for_a_i[1] = counter_of_first_number
inputs_for_a_i[2] = counter_of_second_number
# a_i functions
def read_ai():
global guess
try:
a_i_guess = a_i[inputs_for_a_i[0], inputs_for_a_i[1], inputs_for_a_i[2]]
except:
a_i[inputs_for_a_i[0], inputs_for_a_i[1], inputs_for_a_i[2]] = 0.5
a_i_guess = 0.5
guess = a_i_guess
print(f'guess: {guess}')
print(f'inputs: {inputs_for_a_i}')
return guess
def check_guess():
global first_turn_over
if first_turn_over:
global old_guess
global reward
global past_inputs_for_a_i
old_guess = 0 if old_guess == -1 else 1
print(f'old guess: {old_guess}, input: {round(float(inputs_for_a_i[0]))}')
if old_guess == round(float(inputs_for_a_i[0])):
reward = 1
else:
reward = -1
a_i[past_inputs_for_a_i[0], past_inputs_for_a_i[1], past_inputs_for_a_i[2]] = (1 - learning_rate) * a_i[
past_inputs_for_a_i[0], past_inputs_for_a_i[1], past_inputs_for_a_i[2]] + learning_rate * (
reward + discount_factor * 1)
old_guess = int(round(float(guess)))
past_inputs_for_a_i = inputs_for_a_i
first_turn_over = True
def buy_sell_stocks():
global money
global shares
old_stocks = shares
if guess > 0:
while money > current_stock_price and (shares - old_stocks) < stocks_to_buy * guess:
money -= current_stock_price
shares += 1
else:
while shares > 0 and (old_stocks - shares) > stocks_to_buy * guess:
money += current_stock_price
shares -= 1
# loads the binary_version_of_prices from a file.
def load_binary_prices():
global binary_version_of_prices
with open("../resources/ai_stock_files/binary_stock_prices", 'r') as f:
binary_version_of_prices = f.read()
def load_money():
global money
with open("../resources/ai_stock_files/money") as f:
money = int(f.read())
def load_shares():
global shares
with open("../resources/ai_stock_files/shares") as f:
shares = int(f.read())
# loads the _a_i from a file.
def load_a_i():
global a_i
with open("../resources/ai_stock_files/a_i") as f:
a_i = eval(f.read())
# prints relative information
def print_stuff():
print(f"stock price: {current_stock_price}\n"
f"current balance: {money}\n"
f"current shares: {shares}\n"
f"total value: {money + shares * current_stock_price}\n"
f"guess: {guess}\n")
# loads all variables from files.
def on_program_start():
load_a_i()
load_binary_prices()
load_money()
load_shares()
# saves every 15 checks
def save_every_fifteen():
global count_to_save_every_fifteen
count_to_save_every_fifteen += 1
if count_to_save_every_fifteen == 15:
save_everything()
count_to_save_every_fifteen = 0
# runs all functions.
def do_all_functions():
reduce_prices_to_binary()
convert_binary_to_inputs()
read_ai()
check_guess()
buy_sell_stocks()
save_every_fifteen()
print_stuff()
get_stock()
# loads variables from files.
on_program_start()
# repeats the process.
while True:
do_all_functions()
time.sleep(0.5)
When correcting the policies in the policy gradient, I was using inputs from a cycle ago and over compensating by calling the functions in an order where it already used inputs from a cycle ago, effectively making the gradient off by two inputs. Since I was cycling the input in 3's it made it look like an "off-by-one" error when in reality I was off by two, making it hard to detect.
given the following code (in python):
import random
import sys
import collections
commandStr = ["addClan", "addPlayer",
"clanFight", "getMinClan"]
SUCCESS = "SUCCESS"
FAILURE = "FAILURE"
INVALID_INPUT = "INVALID_INPUT"
ClanID = dict()
playersID = dict()
ClanScore = collections.defaultdict(list)
playersClan = dict()
LosingClans = set()
Clans_count = 0;
players_count = 0;
def initline():
global ClanID, Clans_count
inLine = "init 2 0 1"
outLine = "init done."
ClanID[0] = {}
ClanID[1] = {}
Clans_count += 2
return inLine, outLine
# addClan clanID
def addClan():
global ClanID, Clans_count
clanID = random.randint(-2, 8)
inLine = "addClan %d" % (clanID)
outLine = "addClan: "
if clanID < 0:
outLine += INVALID_INPUT
elif clanID in ClanID.keys():
outLine += FAILURE
else:
ClanID[clanID] = {}
Clans_count += 1
outLine += SUCCESS
return inLine, outLine
# addPlayer playerID score clanID
def addPlayer():
global playersID, ClanID, ClanScore, playersClan, players_count
playerID = random.randint(-10, 1000)
score = random.randint(-10, 1000)
clanID = random.randint(-2, 8)
inLine = "addPlayer %d %d %d" % (playerID, score, clanID)
outLine = "addPlayer: "
if playerID < 0 or clanID < 0 or score <0:
outLine += INVALID_INPUT
elif playerID in playersID.keys() or clanID not in ClanID.keys():
outLine += FAILURE
else:
playersID[playerID] = playerID
if clanID in ClanScore.keys():
ClanScore[clanID].append(score)
else:
ClanScore[clanID] = [score]
playersClan[playerID] = clanID
ClanID[clanID][playerID] = (playersID[playerID], clanID)
players_count += 1
outLine += SUCCESS
return inLine, outLine
# getMinClan
def getMinClan():
global ClanID, LosingClans
inLine = "getMinClan"
outLine = "getMinClan: "
for Clan_id in sorted(ClanID):
if Clan_id not in LosingClans:
outLine += SUCCESS + " %d" % Clan_id
break
return inLine, outLine
def sum_n_strongest(Clan, num):
sortedClan = sorted(Clan, reverse=True)
topNum = sortedClan[:num]
Sum = 0
for element in topNum:
Sum += element
return Sum
# clanFight clan1 clan2 k1 k2
def clanFight():
global ClanID, ClanScore, LosingClans
clan1 = random.randint(-1, 8)
clan2 = random.randint(-1, 8)
k1 = random.randint(-1, 10)
k2 = random.randint(-1, 10)
inLine = "clanFight %d %d %d %d" % (clan1, clan2, k1, k2)
outLine = "clanFight: "
if k1 <= 0 or k2 <= 0 or clan1 < 0 or clan2 < 0:
outLine += INVALID_INPUT
elif clan1 not in ClanID.keys() or clan2 not in ClanID.keys() or clan1 == clan2 or len(ClanID[clan1]) < k1 or len(ClanID[clan2]) < k2:
outLine += FAILURE
elif clan1 in LosingClans or clan2 in LosingClans:
outLine += FAILURE
else:
sum1 = sum_n_strongest(ClanScore[clan1], k1)
sum2 = sum_n_strongest(ClanScore[clan2], k2)
if sum1 == sum2:
if clan1 < clan2:
LosingClans.add(clan2)
else:
LosingClans.add(clan1)
elif sum1 < sum2:
LosingClans.add(clan1)
else:
LosingClans.add(clan2)
outLine += SUCCESS
return inLine, outLine
def main():
if len(sys.argv) < 3:
print("Usage %s <lines>" % sys.argv[0])
exit(0)
lines = int(sys.argv[1])
infname = "%s.in" % sys.argv[2]
outfname = "%s.out" % sys.argv[2]
functions = [addClan, addPlayer,
getMinClan, clanFight]
with open(infname, 'wb') as infhandler:
with open(outfname, 'wb') as outfhandler:
inLine, outLine = initline()
infhandler.write(inLine + "\n")
outfhandler.write(outLine + "\n")
while lines > 0:
f = random.randint(0, len(functions)-1)
func = functions[f]
inLine, outLine = func()
if inLine is not "":
infhandler.write(inLine + "\n")
outfhandler.write(outLine + "\n")
lines -= 1
infhandler.write("quit\n")
outfhandler.write("quit done.\n")
main()
This code should create a new file while I need to give as parameters filename and numberOfLines.
But, while I trying to run this script, opened to me a black window (like a cmd) and it's closed immediately.
How can I fix it? someone know what is the problem?
Note: this code written me in a file which his name is "Test.py" , and I trying to run it with this line command: python ./Test.py <Number of Lines> <Test Name> (at least, I trying to do it while I double-click about "Test.py" but like that I said, the window closed immediately..
Follow-up question: Are you using an IDE, or are you trying to run this from the command line/command prompt?
First, check if the files exist after you run the program. It might just be that the program is running quickly enough that it only takes a couple milliseconds, and the command prompt goes away once the program terminates. If it does create a file, the program wouldn't outwardly notify you; look in your file directory and see if it did.
Second, instead of just calling main() at the end of your file, maybe try:
if __name__ == "__main__":
main()
and see if anything different happens. This bit of code is executed whenever the file is run as specifically as a script (as you're doing with the command % python Test.py <num> <fname>).
I'm in the process of creating a minesweeper style game using a turtle-based grid setup. I need to find the closest cell within the grid and reveal the icon located under it whether that be a bomb or a number icons. I'm not looking to make it exact, I just need the mouse click to find the nearest cell in the grid even if the click isn't directly on the board. Currently my code only reveals the icon of the last turtle created on the board and then does nothing else with further clicks.
What can I do to make it recognize the real closest click and do it multiple times until the last bomb is found?
import random
import turtle
import cell
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__probelist = []
offset = (size-1) * 17
for x in range(size):
for y in range(size):
t = cell.Cell(x,y)
t.up()
t.shape('question.gif')
t.goto(y*34-offset, offset-x*34)
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, (self.__boardsize**2) - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, x, y):
for t in self.__boardlist:
pos = t.position()
distx = abs(x - pos[0])
disty = abs(y - pos[1])
distfinal = (distx ** 2 + disty ** 2) ** 0.5
curdist = 0
if curdist < distfinal:
curdist = distfinal
closest = t
if closest in self.__probelist:
return (self.__probe, self.__bombnum)
elif closest in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
else:
closest.shape("0.gif")
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
def registershapes():
wn = turtle.Screen()
wn.register_shape('0.gif')
wn.register_shape('1.gif')
wn.register_shape('2.gif')
wn.register_shape('3.gif')
wn.register_shape('4.gif')
wn.register_shape('5.gif')
wn.register_shape('6.gif')
wn.register_shape('7.gif')
wn.register_shape('8.gif')
wn.register_shape('9.gif')
wn.register_shape('bomb.gif')
wn.register_shape('question.gif')
I believe you're approaching this problem the wrong way. You're activating screen.onclick() and trying to map it to a turtle. Instead, activate turtle.onclick() on the individual turtles, deactivating it when a turtle is selected. Then you don't have to search for the turtle in question, and not actively ignore turtles that have already been selected.
Below is my rework of your code from this and your previous question into an example you can run. I had to guess about the definition of the Cell class:
from turtle import Turtle, Screen
import random
class Cell(Turtle):
def __init__(self, number):
super().__init__("question.gif")
self.__number = number
self.penup()
def number(self):
return self.__number
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__rnums = None
offset = (size - 1) * 17
for y in range(size):
for x in range(size):
t = Cell(x + y * size)
t.goto(x * 34 - offset, offset - y * 34)
t.onclick(lambda x, y, self=t: closure(self))
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, self.__boardsize ** 2 - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, closest):
closest.onclick(None)
if closest.number() in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
else:
closest.shape("0.gif")
self.__probe += 1
return (self.__probe, self.__bombnum)
def registershapes():
screen.register_shape('0.gif')
# ...
screen.register_shape('bomb.gif')
screen.register_shape('question.gif')
def closure(closest):
_, rem = mine.probe(closest)
if rem == 0:
over = screen.textinput("Text Input", "Would you like to play again? (Y)es or (N)o")
if over.upper() == 'Y':
main()
else:
screen.bye()
def main():
global mine
board = screen.numinput("Numeric Input", "Enter desired board size: ")
mine = Game(int(board))
nummine = screen.numinput("Numeric Input", "Enter desired number of mines: ")
mine.hideMines(int(nummine))
screen = Screen()
mine = None
main()
screen.mainloop()
My first function I defined that works
def chainPoints(aa,DIS,SEG,H):
#xtuple
n=0
xterms = []
xterm = -DIS
while n<=SEG:
xterms.append(xterm)
n+=1
xterm = -DIS + n*SEGL
#
#ytuple
k=0
yterms = []
while k<=SEG:
yterm = H + aa*m.cosh(xterms[k]/aa) - aa*m.cosh(DIS/aa)
yterms.append(yterm)
k+=1
But now I need a second function that depends on my first function, speciffically the lists xterms and yterms.
def chainLength(aa,DIS,SEG,H):
chainPoints(aa,DIS,SEG,H)
#length of chain
ff=1
Lterm=0.
totallength=0.
while ff<=SEG:
Lterm = m.sqrt((xterms[ff]-xterms[ff-1])**2 + (yterms[ff]-yterms[ff-1])**2)
totallength += Lterm
ff+=1
return(totallength)
I had it all done without defined functions, but now I need to have defined functions for each part.
You need to return results from your chainPoints() function, then assign the return value to local name(s) in your chainLength() function:
def chainPoints(aa, DIS, SEG, H):
#xtuple
n = 0
xterms = []
xterm = -DIS
while n <= SEG:
xterms.append(xterm)
n += 1
xterm = -DIS + n * SEGL
#
#ytuple
k = 0
yterms = []
while k <= SEG:
yterm = H + aa * m.cosh(xterms[k] / aa) - aa * m.cosh(DIS / aa)
yterms.append(yterm)
k += 1
return xterms, yterms
def chainLength(aa, DIS, SEG, H):
xterms, yterms = chainPoints(aa, DIS, SEG, H)
ff = 1
Lterm = 0.
totallength = 0.
while ff <= SEG:
Lterm = m.sqrt((xterms[ff] - xterms[ff-1]) ** 2 +
(yterms[ff] - yterms[ff - 1]) ** 2)
totallength += Lterm
ff += 1
return totallength
I used the same names in chainLength here, but that is not a requirement.
I have a label into which I am going to put content of different sizes. I would like to know how high I need to make the label so that I can size the window so it can stay the same for the different content sizes. I have a strategy, but it seems more complicated then it should be.
I want to set a label to a given width and wraplength:
l = Label(root)
l['width'] = 30
l['wraplength'] = 244
l['text'] = "testing this"
Now I want to query the label to find how many lines are used. l['height'] stays at 0, so the best I have been able to come up with is to use l.winfo_height() and convert the height given in pixels to the number of lines used. Nothing in dir(l) seems to give me the information directly, but this strategy is fragile to font changes and other changes.
Any suggestions?
Update: using Brian Oakley's suggestion (which is similar to what I got on usenet) I have the following approximation to a solution (needs polishing, e.g. doesn't take into account that Label breaks at whitespace):
import Tkinter as Tk
import tkFont
import random
import sys
def genstr (j):
rno = random.randint(4,50)
ret_val = str(j) + ":"
for i in range (0, rno):
ret_val += "hello" + str(i)
return ret_val
def gendata (lh):
ret_val = []
for i in range(0,lh):
ret_val.append (genstr (i))
return ret_val
data = gendata (100)
root = Tk.Tk()
font = tkFont.Font(family='times', size=13)
class lines:
def __init__ (self):
self.lastct = 1 # remember where the cutoff was last work from there
def count (self, text, cutoff = 400):
global font
no_lines = 1
start_idx = 0
idx = self.lastct
while True:
if idx > len (text):
idx = len (text)
# shrink from guessed value
while font.measure (text[start_idx:idx - 1]) > cutoff:
if idx <= start_idx:
print "error"
sys.exit ()
else:
idx -= 1
self.lastct = idx - start_idx # adjust since was too big
# increase from guessed value (note: if first shrunk then done)
while (idx < len (text)
and font.measure (text[start_idx:idx]) < cutoff):
idx += 1
self.lastct = idx - start_idx # adjust since was too small
# next line has been determined
print "*" + text[start_idx:idx-1] + "*"
if idx == len(text) and font.measure (text[start_idx:]) < cutoff:
return no_lines
elif idx == len(text):
return no_lines + 1
else:
no_lines += 1
start_idx = idx - 1
idx = start_idx + self.lastct
lin = lines()
for i in range(0,len(data)):
lin.count(data[i], 450)
for i in range(0,min(len(data),10)):
l = Tk.Label(root)
l.pack()
l['text'] = data[i]
print i
no = lin.count (data[i], 450)
print "computed lines", no
l['width'] = 50
l['justify'] = Tk.LEFT
l['anchor'] = 'w'
l['wraplength'] = 450
l['padx']=10
l['pady'] = 5
l['height'] = no
l['font'] = font
if i % 2 == 0:
l['background'] = 'grey80'
else:
l['background'] = 'grey70'
root.mainloop()
You are correct that the height attribute doesn't change. That attribute doesn't tell you the actual height, only the height it is configured to be. The actual height depends on factors such as how much text is in it, the wrap length, the font, and how the widget geometry is managed.
tkinter Font objects have a measure method which lets you determine how tall and wide a string is for a given font. You can get the font for the widget and use that method to determine how much space is required for your string.