player.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. '''
  2. * This file is part of the Chinchon (https://notabug.org/alkeon/chinchon.
  3. * Copyright (c) 2020 Alejandro "alkeon" Castilla.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 3.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. '''
  17. from hand import Hand
  18. from copy import deepcopy
  19. debug = False
  20. '''
  21. Checks if string can be converted to int
  22. '''
  23. def possible_int(string):
  24. try:
  25. int(string)
  26. return True
  27. except ValueError:
  28. return False
  29. class Player:
  30. def __init__(self, hand, mode, hard_mode):
  31. self.mode = mode
  32. self.hand = hand
  33. self.possible_end = 0
  34. self.hard_mode = hard_mode
  35. self.deck_cards_avoided = 0
  36. '''
  37. Easy mode AI
  38. Takes risk when choose card from deck.
  39. Try best movement but never tries a chinchon or a full hand unless luck give it
  40. '''
  41. def decide_next_move_easy(self, card):
  42. initial_points = self.hand.calculate_points()
  43. choice_and_position = list()
  44. if(initial_points >= 4):
  45. best_move_list = self.best_move(card, initial_points)
  46. if(best_move_list[1] < initial_points):
  47. choice_and_position.append(1)
  48. choice_and_position += best_move_list
  49. else:
  50. choice_and_position.append(0)
  51. choice_and_position.append(best_move_list[0])
  52. choice_and_position.append(best_move_list[1] + 10)
  53. else:
  54. choice_and_position.append(2)
  55. choice_and_position.append(0)
  56. choice_and_position.append(initial_points)
  57. return choice_and_position
  58. '''
  59. Hard mode AI
  60. Knows first card from deck
  61. Try best movement but never tries a chinchon or a full hand unless luck give it
  62. '''
  63. def decide_next_move_hard(self, card, deck_card):
  64. initial_points = self.hand.calculate_points()
  65. choice_and_position = list() #result
  66. if(initial_points >= 4):
  67. best_move_list = self.best_move(card, initial_points)
  68. best_move_list_deck_card = self.best_move(deck_card, initial_points)
  69. if(best_move_list[1] < best_move_list_deck_card[1] and
  70. best_move_list[1] < initial_points):
  71. choice_and_position.append(1)
  72. choice_and_position += best_move_list
  73. elif(best_move_list[1] > best_move_list_deck_card[1] and
  74. best_move_list_deck_card[1] < initial_points):
  75. choice_and_position.append(0)
  76. choice_and_position += best_move_list_deck_card
  77. elif(self.deck_cards_avoided < 10):
  78. choice_and_position.append(1)
  79. choice_and_position += best_move_list
  80. self.deck_cards_avoided += 1
  81. else:
  82. choice_and_position.append(0)
  83. choice_and_position += best_move_list_deck_card
  84. self.deck_cards_avoided = 0
  85. elif(self.possible_end <= 5):
  86. best_move_list = self.best_move(card, initial_points)
  87. choice_and_position.append(1)
  88. choice_and_position += best_move_list
  89. self.possible_end += 1
  90. else:
  91. choice_and_position.append(2)
  92. choice_and_position.append(0)
  93. choice_and_position.append(initial_points)
  94. return choice_and_position
  95. '''
  96. Greedy algorithm that checks all movements points
  97. '''
  98. def best_move(self, card, initial_points):
  99. temporal_hand = deepcopy(self.hand)
  100. temporal_hand.insert(0, card)
  101. position = 0
  102. min_points_position = 0
  103. min_points = initial_points
  104. while(position < len(temporal_hand.get_cards())):
  105. possible_hand = deepcopy(temporal_hand)
  106. possible_hand.pop(position)
  107. points = possible_hand.calculate_points()
  108. if(points < min_points):
  109. min_points_position = position
  110. min_points = points
  111. position += 1
  112. return_list = list()
  113. return_list.append(min_points_position)
  114. return_list.append(min_points)
  115. return return_list
  116. '''
  117. After AI choose best option, this code executes that option
  118. '''
  119. def opponent(self, deck, reversed_deck):
  120. choice_and_position = list()
  121. if(self.hard_mode == 1):
  122. choice_and_position = self.decide_next_move_hard(reversed_deck.get(0), deck.get(0))
  123. else:
  124. choice_and_position = self.decide_next_move_easy(reversed_deck.get(0))
  125. result = 0
  126. if(debug):
  127. print('choice')
  128. print(choice_and_position[0])
  129. print('position')
  130. print(choice_and_position[1])
  131. print('points')
  132. print(choice_and_position[2])
  133. if(choice_and_position[0] == 0):
  134. self.hand.insert(0, deck.get(0))
  135. deck.pop(0)
  136. reversed_deck.insert(0, self.hand.get(choice_and_position[1]))
  137. self.hand.pop(choice_and_position[1])
  138. elif(choice_and_position[0] == 1):
  139. self.hand.insert(0, reversed_deck.get(0))
  140. reversed_deck.pop(0)
  141. reversed_deck.insert(0, self.hand.get(choice_and_position[1]))
  142. self.hand.pop(choice_and_position[1])
  143. else:
  144. result = 2
  145. return result
  146. '''
  147. UI for choosing an option
  148. '''
  149. def choose_option(self, deck, reversed_deck):
  150. if(self.mode == 2):
  151. option_s = input('0 top of deck, 1 Reversed card , 2 stop ')
  152. choice = int()
  153. if(possible_int(option_s)):
  154. choice = int(option_s)
  155. else:
  156. choice = 0
  157. if(choice != 2):
  158. if(choice == 0):
  159. self.hand.insert(0, deck.get(0))
  160. deck.pop(0)
  161. else:
  162. self.hand.insert(0, reversed_deck.get(0))
  163. reversed_deck.pop(0)
  164. print(self.hand)
  165. card_position = int()
  166. card_position_s = input('Choose card by position ')
  167. if(possible_int(card_position_s)):
  168. card_position = int(card_position_s)
  169. else:
  170. card_position = 0
  171. reversed_deck.insert(0, self.hand.get(card_position))
  172. self.hand.pop(card_position)
  173. else:
  174. if(self.hand.calculate_points() > 3):
  175. print('You must have less than four points in your hand')
  176. choice = self.choose_option( reversed_deck, deck)
  177. return choice
  178. else:
  179. return self.opponent(deck, reversed_deck)
  180. def return_hand(self):
  181. return self.hand
  182. def set_hand(self,hand):
  183. self.hand = deepcopy(hand)
  184. def get_mode(self):
  185. return self.mode
  186. def get_hard_mode(self):
  187. return self.hard_mode
  188. def __str__(self):
  189. return str(self.hand)