def drop(self): """ try to discard every card to find the best """ #print "drop_list: {0}".format(" ".join(self.gb.drop_list)) result = [] all_cards = [ self.wang_list, self.tube_list, self.bamb_list, self.word_list, self.wind_list ] previous = "" for cards in all_cards: for i in range(len(cards)): """ avoid running same card """ if (cards[i] == previous): continue c = cards.pop(i) previous = c mini, useful_amount, score = self.count_steps() cards.insert(i, c) result.append([mini, useful_amount, score, c]) #print "min: {0}, useful_amount: {1}, score: {2}, dcard: {3}".format(mini, useful_amount, score, c) dcard = self.sorting_by_criteria(result) #print "\tGeniusAgent drop: {0}".format(dcard) ctype = GameBoard.CardType(dcard) all_cards[ctype - 1].remove(dcard) self.card_count -= 1 return dcard
def _feedCard(self, card): ctype = GameBoard.CardType(card) if ctype == 1: self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 return True elif ctype == 2: self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 return True elif ctype == 3: self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 return True elif ctype == 4: self.word_list.append(card) self.word_list.sort() self.card_count += 1 return True elif ctype == 5: self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 return True else: self.flow_list.append(card) self.flow_list.sort()
def draw(self, keep=False): card = self.gb.drawCard() #print "\tGeniusAgent draw: {0}".format(card) prewin_tiles = GameBoard.PreWinTiles(self) if card in prewin_tiles: self.gb.win_agent = self self.win_card = card self.win_by_draw += 1 #print("\t[Test] Agent({0}) 自摸 {1}!".format(self.name, card)) return #print("\t[Test] {0} draw {1}...".format(self.name, card)) ctype = GameBoard.CardType(card) if ctype == 1: if self.wang_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 elif ctype == 2: if self.tube_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 elif ctype == 3: if self.bamb_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 elif ctype == 4: if self.word_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.word_list.append(card) self.word_list.sort() self.card_count += 1 elif ctype == 5: if self.wind_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 else: self.flow_list.append(card) self.flow_list.sort() return self.draw() dcard = self.drop() return dcard
def sorting_by_criteria(self, result): """ sort by steps to prewin (small -> big) """ result = sorted(result, key=lambda r: r[0]) flag = False m = result[0][0] for i in range(len(result)): if (result[i][0] == m): continue flag = True break if not flag: i += 1 result = result[:i] """ in prewin status, compare useful_amount only """ if (result[0][0] == 0): result = sorted(result, key=lambda r: r[1], reverse=True) test = "" for r in result: test += "[{0}, {1}, {2}, {3}], ".format(r[0], r[1], r[2], r[3]) # print "prewin status: {0}".format(test) self.current_best_state = [ result[0][0], result[0][1], result[0][2] ] return result[0][3] """ sort by score (big -> small) """ result = sorted(result, key=lambda r: r[2], reverse=True) flag = False m = result[0][2] for i in range(len(result)): if (result[i][2] == m): continue flag = True break if not flag: i += 1 result = result[:i] """ sort by useful card amount (big -> small) """ result = sorted(result, key=lambda r: r[1], reverse=True) """ choose one to discard """ dcard = result[0][3] m = result[0][1] best = result[0] for r in result: if (r[1] != m): break ctype = GameBoard.CardType(r[3]) if (ctype == 4) and (self.word_list.count(r[3]) == 1): dcard = r[3] best = r if (ctype == 5) and (self.wind_list.count(r[3]) == 1): dcard = r[3] best = r self.current_best_state = [r[0], r[1], r[2]] return dcard
def draw(self, keep=False): """ Draw card. (Required API by Agent) Gameboard will call this API to informat agent to draw card. Here should be responsible for: 1. Call API:drawCard() from GameBoard object to draw card. 2. Add drawn card into hand. 3. Return card as dropped card. (In general, you will call API:drop() for dropped card) * Return: Dropped card.""" card = self.gb.drawCard() if GameBoard.GoalState(self, card): # Check goal state self.gb.win_agent = self self.win_card = card self.win_by_draw += 1 print("\t[Test] Agent({0}) 自摸 {1}!".format(self.name, card)) return #print("\t[Test] {0} draw {1}...".format(self.name, card)) ctype = GameBoard.CardType(card) if ctype == 1: self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 elif ctype == 2: self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 elif ctype == 3: self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 elif ctype == 4: self.word_list.append(card) self.word_list.sort() self.card_count += 1 elif ctype == 5: self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 else: self.flow_list.append(card) self.flow_list.sort() return self.draw() dcard = None if not keep: dcard = self.drop() #print("\t[Test] {0} drop {1}...".format(self.name, dcard)) #self.gb.disCard(self, dcard) return dcard
def _isPrewin(self): prewin_tiles = GameBoard.PreWinTiles(self) if len(prewin_tiles) > 0: for tile in prewin_tiles: ctype = GameBoard.CardType(tile) if ctype == 1: if tile in self.gb.wang_list: return True elif ctype == 2: if tile in self.gb.tube_list: return True elif ctype == 3: if tile in self.gb.bamb_list: return True elif ctype == 4: if tile in self.gb.word_list: return True elif ctype == 5: if tile in self.gb.wind_list: return True
def _isPrewin(self): """ Check if entering pre-win(ready hand) status.""" prewin_tiles = GameBoard.PreWinTiles(self) if len(prewin_tiles) > 0: for tile in prewin_tiles: ctype = GameBoard.CardType(tile) if ctype == 1: if tile in self.gb.wang_list: return True elif ctype == 2: if tile in self.gb.tube_list: return True elif ctype == 3: if tile in self.gb.bamb_list: return True elif ctype == 4: if tile in self.gb.word_list: return True elif ctype == 5: if tile in self.gb.wind_list: return True
def draw(self, keep=False): """ Draw card. (Required API by Agent) Gameboard will call this API to informat agent to draw card. Here should be responsible for: 1. Call API:drawCard() from GameBoard object to draw card. 2. Add drawn card into hand. 3. Return card as dropped card. (In general, you will call API:drop() for dropped card) Different from the extended class, SmartAgent has its' own algorithm in drawing card: 1. 使用 self.gb.drawCard() 從牌桌抽一張牌. 2. 檢查是否滿足 Goal State (自摸). 2.1 如果已經聽牌, 則打出抽到的牌. 3. 檢查是否可以槓 3.1 如果槓, 可以再抽一張. 4. 選擇要放棄的牌. * Return: Dropped card.""" card = self.gb.drawCard() prewin_tiles = GameBoard.PreWinTiles(self) if card in prewin_tiles: #if GameBoard.GoalState(self, card): # Check goal state self.gb.win_agent = self self.win_card = card self.win_by_draw += 1 self.dprint("\t[Test] Agent({0}) 自摸 {1}!".format(self.name, card)) return elif len(prewin_tiles) > 0: self.pwin_flag = True for tile in prewin_tiles: ctype = GameBoard.CardType(tile) if ctype == 1: if tile in self.gb.wang_list: return card elif ctype == 2: if tile in self.gb.tube_list: return card elif ctype == 3: if tile in self.gb.bamb_list: return card elif ctype == 4: if tile in self.gb.word_list: return card elif ctype == 5: if tile in self.gb.wind_list: return card self.dprint("\t[Test] {0} draw {1}...".format(self.name, card)) ctype = GameBoard.CardType(card) if ctype == 1: if self.wang_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 elif ctype == 2: if self.tube_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 elif ctype == 3: if self.bamb_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 elif ctype == 4: if self.word_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.word_list.append(card) self.word_list.sort() self.card_count += 1 elif ctype == 5: if self.wind_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 else: self.flow_list.append(card) self.flow_list.sort() return self.draw() dcard = None if not keep: dcard = self.drop() self.dprint("\t[Test] {0} drop {1}...".format(self.name, dcard)) #self.gb.disCard(self, dcard) if (len(self.word_list) % 3 + len(self.wind_list) % 3 + len(self.tube_list) % 3 + len(self.wang_list) % 3 + len(self.bamb_list) % 3) == 0: self.wrong = True return dcard
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 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 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 draw(self, keep=False): card = self.gb.drawCard() if GameBoard.GoalState(self, card): # Check goal state self.gb.win_agent = self self.win_card = card self.win_by_draw += 1 print("\t[Test] Agent({0}) 自摸 {1}!".format(self.name, card)) return print("\t[Test] {0} draw {1}...".format(self.name, card)) ctype = GameBoard.CardType(card) if ctype == 1: if self.wang_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 elif ctype == 2: if self.tube_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 elif ctype == 3: if self.bamb_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 elif ctype == 4: if self.word_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.word_list.append(card) self.word_list.sort() self.card_count += 1 elif ctype == 5: if self.wind_list.count(card) == 3: # 確認槓牌 self._kong(ctype, card) return self.draw() self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 else: self.flow_list.append(card) self.flow_list.sort() return self.draw() dcard = None if not keep: dcard = self.drop() print("\t[Test] {0} drop {1}...".format(self.name, dcard)) #self.gb.disCard(self, dcard) if len(self.word_list) % 3 + len(self.wind_list) % 3 + len( self.tube_list) % 3 + len(self.wang_list) % 3 + len( self.bamb_list) % 3 != 2: self.wrong = True return dcard
def idraw(self): card = self.gb.drawCard() dctype = GameBoard.CardType(card) if GameBoard.GoalState(self, card): # Check goal state self.gb.win_agent = self self.win_card = card self.win_by_draw += 1 print("\t[Test] Agent({0}) 自摸 {1}!".format(self.name, card)) return if dctype > 5: self.flow_list.append(card) self.flow_list.sort() return self.idraw() print("\t[Info] {0}: You draw {1}...".format(self, card)) # 確認槓牌 if dctype == 1: if self.wang_list.count(card) == 3: # 確認槓牌 kong_opt = input('\t[Info] Kong {0} (y/n): '.format(card)) if len(kong_opt) > 0 and (kong_opt == 'y' or kong_opt == 'Y'): self._kong(dctype, card) return self.idraw() elif dctype == 2: if self.tube_list.count(card) == 3: # 確認槓牌 kong_opt = input('\t[Info] Kong {0} (y/n): '.format(card)) if len(kong_opt) > 0 and (kong_opt == 'y' or kong_opt == 'Y'): self._kong(dctype, card) return self.idraw() elif dctype == 3: if self.bamb_list.count(card) == 3: # 確認槓牌 kong_opt = input('\t[Info] Kong {0} (y/n): '.format(card)) if len(kong_opt) > 0 and (kong_opt == 'y' or kong_opt == 'Y'): self._kong(dctype, card) return self.idraw() elif dctype == 4: if self.word_list.count(card) == 3: # 確認槓牌 kong_opt = input('\t[Info] Kong {0} (y/n): '.format(card)) if len(kong_opt) > 0 and (kong_opt == 'y' or kong_opt == 'Y'): self._kong(dctype, card) return self.idraw() elif dctype == 5: if self.wind_list.count(card) == 3: # 確認槓牌 kong_opt = input('\t[Info] Kong {0} (y/n): '.format(card)) if len(kong_opt) > 0 and (kong_opt == 'y' or kong_opt == 'Y'): self._kong(dctype, card) return self.idraw() # choose drop card dcard = self._chooseDropCard() if dcard: if dctype == 1: self.wang_list.append(card) self.wang_list.sort() self.card_count += 1 elif dctype == 2: self.tube_list.append(card) self.tube_list.sort() self.card_count += 1 elif dctype == 3: self.bamb_list.append(card) self.bamb_list.sort() self.card_count += 1 elif dctype == 4: self.word_list.append(card) self.word_list.sort() self.card_count += 1 elif dctype == 5: self.wind_list.append(card) self.wind_list.sort() self.card_count += 1 print("\t[Test] {0} drop card={1}...".format(self.name, dcard)) #self.gb.disCard(self, dcard) return dcard else: print("\t[Test] {0} drop draw card={1}...".format(self.name, card)) #self.gb.disCard(self, card) return card