patternpythonModerate
Magic Trick (Google Code Jam 2014 QR Problem A) in Python
Viewed 0 times
problemtrickgooglemagicpythoncode2014jam
Problem
I'm learning Python by solving previous GCJ problems. This problem is quite simple to solve, but I'd like my code to be reviewed for advance (more Pythonic expression and more efficient algorithm).
The magician starts by arranging 16 cards in a square grid: 4 rows of cards, with 4 cards in each row. Each card has a different number from 1 to 16 written on the side that is showing. Next, the magician asks a volunteer to choose a card, and to tell him which row that card is in.
Finally, the magician arranges the 16 cards in a square grid again, possibly in a different order. Once again, he asks the volunteer which row her card is in. With only the answers to these two questions, the magician then correctly determines which card the volunteer chose. Amazing, right?
You decide to write a program to help you understand the magician's technique. The program will be given the two arrangements of the cards, and the volunteer's answers to the two questions: the row number of the selected card in the first arrangement, and the row number of the selected card in the second arrangement. The rows are numbered 1 to 4 from top to bottom.
Your program should determine which card the volunteer chose; or if there is more than one card the volunteer might have chosen (the magician did a bad job); or if there's no card consistent with the volunteer's answers (the volunteer cheated).
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing an integer: the answer to the first question. The next 4 lines represent the first arrangement of the cards: each contains 4 integers, separated by a single space. The next line contains the answer to the second question, and the following four lines contain the second arrangement in the same format.
Output
For each test case, output one line containing "Case #x: y", where x is the test case number (starting from 1).
If the
The magician starts by arranging 16 cards in a square grid: 4 rows of cards, with 4 cards in each row. Each card has a different number from 1 to 16 written on the side that is showing. Next, the magician asks a volunteer to choose a card, and to tell him which row that card is in.
Finally, the magician arranges the 16 cards in a square grid again, possibly in a different order. Once again, he asks the volunteer which row her card is in. With only the answers to these two questions, the magician then correctly determines which card the volunteer chose. Amazing, right?
You decide to write a program to help you understand the magician's technique. The program will be given the two arrangements of the cards, and the volunteer's answers to the two questions: the row number of the selected card in the first arrangement, and the row number of the selected card in the second arrangement. The rows are numbered 1 to 4 from top to bottom.
Your program should determine which card the volunteer chose; or if there is more than one card the volunteer might have chosen (the magician did a bad job); or if there's no card consistent with the volunteer's answers (the volunteer cheated).
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing an integer: the answer to the first question. The next 4 lines represent the first arrangement of the cards: each contains 4 integers, separated by a single space. The next line contains the answer to the second question, and the following four lines contain the second arrangement in the same format.
Output
For each test case, output one line containing "Case #x: y", where x is the test case number (starting from 1).
If the
Solution
- Naming:
mainis reserved so that's ok, butmain2makes no sense. The name should be a hint about what the function does, I'd go forguess_card.
- Since there's no mention of a file input, I'd say go for standard input. You can always read a file and redirect the input if that's needed. The same goes for standard output.
- You're using both
inputandraw_input, why is that? If you want to do input validation, you should do it properly, trying to parse it and eventually catching exceptions. But if you go down that road, then you should also not assume that the rest of the input is correct. I'd say that for this specific program, you can safely say that the syntax of the input will be fine.
- Comments used like this are pretty much useless, they should tell why things are happening the way they are, not re-describe the code
- Your second function is not modular, it will take all cases and do everything. I think you should make that function guess one of the cases and loop around it instead of inside.
- There's really no need to do anything differently from what the "magician" is doing, no need to import itertools, just keep in mind that user answers are a 1-based index, while arrays are 0-based.
Here's my take on it:
def guess_card(user_rows, card_rows):
possible_answers = []
possible_cards = card_rows[user_rows[0] - 1]
for card in possible_cards:
if card in card_rows[user_rows[1] + 3]:
possible_answers.append(card)
if len(possible_answers) > 1:
return 'Bad magician!'
if len(possible_answers) == 0:
return 'Volunteer cheated!'
return possible_answers[0]
def main():
n_test_cases = int(raw_input())
answers = []
while n_test_cases:
n_test_cases -= 1
user_rows = []
card_rows = []
user_rows.append(int(raw_input()))
for i in range(0, 4):
card_rows.append(raw_input().split(' '))
user_rows.append(int(raw_input()))
for i in range(4, 8):
card_rows.append(raw_input().split(' '))
answers.append(guess_card(user_rows, card_rows))
for answer in answers:
print answer
if __name__ == "__main__":
main()If you're wondering about the
if __name__ == "__main__": line, you can have a look here.Code Snippets
def guess_card(user_rows, card_rows):
possible_answers = []
possible_cards = card_rows[user_rows[0] - 1]
for card in possible_cards:
if card in card_rows[user_rows[1] + 3]:
possible_answers.append(card)
if len(possible_answers) > 1:
return 'Bad magician!'
if len(possible_answers) == 0:
return 'Volunteer cheated!'
return possible_answers[0]
def main():
n_test_cases = int(raw_input())
answers = []
while n_test_cases:
n_test_cases -= 1
user_rows = []
card_rows = []
user_rows.append(int(raw_input()))
for i in range(0, 4):
card_rows.append(raw_input().split(' '))
user_rows.append(int(raw_input()))
for i in range(4, 8):
card_rows.append(raw_input().split(' '))
answers.append(guess_card(user_rows, card_rows))
for answer in answers:
print answer
if __name__ == "__main__":
main()Context
StackExchange Code Review Q#154334, answer score: 11
Revisions (0)
No revisions yet.