1-1

from enum import Enum
from dataclasses import dataclass
from typing import List, Optional, Tuple
from collections import Counter
from itertools import combinations
import sys
import random
 
class DiceRule(Enum):
    ONE = 0; TWO = 1; THREE = 2; FOUR = 3; FIVE = 4; SIX = 5
    CHOICE = 6; FOUR_OF_A_KIND = 7; FULL_HOUSE = 8; SMALL_STRAIGHT = 9; LARGE_STRAIGHT = 10; YACHT = 11
 
@dataclass
class Bid:
    group: str; amount: int
 
@dataclass
class DicePut:
    rule: DiceRule; dice: List[int]
 
class Game:
    def __init__(self):
        self.my_state = GameState(); self.opp_state = GameState()
        self.round = 0
        self.opp_bid_history: List[int] = []
 
    def calculate_bid(self, dice_a: List[int], dice_b: List[int]) -> Bid:
        """'이익 마진'과 '상황 판단'을 종합한 입찰 시스템"""
        self.round += 1
 
        my_score = self.my_state.get_total_score()
        opp_score = self.opp_state.get_total_score()
        score_diff = my_score - opp_score
        STANCE_THRESHOLD = 30000
 
        base_value = self.my_state.evaluate_dice_group_value([], self.round)
        my_value_a = self.my_state.evaluate_dice_group_value(dice_a, self.round)
        my_value_b = self.my_state.evaluate_dice_group_value(dice_b, self.round)
        gain_a = my_value_a - base_value
        gain_b = my_value_b - base_value
        
        my_best_group = "A" if gain_a > gain_b else "B"
        my_best_gain = max(gain_a, gain_b)
        
        # [NEW] 상대가 계속 0점만 냈는지 확인
        if self.round > 3 and self.opp_bid_history and all(b == 0 for b in self.opp_bid_history[-3:]):
            return Bid(my_best_group, 1) # 최근 3번 모두 0점이면, 우리도 1점만 냄
        # [수정] 기본 입찰액을 '순수 이득'의 일정 비율로 설정
        base_bid_ratio = 0.03
        if score_diff < -STANCE_THRESHOLD and self.round > 4:
            base_bid_ratio = 0.05
        elif score_diff > STANCE_THRESHOLD and self.round > 4:
            base_bid_ratio = 0.01
        
        amount = my_best_gain * base_bid_ratio
 
        # 상대방 평균 입찰액을 추가로 고려하여 최종 입찰액 상향 조정
        if self.opp_bid_history:
            opp_avg_bid = sum(self.opp_bid_history) / len(self.opp_bid_history)
            amount += opp_avg_bid * 0.5 # 상대 평균의 50%를 추가
 
        return Bid(my_best_group, min(7000, max(1, int(amount))))
 
    def calculate_put(self) -> DicePut:
        _, best_rule, best_dice_put = self.my_state.calculate_best_put(self.round)
        return DicePut(best_rule, best_dice_put)
    
    def update_get(self, dice_a: List[int], dice_b: List[int], my_bid: Bid, opp_bid: Bid, my_group: str):
        self.opp_bid_history.append(opp_bid.amount)
        if my_group == "A": self.my_state.add_dice(dice_a); self.opp_state.add_dice(dice_b)
        else: self.my_state.add_dice(dice_b); self.opp_state.add_dice(dice_a)
        my_bid_ok = my_bid.group == my_group
        self.my_state.bid(my_bid_ok, my_bid.amount)
        opp_group = "B" if my_group == "A" else "A"; opp_bid_ok = opp_bid.group == opp_group
        self.opp_state.bid(opp_bid_ok, opp_bid.amount)
 
    def update_put(self, put: DicePut): self.my_state.use_dice(put)
    def update_set(self, put: DicePut): self.opp_state.use_dice(put)
 
