Currently, I am writing a code on Python to make lab 6 for CS50x. When I am trying to debug my code, it seems just to skip the function simulate_tournament() and produces anything as an output. I would appreciate suggestions on how to debug this code and make the program running:)
My code with the mentioned problem:
# Simulate a sports tournament
import csv
import sys
import random
# Number of simluations to run
N = 1000
def main():
# Ensure correct usage
if len(sys.argv) != 2:
sys.exit("Usage: python tournament.py FILENAME")
teams = []
# TODO: Read teams into memory from file
with open(sys.argv[1], "r") as file:
reader = csv.DictReader(file)
for row in reader:
row["team"]
row["rating"] = int(row["rating"])
teams.append(row)
counts = {}
# TODO: Simulate N tournaments and keep track of win counts
i = 0
while i < N:
winner = simulate_tournament(teams)
if winner in counts:
counts["winner"] += 1
else:
counts["winner"] = 1
# Print each team's chances of winning, according to simulation
for team in sorted(counts, key=lambda team: counts[team], reverse=True):
print(f"{team}: {counts[team] * 100 / N:.1f}% chance of winning")
def simulate_game(team1, team2):
"""Simulate a game. Return True if team1 wins, False otherwise."""
rating1 = team1["rating"]
rating2 = team2["rating"]
probability = 1 / (1 + 10 ** ((rating2 - rating1) / 600))
return random.random() < probability
def simulate_round(teams):
"""Simulate a round. Return a list of winning teams."""
winners = []
# Simulate games for all pairs of teams
for i in range(0, len(teams), 2):
if simulate_game(teams[i], teams[i + 1]):
winners.append(teams[i])
else:
winners.append(teams[i + 1])
return winners
def simulate_tournament(teams):
"""Simulate a tournament. Return name of winning team."""
# TODO
while len(teams) > 1:
teams = simulate_round(teams)
return teams[0]["team"]
if __name__ == "__main__":
main()
I think it is because you don't increment i your while loop?
i = 0
while i < N:
winner = simulate_tournament(teams)
if winner in counts:
counts["winner"] += 1
else:
counts["winner"] = 1
I think your simulate_tournament function is not returning a value.
Try with:
if len(teams) > 2:
winners = simulate_round(teams)
ganador = simulate_tournament(winners)
else:
ganador = simulate_round(teams)
return ganador[0]['team']
return ganador
i donĀ“t know if its the most efficient function, but it worked fine for me!
I was working on the same lab today. I think your mistake is here:
with open(sys.argv[1], "r") as file:
It should be only, with open(sys.argv[1]) as file.
You need to have keys/values inside your count variable. The reason why it is not printing anything is because there is nothing in count. Also you are not supposed to use winner as a string, the function returns a string so python automatically makes winner a string variable. You are supposed to hash the string returned for winner to the counts variable and thus update count to the correct name.
Related
I'm working on a Mancala game where players get to play against an AI. the code is complete, the Mancala game functionality is found within the Mancala_helpers, the AI algorithm is a MinMax tree and is found in the MinMax file, and finally the game itself. everything runs fine except for when the AI plays, if the AI starts the game immediately ends, it moves all the rocks from its pits in one round. and if I start I can only play one move before it does the same. I cannot understand what's happening, at first, I thought maybe I had a problem within the function of mancala helpers where they did not switch turns properly and the AI kept playing. but I ran multiple tests and that part is working fine. I cant identify the issue, help, please. if anyone also has suggestions for a better evaluation function then that would be great. thanks
--------------------------Mancala helpers--------------
# TODO: implement pad(num)
# Return a string representation of num that is always two characters wide.
# If num does not already have two digits, a leading "0" is inserted in front.
# This is called "padding". For example, pad(12) is "12", and pad(1) is "01".
# You can assume num is either one or two digits long.
def pad(num: int) -> str:
x = str(num)
if len(x) > 1:
return x
else:
return "0"+x
# TODO: implement pad_all(nums)
# Return a new list whose elements are padded versions of the elements in nums.
# For example, pad_all([12, 1]) should return ["12", "01"].
# Your code should create a new list, and not modify the original list.
# You can assume each element of nums is an int with one or two digits.
def pad_all(nums: list) -> list:
x = []
for i in nums:
x.append(pad(i))
return x
# TODO: implement initial_state()
# Return a (player, board) tuple representing the initial game state
# The initial player is player 0.
# board is list of ints representing the initial mancala board at the start of the game.
# The list element at index p should be the number of gems at position p.
def initial_state() -> tuple:
return (0, [4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 0])
# TODO: implement game_over(state)
# Return True if the game is over, and False otherwise.
# The game is over once all pits are empty.
# Your code should not modify the board list.
# The built-in functions "any" and "all" may be useful:
# https://docs.python.org/3/library/functions.html#all
def game_over(state: tuple) -> bool:
lst = state[1]
if (lst[0] == lst[1] == lst[2] == lst[3] == lst[4] == lst[5] == 0) or (lst[7] == lst[8] == lst[9] == lst[10] == lst[11] == lst[12] == 0):
return True
else:
return False
# TODO: implement valid_actions(state)
# state is a (player, board) tuple
# Return a list of all positions on the board where the current player can pick up gems.
# A position is a valid move if it is one of the player's pits and has 1 or more gems in it.
# For example, if all of player's pits are empty, you should return [].
# The positions in the returned list should be ordered from lowest to highest.
# Your code should not modify the board list.
def valid_actions(state: tuple) -> list:
actions = []
lst = state[1]
player = state[0]
if player == 0:
for i in range(6):
if lst[i] > 0:
actions.append(i)
return actions
else:
for i in range(6):
if lst[i+7] >0: actions.append(i+7)
return actions
# TODO: implement mancala_of(player)
# Return the numeric position of the given player's mancala.
# Player 0's mancala is on the right and player 1's mancala is on the left.
# You can assume player is either 0 or 1.
def mancala_of(player: int) -> int:
if player ==0: return 6
elif player==1: return 13
# TODO: implement pits_of(player)
# Return a list of numeric positions corresponding to the given player's pits.
# The positions in the list should be ordered from lowest to highest.
# Player 0's pits are on the bottom and player 1's pits are on the top.
# You can assume player is either 0 or 1.
def pits_of(player: int) -> list:
if player ==0:
return [0,1,2,3,4,5]
elif player==1:
return [7,8,9,10,11,12]
# TODO: implement player_who_can_do(move)
# Return the player (either 0 or 1) who is allowed to perform the given move.
# The move is allowed if it is the position of one of the player's pits.
# For example, position 2 is one of player 0's pits.
# So player_who_can_do(2) should return 0.
# You can assume that move is a valid position for one of the players.
def player_who_can_do(move: int) -> int:
if move in [0,1,2,3,4,5] : return 0
elif move in [7,8,9,10,11,12]: return 1
# TODO: implement opposite_from(position)
# Return the position of the pit that is opposite from the given position.
# Check the pdf instructions for the definition of "opposite".
def opposite_from(position: int) -> int:
d_p_1 = {}
d_p_1[0]=12
d_p_1[1]=11
d_p_1[2]=10
d_p_1[3]=9
d_p_1[4]=8
d_p_1[5]=7
d_p_1[7]=5
d_p_1[8]=4
d_p_1[9]=3
d_p_1[10]=2
d_p_1[11]=1
d_p_1[12]=0
return d_p_1[position]
# TODO: implement play_turn(move, board)
# Return the new game state after the given move is performed on the given board.
# The return value should be a tuple (new_player, new_board).
# new_player should be the player (0 or 1) whose turn it is after the move.
# new_board should be a list representing the new board state after the move.
#
# Parameters:
# board is a list representing the current state of the game board before the turn is taken.
# move is an int representing the position where the current player picks up gems.
# You can assume that move is a valid move for the current player who is taking their turn.
# Check the pdf instructions for the detailed rules of taking a turn.
#
# It may be helpful to use several of the functions you implemented above.
# You will also need control flow such as loops and if-statements.
# Lastly, the % (modulo) operator may be useful:
# (x % y) returns the remainder of x / y
# from: https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
def play_turn(move: int, board: list) -> tuple:
player = player_who_can_do(move)
new_board = board
gems = new_board[move]
new_board[move] = 0
hasht = {}
hasht[0] =1
hasht[1] = 0
if player ==0:
x =0
offset = 1
gems_counter = gems
for i in range(gems):
if i + move + offset == 13: offset += 1
elif (i+move+offset) - 14 == 13: offset += 1
if i + move +offset > 13:
gem_position = (i+move+offset) - 14
else:
gem_position = i + move + offset
new_board[gem_position] += 1
gems_counter -= 1
if gems_counter ==0 and gem_position==6: x = 1
if gems_counter==0 and gem_position in pits_of(0) and new_board[gem_position] == 1 and new_board[opposite_from(gem_position)] > 0:
gems_from_myside = new_board[gem_position]
gems_from_opside = new_board[opposite_from(gem_position)]
new_board[6] = gems_from_myside+gems_from_opside
new_board[gem_position] = 0
new_board[opposite_from(gem_position)] = 0
return (hasht[x],new_board)
if player ==1:
x_2 = 1
offset = 1
gems_counter2 = gems
for i in range(gems):
if i + move + offset == 6: offset += 1
elif (i+move+offset) - 14 == 6: offset += 1
if i + move +offset > 13:
gem_position = (i+move+offset) - 14
else:
gem_position = i + move + offset
new_board[gem_position] += 1
gems_counter2 -= 1
if gems_counter2 == 0 and gem_position == 13: x_2 = 0
if gems_counter2==0 and gem_position in pits_of(1) and new_board[gem_position] == 1 and new_board[opposite_from(gem_position)] > 0:
gems_from_myside = new_board[gem_position]
gems_from_opside = new_board[opposite_from(gem_position)]
new_board[13] = gems_from_myside+gems_from_opside
new_board[gem_position] = 0
new_board[opposite_from(gem_position)] = 0
return (hasht[x_2],new_board)
# TODO: implement clear_pits(board)
# Return a new list representing the game state after clearing the pits from the board.
# When clearing pits, any gems in a player's pits get moved to that player's mancala.
# Check the pdf instructions for more detail about clearing pits.
def clear_pits(board: list) -> list:
length = len(board)
middle_index = length // 2
first_half = board[:middle_index]
second_half = board[middle_index:]
for i in range(6):
first_half[6] += first_half[i]
first_half[i]=0
second_half[6] += second_half[i]
second_half[i] = 0
return (first_half+second_half)
# This one is done for you.
# Plays a turn and clears pits if needed.
def perform_action(action, state):
player, board = state
new_player, new_board = play_turn(action, board)
if 0 in [len(valid_actions((0, new_board))), len(valid_actions((1, new_board)))]:
new_board = clear_pits(new_board)
return new_player, new_board
# TODO: implement score_in(state)
# state is a (player, board) tuple
# Return the score in the given state.
# The score is the number of gems in player 0's mancala, minus the number of gems in player 1's mancala.
def score_in(state: tuple) -> int:
lst = state[1]
return lst[6] - lst[13]
# TODO: implement is_tied(board)
# Return True if the game is tied in the given board state, False otherwise.
# A game is tied if both players have the same number of gems in their mancalas.
# You can assume all pits have already been cleared on the given board.
def is_tied(board: list) -> bool:
if board[mancala_of(0)] - board[mancala_of(1)] == 0: return True
else: return False
# TODO: implement winner_of(board)
# Return the winning player (either 0 or 1) in the given board state.
# The winner is the player with more gems in their mancala.
# You can assume it is not a tied game, and all pits have already been cleared.
def winner_of(board: list) -> int:
if board[mancala_of(0)] > board[mancala_of(1)]: return 0
elif board[mancala_of(0)] < board[mancala_of(1)]: return 1
# TODO: implement string_of(board)
def string_of(board: list) -> str:
new_board = pad_all(board)
return '\n {} {} {} {} {} {}\n {} {}\n {} {} {} {} {} {}\n'.format(new_board[12],new_board[11],new_board[10],new_board[9],new_board[8],new_board[7],new_board[13],new_board[6],new_board[0],new_board[1],new_board[2],new_board[3],new_board[4],new_board[5])
-----------------------MinMax AI-------------------------------------------------------------
from os import stat
import numpy as np
from mancala_helpers import *
# A simple evaluation function that simply uses the current score.
def simple_evaluate(state):
return score_in(state)
# TODO
# Implement a better evaluation function that outperforms the simple one.
def better_evaluate(state):
#lst = state[1]
#return score_in(state)/2
return None
# depth-limited minimax as covered in lecture
def minimax(state, max_depth, evaluate):
# returns chosen child state, utility
# base cases
if game_over(state): return None, score_in(state)
if max_depth == 0: return None, evaluate(state)
# recursive case
children = [perform_action(action, state) for action in valid_actions(state)]
results = [minimax(child, max_depth-1, evaluate) for child in children]
_, utilities = zip(*results)
player, board = state
if player == 0: action = np.argmax(utilities)
if player == 1: action = np.argmin(utilities)
return children[action], utilities[action]
# runs a competitive game between two AIs:
# better_evaluation (as player 0) vs simple_evaluation (as player 1)
def compete(max_depth, verbose=True):
state = initial_state()
while not game_over(state):
player, board = state
if verbose: print(string_of(board))
if verbose: print("--- %s's turn --->" % ["Better","Simple"][player])
state, _ = minimax(state, max_depth, [better_evaluate, simple_evaluate][player])
score = score_in(state)
player, board = state
if verbose:
print(string_of(board))
print("Final score: %d" % score)
return score
if __name__ == "__main__":
score = compete(max_depth=4, verbose=True)
----------------------------------------playing the game---------------------------
from os import stat
from mancala_helpers import *
from mancala_minimax import minimax, simple_evaluate
def get_user_action(state):
actions = list(map(str, valid_actions(state)))
player, board = state
prompt = "Player %d, choose an action (%s): " % (player, ",".join(actions))
while True:
action = input(prompt)
if action in actions: return int(action)
print("Invalid action, try again.")
if __name__ == "__main__":
max_depth = 1
state = initial_state()
while not game_over(state):
player, board = state
print(string_of(board))
if player == 0:
action = get_user_action(state)
state = perform_action(action, state)
else:
print("--- AI's turn --->")
#print(string_of(board))
print(state)
print(max_depth)
state, _ = minimax(state, max_depth, simple_evaluate)
#print(string_of(board))
player, board = state
print(string_of(board))
if is_tied(board):
print("Game over, it is tied.")
else:
winner = winner_of(board)
print("Game over, player %d wins." % winner)
the entire problem was in the mancala helper file. in the function play_turn() the 2nd line new_board = board. this was causing the issue because the original state should be immutable to work properly. any changes on new_board were also affecting board. the following new_board = copy.deepcopy(board) fixed everything. the function copy.deepcopy() creates a completely new copy, any changes applied to one of them does not affect the other.
Just learning python, and trying to make a game of Hangman.
I'm having an issue when running the program, where if I run through it without trying to throw it off (ex. input "enter" and input "2") then it gives me a random word of difficulty I'm asking for.
If I try to throw it off, (ex. input "enter", input "12", input "3") it returns "None"
I've been trying to figure it out, printing different variables in different locations to see what's off, but I can't find anything.
I'd appreciate any help I can get.
Any other input welcome as well.
wordbank file
import random
import math
# Random Word Generator
with open('wordbank.csv') as f:
file = f.read().split('\n')
word_list = list(file)
def max_letters(x):
max_length = 0
for words in x:
if len(str(words)) >= max_length:
max_length = len(str(words))
return max_length
def word_selector(x):
diff = input("What difficulty would you like? Type a difficulty of 1 - 3 and press 'Enter': ")
diff_list = []
diff_var = math.ceil((max_letters(word_list) / 3))
if diff == "1" or diff == "2" or diff == "3":
for words in x:
length = len(str(words))
if diff == "1":
if 0 < length <= diff_var:
diff_list.append(str(words))
elif diff == "2":
if diff_var < length <= (diff_var * 2):
diff_list.append(str(words))
elif diff == "3":
if (diff_var * 2) < length:
diff_list.append(str(words))
return random.choice(diff_list)
else:
print("That's not an option... Difficulties are 1 - 3. Try again.")
word_selector(word_list)
def start_hangman():
start = input("Press 'Enter' to start!\n")
if start == "":
print(word_selector(word_list)) # Will eventually be hangman
else:
print("What are you doing??? Just press enter!")
start_hangman()
start_hangman()
You are calling the function back, which is called recursion. It can be pretty confusing. Let's say a bad input, 12 is entered. The function word_selector() will execute the else statement, which calls the function back:
def word_selector(x):
(...)
else:
word_selector(word_list) # <-- we are here
The function then asks again for input, let's say this time a valid input is entered, 3. It will then correctly return a word, let's say apple. So now, the function returned apple, but we are back at where the function was called from.
def word_selector(x):
(...)
else:
"apple" # because the function call returned "apple".
As you can see now, the else condition simply says "apple", without returning anything or assigning it to a value. Since the function does not return anything, python makes it return None, which is like a null/undefined value. This is why you are getting your error.
As a fix, I believe you have to move your error-checking and input getting code out of word_selector() to the start_hangman() loop. For example, this works as intended:
import random
import math
# Random Word Generator
with open('wordbank.csv') as f:
file = f.read().split('\n')
word_list = list(file)
def max_letters(x):
max_length = 0
for words in x:
if len(str(words)) >= max_length:
max_length = len(str(words))
return max_length
def word_selector(x, diff):
diff_list = []
diff_var = math.ceil((max_letters(word_list) / 3))
for words in x:
length = len(str(words))
if diff == "1":
if 0 < length <= diff_var:
diff_list.append(str(words))
elif diff == "2":
if diff_var < length <= (diff_var * 2):
diff_list.append(str(words))
elif diff == "3":
if (diff_var * 2) < length:
diff_list.append(str(words))
return random.choice(diff_list)
def start_hangman():
start = input("Press 'Enter' to start!\n")
if start == "":
diff = input(
"What difficulty would you like? Type a difficulty of 1 - 3 and press 'Enter': ")
if diff == "1" or diff == "2" or diff == "3":
print(word_selector(word_list, diff))
else:
print("That's not an option... Difficulties are 1 - 3. Try again.")
start_hangman()
else:
print("What are you doing??? Just press enter!")
start_hangman()
start_hangman()
i switched to python after some few months of learning c#. am a newbie in both.
i was getting an "undefined variable 'appender' error msg and for other def method in the class. i removed it from the class and noticed that the password list is always empty and never updates. how can i fix this?
feel free to check the code and criticize it, am still learning and don't know how this fully works
THANKS
import random
#Lists of avaliable code options
numb_opt = ['1','2','3','4','5','6','7','8','9','0']
char_opt = ['a','b','c','d','e','f','g','h','i','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
sym_opt = ['~','!','#','#','$','%','?','/']
avaliable_code = [numb_opt, char_opt, sym_opt]
""" This class generates and returns password based on data passed by the user. """
class generator:
def __init__(self, passLength, charLength, symLength, numbLength):
#initializing attributes
self.passLength = passLength
self.charLength = charLength
self.symLength = symLength
self.numbLength = numbLength
#Passcode generator
#select random list and passcode from list and append to empty list
def passcode_generator(self):
counter = 1
while counter <= self.passLength:
active_list = random.choice(avaliable_code) #pick random list from lists
#check which list by index, generated code of len == user's, append code and remove list
if active_list == avaliable_code[0] and isList_used(active_list) == False:
c = 1
while c <= self.numbLength:
p = random.choice(active_list)
appender(p)
c += c
pass
elif active_list == avaliable_code[1] and isList_used(active_list) == False:
c = 1
while c <= self.charLength:
p = random.choice(active_list)
appender(p)
c += c
pass
elif active_list == avaliable_code[2] and isList_used(active_list) == False:
c = 1
while c <= self.symLength:
p = random.choice(active_list)
appender(p)
c += c
pass
counter += counter
pass
'''
#Passcode appender
def appender(code):
passwords = [] #empty list which would hold passwords durig generation.
passwords.append(code)
print(passwords) '''
#Exiting dialog
def exiting_dialog(self):
print("Closing session...........")
print("Exiting program")
pass
def PrintOut(passwrd):
return passwrd
#Returns true if list is used
def isList_used(u_list):
isUsed = False
used = []
#check if active list is in used list. if yes, don't use list
if u_list in used:
isUsed = True #if list is used
elif u_list not in used:
isUsed = False #if list is not used
used.append(u_list)
return isUsed
I'm making a scalable tic tac toe game in Tkinter (meaning the board size can be 2x2 up to whatever fits the screen). I'm using cget("image") to find what mark a button has. For some reason, the win check displays very random things. I've tried a lot of semi-random things to fix it, but had no success in fixing it. Here's the code:
from tkinter import *
class XOGame:
def main_game(self):
self.__game_window = Tk()
self.__grid_size = 3 # User inputted in a different part of the code
self.__game_window.title("Tic Tac Toe (" + str(self.__grid_size) + "x"
+ str(self.__grid_size) + ")")
# this is user inputted in a different part of the program.
self.__players = ["p1", "p2"]
self.__player1 = self.__players[0]
self.__player2 = self.__players[1]
self.build_board(self.__game_window)
self.__game_window.mainloop()
def build_board(self, window):
self.__size = self.__grid_size ** 2
self.__turn_nr = 1
self.__win = False
self.__empty_square = PhotoImage(master=window,
file="rsz_empty.gif")
self.__x = PhotoImage(master=window,
file="rsz_cross.gif")
self.__o = PhotoImage(master=window,
file="rsz_nought.gif")
self.__squares = [None] * self.__size
self.create_win_check_lists()
# Building the buttons and gridding them
for i in range(self.__size):
self.__squares[i] = (Button(window, image=self.__empty_square))
row = 0
column = 0
number = 1
for j in self.__squares:
j.grid(row=row, column=column)
j.config(command=lambda index=self.__squares.index(j):
self.change_mark(index))
column += 1
if number % 3 == 0:
row += 1
column = 0
number += 1
# This is the part where the picture changing happens.
def change_mark(self, i):
"""
Function changes mark of empty button to either X or O depending on the
player in turn. It also checks if the change in mark results in a win.
:param i: The button number, whose mark is being changed
:return: None
"""
if self.__turn_nr % 2 == 1:
self.__player_in_turn = self.__player1
else:
self.__player_in_turn = self.__player2
if self.__player_in_turn == self.__player1:
self.__mark = self.__x
else:
self.__mark = self.__o
self.__squares[i].configure(image=self.__mark, state=DISABLED)
self.__turn_nr += 1
self.check_win(i)
if self.__win is True:
print("this is thought to be a win")
else:
print("the game thinks this is not a win")
# Checking if the game tied.
if self.__turn_nr == self.__size + 1 and not self.__win:
print("the game thinks it tied.")
def check_win(self, i):
"""
Checks if mark placement leads to a win.
:param i: i is the button location.
:return: None
"""
# checks row
if self.__win == False:
for row in self.__rows:
if i + 1 in row:
self.__win = self.checksameimage(row)
if self.__win == True:
break
# checks column
if self.__win == False:
for column in self.__columns:
if i + 1 in column:
self.__win = self.checksameimage(column)
if self.__win == True:
break
# if i is in a diagonal, checks one/both diagonals
if self.__win == False:
for diag in self.__diagonals:
if i + 1 in diag:
self.__win = self.checksameimage(diag)
if self.__win == True:
break
return self.__win
# checking if all the images are same
# This is likely where the issue is. Either this part or checkEqual.
def checksameimage(self, lst):
images = []
for nr in lst:
try:
images.append(self.__squares[nr].cget("image"))
except IndexError:
pass
return self.checkEqual(images)
def checkEqual(self, lst):
"""
Function checks if all elements in a list are equal. Used for checking
if the dice throws are the same.
:param lst: The list the check is performed on
:return: True/False, True if all elements are equal.
"""
if all(x == lst[0] for x in lst):
return True
else:
return False
def create_win_check_lists(self):
"""
Creates lists whose elements are lists of the locations of each spot
of the game board that belongs to a row/column/diagonal
:return:
"""
self.__rows = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
self.__rows[i].append(i + 1)
for k in range(1, self.__grid_size):
self.__rows[i].append(i + 1 + self.__grid_size * k)
self.__columns = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
for j in range(1, self.__grid_size + 1):
self.__columns[i].append(i * self.__grid_size + j)
self.getDiagonals(self.__columns)
def getDiagonals(self, lst):
self.__diagonals = [[], []]
self.__diagonals[0] = [lst[i][i] for i in range(len(lst))]
self.__diagonals[1] = [lst[i][len(lst) - i - 1] for i in
range(len(lst))]
def start(self):
# Function starts the first window of the game.
self.main_game()
def main():
ui = XOGame()
ui.start()
main()
The images used in the code are 125x125. Here is a link that works for 24h: https://picresize.com/b5df006025f0d8
your problem is unquestionably with indices. We can see what index each square corresponds to by changing the image to be text corresponding to the index:
Try changing this loop in build_board:
for i in range(self.__size):
self.__squares[i] = (Button(window, image=self.__empty_square))
To instead show the index it corresponds to:
for i in range(self.__size):
self.__squares[i] = (Button(window, text=str(i)))
Then print out lst passed to checksameimage and you will see that the indices you are checking are all one higher than you intended.
So i wrote this code and it passes the first test case, and fails all the rest. However, I can't seem to find an input that breaks it. Maybe it's because I've been staring at the code too long, but i would appreciate any help.
The algorithm uses two priority queues for the smallest and largest halves of the current list. Here's the code:
#!/bin/python
import heapq
def fix(minset, maxset):
if len(maxset) > len(minset):
item = heapq.heappop(maxset)
heapq.heappush(minset, -item)
elif len(minset) > (len(maxset) + 1):
item = heapq.heappop(minset)
heapq.heappush(maxset, -item)
N = int(raw_input())
s = []
x = []
for i in range(0, N):
tmp = raw_input()
a, b = [xx for xx in tmp.split(' ')]
s.append(a)
x.append(int(b))
minset = []
maxset = []
for i in range(0, N):
wrong = False
if s[i] == "a":
if len(minset) == 0:
heapq.heappush(minset,-x[i])
else:
if x[i] > minset[0]:
heapq.heappush(maxset, x[i])
else:
heapq.heappush(minset, -x[i])
fix(minset, maxset)
elif s[i] == "r":
if -x[i] in minset:
minset.remove(-x[i])
heapq.heapify(minset)
elif x[i] in maxset:
maxset.remove(x[i])
heapq.heapify(maxset)
else:
wrong = True
fix(minset, maxset)
if len(minset) == 0 and len(maxset) == 0:
wrong = True
if wrong == False:
#Calculate median
if len(minset) > len(maxset):
item = - minset[0]
print int(item)
else:
item = ((-float(minset[0])) + float(maxset[0])) / 2
if item.is_integer():
print int(item)
continue
out = str(item)
out.rstrip('0')
print out
else:
print "Wrong!"
Your original was not so legible, so first I made it object-oriented:
MedianHeapq supports methods rebalance(), add(), remove(), size(), median(). We seriously want to hide the members minset,maxset from the client code, for all sorts of sensible reasons: prevent client from swapping them, modifying them etc. If client needs to see them you just write an accessor.
We also added a __str__() method which we will use to debug visually and make your life easier.
Also added legibility changes to avoid the indexing with [i] everywhere, rename s,x arrays to op,val, add prompts on the raw_input(), reject invalid ops at the input stage.
Your actual computation of the median confuses me (when do you want float and when integer? the rstrip('0') is a bit wack), so I rewrote it, change that if you want something else.
A discussion of the algorithm is here.
Now it is legible and self-contained. Also makes it testable.
You might be making sign errors in your code, I don't know, I'll look at that later.
Next we will want to automate it by writing some PyUnit testcases. doctest is also a possibility. TBC.
Ok I think I see a bug in the sloppiness about locating the median. Remember the minset and maxset can have a size mismatch of +/-1. So take more care about precisely where the median is located.
#!/bin/python
import heapq
class MedianHeapq(object):
def __init__(self):
self.minset = []
self.maxset = []
def rebalance(self):
size_imbalance = len(self.maxset) - len(self.minset)
if len(self.maxset) > len(self.minset):
#if size_imbalance > 0:
item = heapq.heappop(self.maxset)
heapq.heappush(self.minset, -item)
#elif size_imbalance < -1:
elif len(self.minset) > (len(self.maxset) + 1):
item = heapq.heappop(self.minset)
heapq.heappush(self.maxset, -item)
def add(self, value, verbose=False):
if len(self.minset) == 0:
heapq.heappush(self.minset,-value)
else:
if value > self.minset[0]:
heapq.heappush(self.maxset, value)
else:
heapq.heappush(self.minset, -value)
self.rebalance()
if verbose: print self.__str__()
return False
def remove(self,value,verbose=False):
wrong = False
if -value in self.minset:
minset.remove(-value)
heapq.heapify(self.minset)
elif value in maxset:
maxset.remove(value)
heapq.heapify(self.maxset)
else:
wrong = True
self.rebalance()
if verbose: print self.__str__()
return wrong
def size(self):
return len(self.minset)+len(self.maxset)
def median(self):
if len(self.minset) > len(self.maxset):
item = - self.minset[0]
return int(item)
else:
item = (-self.minset[0] + self.maxset[0]) / 2.0
# Can't understand the intent of your code here: int, string or float?
if item.is_integer():
return int(item)
# continue # intent???
else:
return item
# The intent of this vv seems to be round floats and return '%.1f' % item ??
#out = str(item)
#out.rstrip('0') # why can't you just int()? or // operator?
#return out
def __str__(self):
return 'Median: %s Minset:%s Maxset:%s' % (self.median(), self.minset,self.maxset)
# Read size and elements from stdin
N = int(raw_input('Size of heap? '))
op = []
val = []
while(len(val)<N):
tmp = raw_input('a/r value : ')
op_, val_ = tmp.split(' ')
if op_ not in ['a','r']: # reject invalid ops
print 'First argument (operation) must be a:Add or r:Remove! '
continue
op.append(op_)
val.append(int(val_))
mhq = MedianHeapq()
for op_,val_ in zip(op,val): # use zip to avoid indexing with [i] everywhere
wrong = False
if op_ == 'a':
wrong = mhq.add(val_)
elif op_ == 'r':
wrong = mhq.remove(val_)
assert (mhq.size()>0), 'Heap has zero size!'
assert (not wrong), 'Heap structure is wrong!'
if not wrong:
print mhq.__str__()