217 lines
7.5 KiB
Python
217 lines
7.5 KiB
Python
# Title: Project 3 - Group scoring
|
|
# Author: Rory Healy
|
|
# Date created - 17th May 2019
|
|
# Date modified - 30th May 2019
|
|
|
|
def is_n_of_a_kind(cards):
|
|
'''Takes a list of cards and returns a Boolean value based on if those
|
|
cards are said to be "N-of-a-kind".'''
|
|
|
|
# Analyse the numbers of the cards to determine validity.
|
|
numbers_of_cards = []
|
|
for i in range(len(cards)):
|
|
numbers_of_cards.append(cards[i][:-1])
|
|
if numbers_are_same(numbers_of_cards):
|
|
return True
|
|
return False
|
|
|
|
def numbers_are_same(numbers):
|
|
'''Takes a list of strings, "numbers", and returns True if all the numbers
|
|
in the list of strings are the same, and False otherwise.'''
|
|
original_number = numbers[0]
|
|
for i in range(len(numbers)):
|
|
if numbers[i] != original_number:
|
|
return False
|
|
return True
|
|
|
|
def is_run(cards):
|
|
'''Determines if a set of cards are said to be a "valid run" and returns a
|
|
corresponding Boolean value.'''
|
|
|
|
# Extracts the suits of all the cards in the list.
|
|
suits_of_cards = []
|
|
colour_of_cards = ''
|
|
red_cards = 'DH'
|
|
for i in range(len(cards)):
|
|
suits_of_cards.append(cards[i][-1])
|
|
for card in suits_of_cards:
|
|
if card in red_cards:
|
|
colour_of_cards += 'R'
|
|
else:
|
|
colour_of_cards += 'B'
|
|
|
|
# Extracts the numbers of the cards in the list.
|
|
numbers_of_cards = []
|
|
for i in range(len(cards)):
|
|
numbers_of_cards.append(cards[i][:-1])
|
|
|
|
# Return True/False based on the validity of the suits and numbers.
|
|
if suits_are_alternating(colour_of_cards) and \
|
|
numbers_are_monotonic(numbers_of_cards):
|
|
return True
|
|
return False
|
|
|
|
def suits_are_alternating(suits):
|
|
'''Takes a string "suits" and returns True if the suits of the string are
|
|
alternating, and False otherwise.'''
|
|
for i in range(1, len(suits)):
|
|
if suits[i] == suits[i - 1]:
|
|
return False
|
|
return True
|
|
|
|
def numbers_are_monotonic(numbers):
|
|
'''Takes a list of strings of numbers and returns True if the numbers in
|
|
the list are monotonic (i.e. strictly increasing or strictly decreasing),
|
|
where aces can represent any number.'''
|
|
|
|
# Replaces Aces with their numerical value, based on the values of the
|
|
# cards adjacent to the Ace.
|
|
for i in range(len(numbers)):
|
|
if numbers[i] == 'A':
|
|
if (i == 0) or (i == (len(numbers) - 1)):
|
|
return False
|
|
|
|
# The value the a is actually taking depends on whether the cards
|
|
# are increasing or decreasing in value, so this step is necessary
|
|
# for dealing with Aces.
|
|
if int(numbers[0]) < int(numbers[-1]):
|
|
a_actually_is = int(numbers[i - 1]) + 1
|
|
elif int(numbers[0]) > int(numbers[-1]):
|
|
a_actually_is = int(numbers[i + 1]) + 1
|
|
elif int(numbers[0]) == int(numbers[-1]):
|
|
return False
|
|
|
|
# Validating that the ace represents the correct number.
|
|
a_should_represent = (int(numbers[i + 1]) + int(numbers[i - 1])) \
|
|
/2
|
|
if a_should_represent != a_actually_is:
|
|
return False
|
|
else:
|
|
numbers.insert(i, str(a_actually_is))
|
|
numbers.remove('A')
|
|
|
|
# Checks if the numbers are consecutive.
|
|
for i in range(len(numbers)):
|
|
if int(numbers[0]) == int(numbers[-1]):
|
|
return False
|
|
|
|
# For runs that are ascending.
|
|
elif int(numbers[0]) < int(numbers[-1]):
|
|
if i == 0:
|
|
if int(numbers[0]) != (int(numbers[1]) - 1):
|
|
return False
|
|
|
|
elif i == (len(numbers) - 1):
|
|
if int(numbers[i]) != (int(numbers[i - 1]) + 1):
|
|
return False
|
|
|
|
elif int(numbers[i]) != (int(numbers[i - 1]) + 1):
|
|
return False
|
|
|
|
# For runs that are descending.
|
|
elif int(numbers[0]) > int(numbers[-1]):
|
|
if i == 0:
|
|
if int(numbers[0]) != (int(numbers[1]) + 1):
|
|
return False
|
|
|
|
elif i == (len(numbers) - 1):
|
|
if int(numbers[i]) != (int(numbers[i - 1]) - 1):
|
|
return False
|
|
|
|
elif int(numbers[i]) != (int(numbers[i - 1]) - 1):
|
|
return False
|
|
|
|
# If the run passes all of these cases, then it must be a valid run.
|
|
return True
|
|
|
|
def convert_0jqk(cards):
|
|
'''Takes a list of cards and converts special numbers (0, J, Q, K) to
|
|
their respective values (10, 11, 12, 13) respectively.'''
|
|
|
|
# Replaces letters with numbers.
|
|
for i in range(len(cards)):
|
|
# Replaces Kings with their numerical value - 13.
|
|
if cards[i][0] == 'K':
|
|
suit = cards[i][1]
|
|
cards[i] = '13' + suit
|
|
|
|
# Replaces Queens with their numerical value - 12.
|
|
elif cards[i][0] == 'Q':
|
|
suit = cards[i][1]
|
|
cards[i] = '12' + suit
|
|
|
|
# Replaces Jacks with their numerical value - 11.
|
|
elif cards[i][0] == 'J':
|
|
suit = cards[i][1]
|
|
cards[i] = '11' + suit
|
|
|
|
# Replaces '0', representing 10, with its numerical value.
|
|
elif cards[i][0] == '0':
|
|
suit = cards[i][1]
|
|
cards[i] = '10' + suit
|
|
return cards
|
|
|
|
def factorial(num):
|
|
'''Calculates the factorial of the number and returns it.'''
|
|
if num == 1:
|
|
return 1
|
|
else:
|
|
return num * factorial(num - 1)
|
|
|
|
def order_a_list(cards):
|
|
'''Orders a list of cards based their numerical value with Aces last.'''
|
|
ordered_list = []
|
|
numbers_of_cards = []
|
|
aces = []
|
|
for i in range(len(cards)):
|
|
if cards[i][:-1] == 'A':
|
|
aces.append('A')
|
|
else:
|
|
numbers_of_cards.append(cards[i][:-1])
|
|
|
|
numbers_of_cards.sort(key=int)
|
|
numbers_of_cards += aces
|
|
for number in numbers_of_cards:
|
|
for card in cards:
|
|
if number == card[:-1]:
|
|
if card in ordered_list:
|
|
continue
|
|
ordered_list.append(number + card[-1])
|
|
return ordered_list
|
|
|
|
def comp10001go_score_group(cards):
|
|
'''Takes a list of cards (each a 2-element string, where the first letter
|
|
is the card value and the second letter is the card suit), and returns the
|
|
calculated score of that set of cards as an integer.'''
|
|
|
|
score = 0
|
|
cards = convert_0jqk(cards)
|
|
cards = order_a_list(cards)
|
|
|
|
# Given a list, identifies an n-of-a-kind case or a run.
|
|
if len(cards) > 1:
|
|
for i in range(2, len(cards) + 1):
|
|
# Handles the case where all of the cards are n-of-a-kind.
|
|
if is_n_of_a_kind(cards):
|
|
score += int(cards[0][:-1]) * factorial(len(cards))
|
|
return score
|
|
|
|
# Handles the case where only some of the cards are n-of-a-kind
|
|
# and the rest aren't.
|
|
elif not is_n_of_a_kind(cards[0:i]):
|
|
score += int(cards[0][:-1]) * factorial(i - 1)
|
|
value = int(cards[0][:-1])
|
|
for j in range(i):
|
|
if int(cards[0][:-1]) == value:
|
|
cards.pop(0)
|
|
|
|
# Any leftover cards have their values taken from the total score.
|
|
if len(cards) > 0:
|
|
for card in cards:
|
|
value = card[:-1]
|
|
if value == 'A':
|
|
value = 20
|
|
else:
|
|
value = int(value)
|
|
score -= value
|
|
return score
|