class GameState:
    def __init__(self):
        self.dice = []; self.rule_score: List[Optional[int]] = [None] * 12; self.bid_score = 0
 
    def get_total_score(self) -> int:
        basic = sum(s for s in self.rule_score[0:6] if s is not None)
        bonus = 35000 if basic >= 63000 else 0
        combination = sum(s for s in self.rule_score[6:12] if s is not None)
        return basic + bonus + combination + self.bid_score
        
    def bid(self, is_successful: bool, amount: int): self.bid_score += -amount if is_successful else amount
    def add_dice(self, new_dice: List[int]): self.dice.extend(new_dice)
 
    def use_dice(self, put: DicePut):
        if put.rule is None or self.rule_score[put.rule.value] is not None:
            fallback_rule_val = next((i for i, s in enumerate(self.rule_score) if s is None), 6)
            put.rule = DiceRule(fallback_rule_val)
        dice_counts = Counter(self.dice)
        for d in put.dice:
            if dice_counts[d] > 0:
                self.dice.remove(d)
                dice_counts[d] -= 1
        self.rule_score[put.rule.value] = self.calculate_score(put)
 
    def evaluate_dice_group_value(self, dice_group: List[int], round_num: int) -> float:
        if not dice_group: return 0
        potential_score, _, _ = self.calculate_best_put(round_num, dice_group)
        future_value_bonus = 0
        counts = Counter(self.dice + dice_group)
        if self.rule_score[DiceRule.YACHT.value] is None:
            for count in counts.values():
                if count >= 5: future_value_bonus += 80000
                elif count == 4: future_value_bonus += 45000
                elif count == 3: future_value_bonus += 15000
        if self.rule_score[DiceRule.FIVE.value] is None and counts[5] >= 3:
            future_value_bonus += 12000 + (counts[5] - 3) * 5000
        if self.rule_score[DiceRule.SIX.value] is None and counts[6] >= 3:
            future_value_bonus += 15000 + (counts[6] - 3) * 6000
        return potential_score + future_value_bonus
 
    def calculate_best_put(self, round_num: int, new_dice: List[int] = []) -> Tuple[int, DiceRule, List[int]]:
        current_dice = sorted(self.dice + new_dice)
        if len(current_dice) < 5:
            return -1, DiceRule(next((i for i, s in enumerate(self.rule_score) if s is None), 6)), current_dice + [1] * (5 - len(current_dice))
 
        potential_plays = []
        # [UPGRADE] CHOICE를 제외하고 먼저 모든 가능한 수를 찾음
        non_choice_rules = [r for r in DiceRule if r != DiceRule.CHOICE]
        for rule in non_choice_rules:
            if self.rule_score[rule.value] is None:
                combo = self._get_best_dice_for_rule(current_dice, rule, round_num)
                if combo:
                    potential_plays.append((self.calculate_score(DicePut(rule, combo)), rule, combo))
 
        def get_strategic_value(play):
            score, rule, combo = play
            value = float(score)
            if rule.value <= 5:
                num_of_dice = combo.count(rule.value + 1)
                if num_of_dice >= 4: value += 50000
                elif num_of_dice == 3: value += 18000
            if rule in [DiceRule.FOUR_OF_A_KIND, DiceRule.FULL_HOUSE] and score >= 24000: value += 40000
            if rule == DiceRule.YACHT and score > 0: value += 100000
            if rule == DiceRule.LARGE_STRAIGHT and score > 0: value += 25000
            if rule == DiceRule.SMALL_STRAIGHT and score > 0: value += 20000
            if round_num > 8 and rule.value > 5: value += 30000
            if score == 0: value = -99999
            return value
 
        best_score = -1
        best_rule = None
        best_combo = []
        best_strat_value = -999999
 
        if potential_plays:
            potential_plays.sort(key=get_strategic_value, reverse=True)
            best_play = potential_plays[0]
            best_score, best_rule, best_combo = best_play
            best_strat_value = get_strategic_value(best_play)
 
        # [UPGRADE] 마지막 턴이거나, 다른 모든 수의 최고점이 0점일 때만 CHOICE 사용
        is_last_turn = (round_num == 14) or len([s for s in self.rule_score if s is None]) == 1
        if (best_score <= 0 or is_last_turn) and self.rule_score[DiceRule.CHOICE.value] is None:
            choice_combo = self._get_best_dice_for_rule(current_dice, DiceRule.CHOICE, round_num)
            if choice_combo:
                return self.calculate_score(DicePut(DiceRule.CHOICE, choice_combo)), DiceRule.CHOICE, choice_combo
        
        # [UPGRADE] '쓰레기통' 족보에서 CHOICE 제외
        TRASH_THRESHOLD = 15000
        if best_strat_value < TRASH_THRESHOLD and round_num < 10:
            trash_options = [DiceRule.ONE, DiceRule.TWO]
            for trash_rule in trash_options:
                if self.rule_score[trash_rule.value] is None:
                    trash_combo = self._get_best_dice_for_rule(current_dice, trash_rule, round_num) or sorted(current_dice)[:5]
                    return self.calculate_score(DicePut(trash_rule, trash_combo)), trash_rule, trash_combo
        
        if best_rule:
            return best_score, best_rule, best_combo
            
        return 0, DiceRule(next((i for i, s in enumerate(self.rule_score) if s is None), 6)), current_dice[:5]
 
    def _get_best_dice_for_rule(self, current_dice: List[int], rule: DiceRule, round_num: int) -> List[int]:
        if len(current_dice) < 5: return []
        best_combo, max_score = [], -1
        min_score_threshold = 0 if rule in [DiceRule.ONE, DiceRule.TWO, DiceRule.CHOICE] else 1
        for combo_tuple in combinations(current_dice, 5):
            combo = list(combo_tuple)
            score = self.calculate_score(DicePut(rule, combo))
            if score >= min_score_threshold and score > max_score:
                max_score, best_combo = score, combo
        
        if max_score < min_score_threshold: return []
 
        if rule in [DiceRule.FIVE, DiceRule.SIX] and max_score > 0:
            if best_combo.count(rule.value + 1) < 4 and round_num < 9: return []
        if rule in [DiceRule.THREE, DiceRule.FOUR] and max_score > 0:
            if best_combo.count(rule.value + 1) < 3: return []
        
        return best_combo
 
    @staticmethod
    def calculate_score(put: DicePut) -> int:
        rule, dice = put.rule, sorted(put.dice); counts = Counter(dice)
        score = sum(dice) * 1000
        if rule.value <= 5: return dice.count(rule.value + 1) * (rule.value + 1) * 1000
        if rule == DiceRule.CHOICE: return score
        if rule == DiceRule.FOUR_OF_A_KIND and any(c >= 4 for c in counts.values()): return score
        if rule == DiceRule.FULL_HOUSE and sorted(counts.values()) in [[2, 3], [5]]: return score
        if rule == DiceRule.SMALL_STRAIGHT:
            s = "".join(map(str, sorted(list(set(dice)))));
            if "1234" in s or "2345" in s or "3456" in s: return 15000
        if rule == DiceRule.LARGE_STRAIGHT:
            s = "".join(map(str, sorted(list(set(dice)))))
            if s in ["12345", "23456"]: return 30000
        if rule == DiceRule.YACHT and 5 in counts.values(): return 50000
        return 0
 
def main():
    game = Game(); dice_a, dice_b = [0] * 5, [0] * 5; my_bid = Bid("", 0)
    while True:
        try:
            line = input().strip()
            if not line: continue
            command, *args = line.split()
            if command == "READY": print("OK")
            elif command == "ROLL":
                str_a, str_b = args
                for i, c in enumerate(str_a): dice_a[i] = int(c)
                for i, c in enumerate(str_b): dice_b[i] = int(c)
                my_bid = game.calculate_bid(dice_a, dice_b)
                print(f"BID {my_bid.group} {my_bid.amount}")
            elif command == "GET":
                get_group, opp_group, opp_score = args
                game.update_get(dice_a, dice_b, my_bid, Bid(opp_group, int(opp_score)), get_group)
            elif command == "SCORE":
                put = game.calculate_put()
                game.update_put(put)
                print(f"PUT {put.rule.name} {''.join(map(str, sorted(put.dice)))}")
            elif command == "SET":
                rule, str_dice = args
                dice = [int(c) for c in str_dice]
                game.update_set(DicePut(DiceRule[rule], dice))
            elif command == "FINISH": break
        except EOFError: break
 
if __name__ == "__main__":
    main()