123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- '''
- * This file is part of the Chinchon (https://notabug.org/alkeon/chinchon.
- * Copyright (c) 2020 Alejandro "alkeon" Castilla.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- '''
- from card import Card
- from copy import deepcopy
- def to_number(card):
- return card.get_number()
- class Hand:
- def __init__(self, provided_list = None): #Default values are static
- if provided_list is None: provided_list = list()
- self.cards = provided_list
-
- def size(self):
- return len(self.cards)
- def set_cards(self, provided_list):
- self.cards = provided_list
- def sort(self):
- self.cards.sort(key = to_number)
- '''
- Calculate points of hand.
- Because of the size of the hand (7), as a maximum there is some limits:
- - Two three of a kind (or one three of a kind and four of a kind)
- - Two straights
- - One straight and two three (or four) of a kind
- First it checks all options for every possibility.
- I couldn't make it better so I decided to check it with three greedy algorithm.
- One that checks three (or four) of a kind
- Other that checks straights
- Other that checks both
- Choice with more points is saved.
- Gets all connected cards with every option and later gets not connected cards
- for best choice, and these points are returned.
- '''
- def calculate_points(self):
- min_points = 70
- position = 0
- straight = list()
- three_of_a_kind = list()
- is_chinchon = False
- three_of_a_kind_options = list()
- straight_options = list()
- sol = list()
- # Get all options from combinations
- while(position < len(self.cards)):
- three_of_a_kind_cards = self.detect_three_and_four_of_a_kind()
- if(len(three_of_a_kind_cards) > 2 and three_of_a_kind_cards not in three_of_a_kind_options):
- three_of_a_kind_options.append(three_of_a_kind_cards)
- #Insert all possible three of a kind from a four of a kind
- #This allows three of a kind when four aren't possible
- if(len(three_of_a_kind_cards) == 4):
- i = 0
- while(i < 4):
- four_to_three_of_a_kind = deepcopy(three_of_a_kind_cards)
- four_to_three_of_a_kind.pop(i)
- if(four_to_three_of_a_kind not in three_of_a_kind_options):
- three_of_a_kind_options.append(four_to_three_of_a_kind)
- i += 1
- not_straight_cards, chinchon = self.get_straight(position)
- if(len(not_straight_cards) > 2 and not_straight_cards not in straight_options):
- straight_options.append(not_straight_cards)
- position += 1
- if(chinchon):
- is_chinchon = True
- # Check three of a kind and four of a kind
- i = 0
- points = 0
- while(i < len(three_of_a_kind_options)):
- possible_solution = list()
- temp = 0
- if(i < len(three_of_a_kind_options) and self.can_be_added(possible_solution, three_of_a_kind_options[i])):
- possible_solution += three_of_a_kind_options[i]
- if(i + 1 < len(three_of_a_kind_options)):
- if(self.can_be_added(possible_solution, three_of_a_kind_options[i + 1])):
- possible_solution += three_of_a_kind_options[i + 1]
- if(i + 2 < len(three_of_a_kind_options)):
- if(self.can_be_added(possible_solution, three_of_a_kind_options[i + 2])):
- possible_solution += three_of_a_kind_options[i + 2]
- temp = self.get_points(possible_solution)
- if(temp > points):
- sol = deepcopy(possible_solution)
- points = temp
- i += 1
- # Check straight options
- i = 0
- while(i < len(straight_options)):
-
- possible_solution = list()
- if(i < len(straight_options) and self.can_be_added(possible_solution, straight_options[i])):
- possible_solution += straight_options[i]
- if(i + 1 < len(straight_options)):
- if(self.can_be_added(possible_solution, straight_options[i + 1])):
- possible_solution += straight_options[i + 1]
- if(i + 2 < len(straight_options)):
- if(self.can_be_added(possible_solution, straight_options[i + 2])):
- possible_solution += straight_options[i + 2]
- temp = self.get_points(possible_solution)
- if(temp > points):
- sol = deepcopy(possible_solution)
- points = temp
- i += 1
- # Check straight options and three and four of a kind
- i = 0
- while(i < len(straight_options)):
- e = 0
- while(e < len(three_of_a_kind_options)):
-
- possible_solution = list()
- possible_solution += straight_options[i]
- if(e < len(three_of_a_kind_options) and self.can_be_added(possible_solution, three_of_a_kind_options[e])):
- possible_solution += three_of_a_kind_options[e]
- if(e + 1 < len(three_of_a_kind_options)):
- if(self.can_be_added(possible_solution, three_of_a_kind_options[e + 1])):
- possible_solution += three_of_a_kind_options[e + 1]
- if(e + 2 < len(three_of_a_kind_options)):
- if(self.can_be_added(possible_solution, three_of_a_kind_options[e + 2])):
- possible_solution += three_of_a_kind_options[e + 2]
- temp = self.get_points(possible_solution)
- if(temp > points):
- sol = deepcopy(possible_solution)
- points = temp
- e += 1
- i += 1
- not_connected_cards = self.get_not_connected_cards(sol)
- min_points = self.get_points(not_connected_cards)
- if(min_points == 0 and is_chinchon == True):
- min_points = -100
- elif(min_points == 0):
- min_points = -10
- return min_points
- '''
- From connected cards, checks hand for not connected cards
- '''
- def get_not_connected_cards(self, connected):
- i = 0
- not_connected_cards = list()
- while(i < len(self.cards)):
- e = 0
- found = False
- while(e < len(connected)):
- if(self.cards[i].get_number() == connected[e].get_number()
- and self.cards[i].get_suit() == connected[e].get_suit()):
- found = True
- e += 1
- if(not found):
- not_connected_cards.append(self.cards[i])
- i += 1
- return not_connected_cards
- '''
- Checks if option can be added to solution
- '''
- def can_be_added(self, sol, cards_to_be_append):
- i = 0
- added = True
- while(i < len(self.cards)):
- if(self.cards[i] in sol and self.cards[i] in cards_to_be_append):
- added = False
- i += 1
- return added
- '''
- Takes card from position and check if the rest of the cards can be used for a straight
- also sends chinchon true if hand is a full straight
- '''
- def get_straight(self, position):
- possible_straight = list()
- first_card = self.cards[position]
- possible_straight = self.get_cards_same_suit(first_card.get_suit())
- chinchon = (len(possible_straight) == 7)
- possible_straight.sort(key = to_number)
-
- straight_cards = self.check_straight(possible_straight)
- chinchon = chinchon and (len(straight_cards) == 7)
- return straight_cards, chinchon
- '''
- Verify if cards is a valid straight
- '''
- def check_straight(self, possible_straight):
- position = 0
- return_straighted_cards = list()
- continuous_straight = 0
- not_straight_cards = list()
- straighted_cards = list()
- while(position < len(possible_straight)):
- if(position + 1 < len(possible_straight)):
- if(to_number(possible_straight[position]) !=
- to_number(possible_straight[position + 1]) - 1):
- if(continuous_straight < 2):
- continuous_straight = 0
- if(to_number(possible_straight[position - 1]) + 1 !=
- to_number(possible_straight[position])):
- not_straight_cards.insert(0, possible_straight[position])
- else:
- straighted_cards.insert(0, possible_straight[position])
- else:
- straighted_cards.insert(0, possible_straight[position])
- continuous_straight += 1
- else:
- if(to_number(possible_straight[position - 1]) + 1 !=
- to_number(possible_straight[position])):
- not_straight_cards.insert(0, possible_straight[position])
-
- else:
- straighted_cards.insert(0, possible_straight[position])
- position += 1
- if(continuous_straight < 2):
- return_straighted_cards = list()
- else:
- position = 0
- while(position < len(self.cards)):
- if(self.cards[position] in straighted_cards and
- self.cards[position] not in return_straighted_cards):
- return_straighted_cards.insert(0, self.cards[position])
- position += 1
-
- return return_straighted_cards
- '''
- Checks every card from hand for a three (or four) of a kind
- '''
- def detect_three_and_four_of_a_kind(self):
- position = 0
- return_three_of_a_kind_cards = list()
- three_of_a_kind_cards = list()
- while(position < len(self.cards)):
- provided_card = self.cards[position]
- new_position = 0
- possible_three_of_a_kind_cards = list()
- while(new_position < len(self.cards)):
- card = self.cards[new_position]
- if(to_number(provided_card) == to_number(card)):
- possible_three_of_a_kind_cards.insert(0, card)
-
- new_position += 1
- if(len(possible_three_of_a_kind_cards) > 2):
- three_of_a_kind_cards += possible_three_of_a_kind_cards
- position += 1
- position = 0
- # Delete repeated cards
- while(position < len(self.cards)):
- if(self.cards[position] in three_of_a_kind_cards):
- return_three_of_a_kind_cards.insert(0, self.cards[position])
- position += 1
-
- return return_three_of_a_kind_cards
-
- def get_cards_same_suit(self, suit):
- position = 0
- same_suit_cards = list()
- while(position < len(self.cards)):
- card = self.cards[position]
- if(suit == card.get_suit()):
- same_suit_cards.insert(0, card)
- position += 1
- return same_suit_cards
- def insert(self, position, object):
- self.cards.insert(position, object)
- def pop(self, position):
- self.cards.pop(position)
- def get_cards(self):
- return self.cards.copy()
- '''
- Sum of all points from cards
- Every card adds its own number unless 11 and 12, those add 10 points.
- '''
- def get_points(self, cards):
- position = 0
- points = 0
- set_seen = set()
- while(position < len(cards)):
- if(cards[position] not in set_seen):
- first_number = to_number(cards[position])
- if(first_number < 11):
- points += first_number
- else:
- points += 10
- set_seen.add(cards[position])
- position += 1
- return points
- def get(self, position):
- return self.cards[position]
- def __str__(self):
- i = 0
- string_result = str()
- while(i < self.size()):
- string_result += str(i) + ".- " + str(self.cards[i]) + " "
- i += 1
- return string_result
|