1-4

#양철호 4승 코드
 
 
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
        
        potential_a = self.my_state.calculate_best_put(self.round, dice_a)[0]
        potential_b = self.my_state.calculate_best_put(self.round, dice_b)[0]
        chosen_group = "A" if potential_a > potential_b else "B"
 
        base_bid = 5
        max_bid = 49999
        my_bid = 0
 
        if self.round <= 5:
            # 초반 공격적 배팅: 덱 가치 차이에 기반
            diff = abs(potential_a - potential_b)
            my_bid = max(base_bid, int(diff / 500))
            if my_bid < 400:
                my_bid = 400
        else:
            # 6턴 이후: 상대방 패턴 분석 기반
            recent_bids = self.opp_bid_history[-5:] if len(self.opp_bid_history) >= 5 else self.opp_bid_history
            opp_avg_recent = sum(recent_bids) / len(recent_bids) if recent_bids else 0
            
            opp_avg_total = sum(self.opp_bid_history) / len(self.opp_bid_history) if self.opp_bid_history else 0
            
            weight_recent = 0.7
            weight_total = 0.3
            opp_weighted_avg = opp_avg_recent * weight_recent + opp_avg_total * weight_total
 
            if opp_weighted_avg > 1500: # 상대가 공격적이면
                my_bid = max(base_bid, int(opp_weighted_avg * 0.9)) # 약간 수비적으로 따라감
            else: # 상대가 수비적이면
                my_bid = max(base_bid, int(opp_weighted_avg * 1.3)) # 더 공격적으로 주도
 
        my_bid = min(max_bid, my_bid)
        return Bid(chosen_group, my_bid)
 
    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)
        for d in put.dice: 
            if d in self.dice: self.dice.remove(d)
        self.rule_score[put.rule.value] = self.calculate_score(put)
 
    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:
            dice_put = current_dice + [1] * (5 - len(current_dice))
            rule_val = next((i for i, s in enumerate(self.rule_score) if s is None), 6)
            return -1, DiceRule(rule_val), dice_put
 
        counts = Counter(current_dice)
        if round_num < 7:
            yacht_candidate_num = next((num for num, count in counts.items() if count >= 4 and num <= 2), None)
            if yacht_candidate_num:
                trash_rule = None
                if self.rule_score[DiceRule.CHOICE.value] is None: trash_rule = DiceRule.CHOICE
                elif self.rule_score[DiceRule.ONE.value] is None: trash_rule = DiceRule.ONE
                if trash_rule:
                    dice_to_discard = [d for d in current_dice if d != yacht_candidate_num]
                    dice_to_discard.extend([d for d in current_dice if d == yacht_candidate_num])
                    put = DicePut(trash_rule, dice_to_discard[:5])
                    return self.calculate_score(put), trash_rule, dice_to_discard[:5]
 
        if self.rule_score[DiceRule.YACHT.value] is None:
            yacht_num = next((num for num, count in counts.items() if count >= 5), None)
            if yacht_num:
                yacht_dice = [yacht_num] * 5
                put = DicePut(DiceRule.YACHT, yacht_dice)
                score = self.calculate_score(put)
                if score > 0: return score, DiceRule.YACHT, yacht_dice
        
        best_total_score = -99999
        best_rule = None
        best_dice_put = []
        potential_moves = []
        for rule in DiceRule:
            if self.rule_score[rule.value] is None:
                for dice_combination_tuple in combinations(current_dice, 5):
                    dice_combo = list(dice_combination_tuple)
                    put = DicePut(rule, dice_combo)
                    immediate_score = self.calculate_score(put)
                    strategic_bonus = 0
                    
                    if rule.value <= 5:
                        if round_num < 9 and dice_combo.count(rule.value + 1) < 3: continue
                        strategic_bonus += immediate_score * 0.8
 
                    four_of_a_kind_num = next((num for num, count in Counter(dice_combo).items() if count >= 4), None)
                    if four_of_a_kind_num and self.rule_score[four_of_a_kind_num-1] is None and rule.value == four_of_a_kind_num-1:
                        strategic_bonus += 30000
 
                    total_score = immediate_score + strategic_bonus
                    potential_moves.append((total_score, rule, dice_combo))
        
        if potential_moves:
            best_total_score, best_rule, best_dice_put = max(potential_moves, key=lambda x: x[0])
        
        if best_total_score < 8000:
            fallback_priority = [DiceRule.ONE, DiceRule.TWO, DiceRule.THREE, DiceRule.CHOICE]
            found_fallback = False
            for rule in fallback_priority:
                if self.rule_score[rule.value] is None:
                    best_rule = rule
                    best_dice_put = sorted(current_dice)[:5]
                    found_fallback = True
                    break
            if not found_fallback and self.rule_score[DiceRule.CHOICE.value] is None:
                best_rule = DiceRule.CHOICE
                best_dice_put = sorted(current_dice)[:5]
 
        if best_rule is None:
            best_rule = DiceRule(next((i for i, s in enumerate(self.rule_score) if s is None), 6))
        if not best_dice_put:
            best_dice_put = current_dice[:5]
 
        return best_total_score, best_rule, list(best_dice_put)
 
    @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()) and score >= 20000: return score
        if rule == DiceRule.FULL_HOUSE and sorted(counts.values()) in [[2, 3], [5]] and score >= 20000: 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:
            if "12345" in "".join(map(str, dice)) or "23456" in "".join(map(str, dice)): 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, 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()