def drop(self): """ Drop card from hand. (Required API by Agent) This API will implement the algorithm to deside the dropped card. It will be called during game when necessary. Agent is responsible for removing dropped card from hand when make decision. The implemented dropping card algorithm as below: 1. 只有獨張的風牌或中發白 2. 沒有機會形成 Triplet 或 Sequence 的萬/筒/條 (只有單張) 3. 頭尾的先丟. (Ex. 1萬/9萬/1筒/9筒/1條/9條) 4. 下家有丟過的先丟. 5. 最後都沒有滿足, 任意丟一張 萬/筒/條. * Return Dropped card which being removed from hand. """ card = '' # 1. 只有獨張的風牌或中發白就丟. if (not card) and len(self.word_list) == 1: card = self.word_list.pop() self.card_count -= 1 return card else: for c in set(self.word_list): if self.word_list.count(c) == 1: self.word_list.remove(c) self.card_count -= 1 return c if (not card) and len(self.wind_list) == 1: card = self.wind_list.pop() self.card_count -= 1 return card else: for c in set(self.wind_list): if self.wind_list.count(c) == 1: self.wind_list.remove(c) self.card_count -= 1 return c # 2. 沒有機會形成 Triplet 或 Sequence 的萬/筒/條 (只有單張) # 3. 頭尾的先丟. (Ex. 1萬/9萬/1筒/9筒/1條/9條) if (not card) and len(self.tube_list) > 0: for c in set(self.tube_list): #number = int(card[:1]) if self.tube_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.tube_list or GameBoard.NextCard( c) in self.tube_list: continue else: self.tube_list.remove(c) self.card_count -= 1 return c if (not card) and '1筒' in self.tube_list: card = '1筒' self.tube_list.remove(card) self.card_count -= 1 return card elif (not card) and '9筒' in self.tube_list: card = '9筒' self.tube_list.remove(card) self.card_count -= 1 return card if (not card) and len(self.wang_list) > 0: for c in set(self.wang_list): if self.wang_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.wang_list or GameBoard.NextCard( c) in self.wang_list: continue else: self.wang_list.remove(c) self.card_count -= 1 return c if (not card) and '1萬' in self.wang_list: card = '1萬' self.wang_list.remove(card) self.card_count -= 1 return card elif (not card) and '9萬' in self.wang_list: card = '9萬' self.wang_list.remove(card) self.card_count -= 1 return card if (not card) and len(self.bamb_list) > 0: for c in set(self.bamb_list): if self.bamb_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.bamb_list or GameBoard.NextCard( c) in self.bamb_list: continue else: self.bamb_list.remove(c) self.card_count -= 1 return c if (not card) and '1條' in self.bamb_list: card = '1條' self.bamb_list.remove(card) self.card_count -= 1 return card elif (not card) and '9條' in self.bamb_list: card = '9條' self.bamb_list.remove(card) self.card_count -= 1 return card # 4. 下家有丟過的先丟 rightAgt = self.gb.rightOpponent(self) if rightAgt.name in self.gb.drop_record and len( self.gb.drop_record[rightAgt.name]) > 0: dc = self.gb.drop_record[rightAgt.name][-1] ct = GameBoard.CardType(dc) if ct == 1 and dc in self.wang_list: self.wang_list.remove(dc) self.card_count -= 1 return dc elif ct == 2 and dc in self.tube_list: self.tube_list.remove(dc) self.card_count -= 1 return dc elif ct == 3 and dc in self.bamb_list: self.bamb_list.remove(dc) self.card_count -= 1 return dc elif ct == 4 and dc in self.word_list: self.word_list.remove(dc) self.card_count -= 1 return dc elif ct == 5 and dc in self.wind_list: self.wind_list.remove(dc) self.card_count -= 1 return dc # 5. 任意丟一張 萬/筒/條 if (not card) and len(self.tube_list) > 0: card = self.tube_list.pop() self.card_count -= 1 return card if (not card) and len(self.wang_list) > 0: card = self.wang_list.pop() self.card_count -= 1 return card if (not card) and len(self.bamb_list) > 0: card = self.bamb_list.pop() self.card_count -= 1 return card
def pong_or_eat(self, action_flag, ctype, card): if (ctype == 1): c_list = self.wang_list elif (ctype == 2): c_list = self.tube_list elif (ctype == 3): c_list = self.bamb_list elif (ctype == 4): c_list = self.word_list else: c_list = self.wind_list temp_cards = [] if (action_flag == 1): temp_cards.append([card, card]) else: # for eat, we have to find all possible eaten cards n = GameBoard.NextCard(card) p = GameBoard.PrevCard(card) if (int(card[0]) == 1): n = GameBoard.NextCard(card) nn = GameBoard.NextCard(n) temp_cards.append([n, nn]) elif (int(card[0]) == 2): p = GameBoard.PrevCard(card) n = GameBoard.NextCard(card) nn = GameBoard.NextCard(n) if ((p in c_list) and (n in c_list)): temp_cards.append([p, n]) if ((n in c_list) and (nn in c_list)): temp_cards.append([n, nn]) elif (int(card[0]) == 8): p = GameBoard.PrevCard(card) n = GameBoard.NextCard(card) pp = GameBoard.PrevCard(p) if ((p in c_list) and (n in c_list)): temp_cards.append([p, n]) if ((p in c_list) and (pp in c_list)): temp_cards.append([pp, p]) elif (int(card[0]) == 9): p = GameBoard.PrevCard(card) pp = GameBoard.PrevCard(p) if ((p in c_list) and (pp in c_list)): temp_cards.append([pp, p]) else: n = GameBoard.NextCard(card) nn = GameBoard.NextCard(n) p = GameBoard.PrevCard(card) pp = GameBoard.PrevCard(p) if ((p in c_list) and (n in c_list)): temp_cards.append([p, n]) if ((pp in c_list) and (p in c_list)): temp_cards.append([pp, p]) if ((n in c_list) and (nn in c_list)): temp_cards.append([n, nn]) mini = 99 useful = 0 score = 0 result = None for one in temp_cards: for c in one: self.pong_list.append(c) c_list.remove(c) self.pong_list.append(card) m, u, s = self.count_steps() for c in one: self.pong_list.remove(c) c_list.append(c) self.pong_list.remove(card) c_list.sort() if (m > mini): continue if (m == mini) and (u < useful): continue if (m == mini) and (u == useful) and (s <= score): continue result = one mini = m useful = u score = s """ noe we know, which cards to eat is better check: should we eat/pong or not return None: do not eat/pong """ if (mini > self.current_best_state[0]): # print "current_best_state: {0}".format(self.current_best_state) # print "mini: {0}, useful: {1}, score: {2}".format(mini, useful, score) return None if (mini == self.current_best_state[0]) and ( useful < self.current_best_state[1]): # print "current_best_state: {0}".format(self.current_best_state) # print "mini: {0}, useful: {1}, score: {2}".format(mini, useful, score) return None for c in result: c_list.remove(c) self.pong_list.append(c) self.card_count -= 1 self.pong_list.append(card) self.pong_list.sort() return self.drop()
def find_all_combination(self, ctype, cards, comb_str, combination): if len(cards) == 0: combination.append(comb_str) return combination card = cards[0] ctype = GameBoard.CardType(card) if (ctype == 1) or (ctype == 2) or (ctype == 3): count = cards.count(card) if count == 3: copy = list(cards) copy.remove(card) copy.remove(card) copy.remove(card) new = "{0} {0} {0}\t".format(card) self.find_all_combination(ctype, copy, comb_str + new, combination) if count == 2: copy = list(cards) copy.remove(card) copy.remove(card) new = "{0} {0}\t".format(card) self.find_all_combination(ctype, copy, comb_str + new, combination) n = GameBoard.NextCard(card) if n != None: nn = GameBoard.NextCard(n) else: nn = "" if (n in cards) and (nn in cards): copy = list(cards) copy.remove(card) copy.remove(n) copy.remove(nn) new = "{0} {1} {2}\t".format(card, n, nn) self.find_all_combination(ctype, copy, comb_str + new, combination) if n in cards: copy = list(cards) copy.remove(card) copy.remove(n) new = "{0} {1}\t".format(card, n) self.find_all_combination(ctype, copy, comb_str + new, combination) if nn in cards: copy = list(cards) copy.remove(card) copy.remove(nn) new = "{0} {1}\t".format(card, nn) self.find_all_combination(ctype, copy, comb_str + new, combination) cards.remove(card) new = "{0}\t".format(card) self.find_all_combination(ctype, cards, comb_str + new, combination) if (ctype == 4) or (ctype == 5): count = cards.count(card) if count == 3: copy = list(cards) copy.remove(card) copy.remove(card) copy.remove(card) new = "{0} {0} {0}\t".format(card) self.find_all_combination(ctype, copy, comb_str + new, combination) if count == 2: copy = list(cards) copy.remove(card) copy.remove(card) new = "{0} {0}\t".format(card) self.find_all_combination(ctype, copy, comb_str + new, combination) cards.remove(card) new = "{0}\t".format(card) self.find_all_combination(ctype, cards, comb_str + new, combination) return combination
def way_to_prewin(self, one): """ kind = [triple, pair, neighbor, single] useful: how many cards can we get one more triple score: a metric to evaluate how good triple = 3, pair/consecutive neighbor = 2, non-consecutive = 1, single = 0 """ kind = [0, 0, 0, 0] useful = [] score = 0 for part in one.split("\t"): #print "part: {0}".format(part) tmp = part.split() length = len(tmp) if (length == 3): # triple kind[0] += 1 score += 3 elif (length == 1): # single kind[3] += 1 elif (tmp[0] == tmp[1]): # pair kind[1] += 1 useful.append("{0}".format(tmp[0])) score += 2 else: kind[2] += 1 n = GameBoard.NextCard(tmp[0]) p = GameBoard.PrevCard(tmp[0]) nn = GameBoard.NextCard(tmp[1]) if (n == tmp[1]): # consecutive neighbor score += 2 if (p != None): useful.append(p) if (nn != None): useful.append(nn) else: useful.append(n) score += 1 #print "kind: {0}".format(kind) """ how many cards can we probably get """ useful_amount = 0 for card in set(useful): ctype = GameBoard.CardType(card) if (ctype == 1): a = self.wang_list.count(card) elif (ctype == 2): a = self.tube_list.count(card) elif (ctype == 3): a = self.bamb_list.count(card) elif (ctype == 4): a = self.word_list.count(card) else: a = self.wind_list.count(card) b = self.gb.drop_list.count(card) useful_amount += (4 - a - b) """ 1. enumerate, because goal state not too much 2. counting pong_list so that we can focus on 16 cards 3. check prewin first """ goals = [[4, 1, 1, 0], [5, 0, 0, 1], [4, 2, 0, 0]] gpattern = [["***", "***", "***", "***", "##", "$$"], ["***", "***", "***", "***", "***", "/"], ["***", "***", "***", "***", "##", "##"]] result = [0, 0, 0] size = len(self.pong_list) / 3 if ((size + kind[0]) > 4): return [0, useful_amount, score] for i in range(size): gpattern[0].remove("***") gpattern[1].remove("***") gpattern[2].remove("***") for number in range(3): k0 = kind[0] k1 = kind[1] k2 = kind[2] k3 = kind[3] p1 = gpattern[number] for i in range(k0): p1.remove("***") for i in range(min(k1, goals[number][1])): k1 -= 1 p1.remove("##") for i in range(min(k2, goals[number][2])): k2 -= 1 p1.remove("$$") #print "p1: {0}, size: {1}".format(p1, (k1+k2)*2+k3) step = 0 two = k1 + k2 for i in range(len(p1)): length = len(p1[i]) if (length == 3): if two: two -= 1 step += 1 else: step += 2 elif (length == 2): step += 1 result[number] = step #print "steps to goal: {0}, useful: {1}".format(result, len(useful)) return [min(result), useful_amount, score]
def drop(self): card = '' # 1. if len(self.word_list) == 1: card = self.word_list.pop() return card else: for c in set(self.word_list): if self.word_list.count(c) == 1: self.word_list.remove(c) self.card_count -= 1 return c if len(self.wind_list) == 1: card = self.wind_list.pop() return card else: for c in set(self.wind_list): if self.wind_list.count(c) == 1: self.wind_list.remove(c) self.card_count -= 1 return c # 2 if (not card) and len(self.tube_list) > 0: for c in set(self.tube_list): #number = int(card[:1]) if self.tube_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.tube_list or GameBoard.NextCard( c) in self.tube_list: continue else: self.tube_list.remove(c) return c if (not card) and '1筒' in self.tube_list: card = '1筒' self.tube_list.remove('1筒') return card elif (not card) and '9筒' in self.tube_list: card = '9筒' self.tube_list.remove('9筒') self.card_count -= 1 return card if (not card) and len(self.wang_list) > 0: for c in set(self.wang_list): if self.wang_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.wang_list or GameBoard.NextCard( c) in self.wang_list: continue else: self.wang_list.remove(c) self.card_count -= 1 return c if (not card) and '1萬' in self.wang_list: card = '1萬' self.wang_list.remove('1萬') return card elif (not card) and '9萬' in self.wang_list: card = '9萬' self.wang_list.remove('9萬') return card if (not card) and len(self.bamb_list) > 0: for c in set(self.bamb_list): if self.bamb_list.count(c) > 1: continue elif GameBoard.PrevCard( c) in self.bamb_list or GameBoard.NextCard( c) in self.bamb_list: continue else: self.bamb_list.remove(c) self.card_count -= 1 return c if (not card) and '1條' in self.bamb_list: card = '1條' self.bamb_list.remove(card) self.card_count -= 1 return card elif (not card) and '9條' in self.bamb_list: card = '9條' self.bamb_list.remove(card) self.card_count -= 1 return card # 任意丟一張 萬/筒/條 if (not card) and len(self.tube_list) > 0: card = self.tube_list.pop() if (not card) and len(self.wang_list) > 0: card = self.wang_list.pop() if (not card) and len(self.bamb_list) > 0: card = self.bamb_list.pop() self.card_count -= 1 return card