From d23b5edbf1c1669612c62e3c94085a9bc86dd078 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 21:30:31 +0530 Subject: [PATCH 01/14] player 4 logic --- players/player_4/player.py | 221 +++++++++++++++++++++++++------------ 1 file changed, 151 insertions(+), 70 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index c3a67a7..f154bdd 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -1,77 +1,158 @@ -import openai +from collections import Counter -from models.player import Item, Player, PlayerSnapshot - -openai_api_key_player_4: str = 'sk-REDACTED' +from models.player import GameContext, Item, Player, PlayerSnapshot class Player4(Player): - def __init__(self, snapshot: PlayerSnapshot, conversation_length: int) -> None: # noqa: F821 - super().__init__(snapshot, conversation_length) - - self.client = openai.OpenAI(api_key=openai_api_key_player_4) - - def propose_item(self, history: list[Item]) -> Item | None: - prompt = self.create_prompt( - self.preferences, self.memory_bank, self.conversation_length, history - ) - print('Sending prompt!') - response = self.client.responses.create( - model='gpt-4.1', - input=prompt, - max_output_tokens=16, - ) - print(f'Received response: {response.output_text}') - if response.output_text == 'None': + def __init__(self, snapshot: PlayerSnapshot, ctx: GameContext) -> None: # noqa: F821 + super().__init__(snapshot, ctx) + + @staticmethod + def _is_pause(x: Item | None) -> bool: + return x is None + + @staticmethod + def _subjects_in(items: list[Item]) -> Counter[int]: + c = Counter() + for it in items: + c.update(it.subjects) + return c + + @staticmethod + def _take_preceding_block(history: list[Item | None], k: int) -> list[Item]: + """Take up to k preceding *non-pause* items, stopping if a pause is hit.""" + out: list[Item] = [] + for x in reversed(history): + if x is None: + break + out.append(x) + if len(out) == k: + break + out.reverse() + return out + + @staticmethod + def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: + """ + When history ends with a pause, take up to k items *before that pause*, + not crossing an earlier pause. + """ + if not history or history[-1] is not None: + return [] + # walk left of the trailing pause + out: list[Item] = [] + count = 0 + for x in reversed(history[:-1]): + if x is None: + break + out.append(x) + count += 1 + if count == k: + break + out.reverse() + return out + + + def _preference_tiebreak_key(self, item: Item) -> tuple[int, int, str]: + """ + Lower is better. Uses: + 1) best (lowest) index among the item's subjects in self.preferences + 2) sum of indices (to prefer items whose subjects are overall higher-ranked) + 3) id string for deterministic ordering + Subjects not found in preferences rank after all known preferences. + """ + n = len(self.preferences) + idxs = [ + (self.preferences.index(s) if s in self.preferences else n) + for s in item.subjects + ] + best = min(idxs) if idxs else n + total = sum(idxs) if idxs else n * 2 + return (best, total, str(item.id)) + + def _score_candidate(self, item: Item, history: list[Item | None]) -> float: + score = 0.0 + + # Repetition check: same item already in history? + already_seen = any(h is not None and h.id == item.id for h in history) + if already_seen: + # repeated items lose one point and contribute zero coherence/importance + score -= 1.0 + return score # early return: zero importance & coherence after first instance + + # Importance (only if not repeated) + score += float(item.importance) + + # Penalty: subject appeared in each of the previous 3 items? + prev3 = self._take_preceding_block(history, 3) + if len(prev3) == 3: + sets = [set(it.subjects) for it in prev3] + common_prev3 = sets[0].intersection(sets[1]).intersection(sets[2]) + if any(s in common_prev3 for s in item.subjects): + score -= 1.0 + + # Pause bonus: if most recent is a pause, and item has a subject not seen + # in the 5 turns prior to the pause (not crossing an earlier pause) -> +1 + if history and history[-1] is None: + window5 = self._take_window_before_pause(history, 5) + seen = set() + for it in window5: + seen.update(it.subjects) + + # Count how many candidate subjects are unseen in the last 5 turns + unseen_count = sum(1 for s in item.subjects if s not in seen) + + if unseen_count >= 2: + score += 2.0 # two or more unseen subjects → +2 + elif unseen_count >= 1: + score += 1.0 # exactly one unseen subject → +1 + + # Coherence relative to up to 3 preceding (no following at the end) + # Window cannot extend across a pause. + else: + context_items = self._take_preceding_block(history, 3) + subj_counts = self._subjects_in(context_items) + + if item.subjects: + # If any subject of I is never mentioned in CI -> -1 + if any(subj_counts.get(s, 0) == 0 for s in item.subjects): + score -= 1.0 + # If all subjects in I are mentioned at least twice in CI -> +1 + elif all(subj_counts.get(s, 0) >= 2 for s in item.subjects): + score += 1.0 + + return score + + # ------------ selection + + def propose_item(self, history: list[Item | None]) -> Item | None: + """ + Pick the memory_bank item with the maximum score under the rules. + Tie-breaker: player preference order. + Returns None if no items available. + """ + if not self.memory_bank: return None - try: - index = int(response.output_text) - if 0 <= index < len(self.memory_bank): - return self.memory_bank[index] - else: - return None - except ValueError: + + # Score all candidates + scored: list[tuple[float, Item]] = [ + (self._score_candidate(it, history), it) for it in self.memory_bank + ] + + # Find best score + if not scored: return None + best_score = max(s for s, _ in scored) + + # All with best score + tied = [it for s, it in scored if s == best_score] + + if len(tied) == 1: + choice = tied[0] + else: + # Tie-break by preferences + choice = min(tied, key=self._preference_tiebreak_key) - def create_prompt( - self, - preferences: list[int], - memory_bank: list[Item], - conversation_length: int, - history: list[Item], - ) -> str: - prompt = f""" - There are some players, and every player has a random memory bank of newsworthy items that they could contribute to the conversation. Every item has an importance. The conversation has a fixed length L, {conversation_length}. - - On each turn, each player may propose to share an item. If multiple players attempt to contribute an item: If the player currently talking wants to contribute again, they will be chosen with probability 0.5. If the player currently talking is not chosen, then a player at random from among those who propose an item and have so far contributed the smallest number of items among that group will be selected. If nobody contributes anything, then the sequence is filled by a "pause". If there are three consecutive pauses, then the conversation ends prematurely. - - The shared goals of a conversation are as follows: - - Coherence - For every item I, the (up to) 3 preceding items and (up to) 3 following items are collected into a set CI of context items. If a subject of I is never mentioned in CI then one point is lost from the final score. If all subjects in I are mentioned at least twice in CI then one point is added to the final score. The window defining CI does not extend beyond the start of the conversation or any pauses. - Importance - The total importance of all items in the final item sequence is added to the shared score. (Everybody agrees about the importance of each item.) - Nonrepetition - An item that is repeated has zero importance and does not contribute to the coherence score after the first instance of the item. - Freshness - Immediately after a pause, an item with a subject that was not previously present in the 5 turns prior to the pause gets a point added to the final score. An item with two novel subjects of this sort gets two bonus points. Repeated items do not get freshness points. - Nonmonotonousness - An item with a subject that was also present in each of the previous three items leads to the loss of a point. Also, repeated items lose one point, since the audience has already heard that news. - Individual goals depend on each player's preferred topics of conversation. The simulator gives each player a random permutation of the S subjects that represents the ranked preference of that player. An item with a subject that is of rank k for that player achieves a bonus of 1-k/|S| where |S| is the total number of possible subjects. An item with two subjects gives the player a bonus corresponing to the average of the two individual bonuses. Players know their own ranking, but not the ranking of other players. - - At the end of the game, the total score for each player is divided by L, resulting in an overall conversation quality that is the final metric by which players will be compared. - - You are a player in this game. Your goal is to select an item from your memory bank, or return "None" to pass, in order to achieve the highest conversation quality. - - The conversation so far is as follows: - {len(history)} items have been proposed in total: {', '.join('[' + 'subjects: ' + str(item.subjects) + ', importance: ' + str(item.importance) + ']' for item in history)}. - - Your memory bank contains the following items: - {', '.join('[' + 'id: ' + str(item.id) + ', subjects: ' + str(item.subjects) + ', importance: ' + str(item.importance) + ']' for item in memory_bank)}. - - Your preferences for subjects are as follows: - {', '.join('subject: ' + str(subject) + ', rank: ' + str(rank) for rank, subject in enumerate(preferences))} - - Based on the conversation so far, your memory bank, and your subject preferences, which item will you propose to contribute next? If you do not want to contribute an item, respond with "None". Otherwise, respond with the index of the item you wish to contribute, in your memory bank. Do not return anything other than either "None" or an integer index. - """ - return prompt + # Track contribution if you care downstream + self.contributed_items.append(choice) + return choice From 7348a3829675ca2c9d02b57fc0d5188724663627 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 21:36:46 +0530 Subject: [PATCH 02/14] ruff fix --- players/player_4/player.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index f154bdd..e975e14 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -52,7 +52,6 @@ def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: out.reverse() return out - def _preference_tiebreak_key(self, item: Item) -> tuple[int, int, str]: """ Lower is better. Uses: @@ -62,14 +61,11 @@ def _preference_tiebreak_key(self, item: Item) -> tuple[int, int, str]: Subjects not found in preferences rank after all known preferences. """ n = len(self.preferences) - idxs = [ - (self.preferences.index(s) if s in self.preferences else n) - for s in item.subjects - ] + idxs = [(self.preferences.index(s) if s in self.preferences else n) for s in item.subjects] best = min(idxs) if idxs else n total = sum(idxs) if idxs else n * 2 return (best, total, str(item.id)) - + def _score_candidate(self, item: Item, history: list[Item | None]) -> float: score = 0.0 @@ -103,9 +99,9 @@ def _score_candidate(self, item: Item, history: list[Item | None]) -> float: unseen_count = sum(1 for s in item.subjects if s not in seen) if unseen_count >= 2: - score += 2.0 # two or more unseen subjects → +2 + score += 2.0 # two or more unseen subjects → +2 elif unseen_count >= 1: - score += 1.0 # exactly one unseen subject → +1 + score += 1.0 # exactly one unseen subject → +1 # Coherence relative to up to 3 preceding (no following at the end) # Window cannot extend across a pause. From 829b1806cd438a70b835b6a9e718285ef294fbd4 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 21:42:31 +0530 Subject: [PATCH 03/14] ruff fix 2 --- players/player_4/player.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index e975e14..0beb87d 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -41,12 +41,11 @@ def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: return [] # walk left of the trailing pause out: list[Item] = [] - count = 0 - for x in reversed(history[:-1]): + #count = 0 + for count, x in enumerate(reversed(history[:-1])): if x is None: break out.append(x) - count += 1 if count == k: break out.reverse() @@ -143,11 +142,7 @@ def propose_item(self, history: list[Item | None]) -> Item | None: # All with best score tied = [it for s, it in scored if s == best_score] - if len(tied) == 1: - choice = tied[0] - else: - # Tie-break by preferences - choice = min(tied, key=self._preference_tiebreak_key) + choice = tied[0] if len(tied) == 1 else min(tied, key=self._preference_tiebreak_key) # Track contribution if you care downstream self.contributed_items.append(choice) From 421cb3e6d80722cd552780332be548c8014a4dac Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 21:43:28 +0530 Subject: [PATCH 04/14] ruff fix 3 --- players/player_4/player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 0beb87d..7b8410e 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -41,7 +41,7 @@ def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: return [] # walk left of the trailing pause out: list[Item] = [] - #count = 0 + # count = 0 for count, x in enumerate(reversed(history[:-1])): if x is None: break From 95fabfbb542ecbd71c3d10f18dc010a761128221 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 22:47:13 +0530 Subject: [PATCH 05/14] some changes with thresholding --- players/player_4/player.py | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 7b8410e..dad4aa7 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -51,6 +51,47 @@ def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: out.reverse() return out + def _coherence_prev3_score(self, item: Item, history: list[Item | None]) -> float: + """ + Coherence over the previous up to 3 non-pause items: + - Hot-streak penalty: if any subject in `item` appears in *each* of the last 3 -> -1.0 + - Otherwise, reward based on total matched frequency across prev-3: + sum_match/len(item.subjects) + sum_match >= 4 -> +1.5 (e.g., 2+2) + sum_match == 3 -> +1.0 (e.g., 2+1) + sum_match == 2 -> +0.5 + sum_match == 1 -> +0.25 + else -> 0.0 + The window does not cross pauses. + """ + prev3 = self._take_preceding_block(history, 3) + if not prev3 or not item.subjects: + return 0.0 + + # Hot-streak penalty (subject present in all three previous items) + if len(prev3) == 3: + sets = [set(it.subjects) for it in prev3] + common_all3 = sets[0] & sets[1] & sets[2] + if any(s in common_all3 for s in item.subjects): + return -1.0 + """if sum_match >= 4: + elif sum_match == 3: + return 1.0 + elif sum_match == 2: + return 0.5 + elif sum_match == 1: + return 0.25 + else: + return 0.0""" + # Count subject frequencies across prev-3 + counts = Counter() + for it in prev3: + counts.update(it.subjects) + + # Total matched frequency across candidate subjects + sum_match = sum(counts.get(s, 0) for s in item.subjects) + return sum_match/len(item.subjects) + def _preference_tiebreak_key(self, item: Item) -> tuple[int, int, str]: """ Lower is better. Uses: @@ -108,7 +149,7 @@ def _score_candidate(self, item: Item, history: list[Item | None]) -> float: context_items = self._take_preceding_block(history, 3) subj_counts = self._subjects_in(context_items) - if item.subjects: + if item.subjects and context_items: # If any subject of I is never mentioned in CI -> -1 if any(subj_counts.get(s, 0) == 0 for s in item.subjects): score -= 1.0 @@ -116,6 +157,7 @@ def _score_candidate(self, item: Item, history: list[Item | None]) -> float: elif all(subj_counts.get(s, 0) >= 2 for s in item.subjects): score += 1.0 + score += self._coherence_prev3_score(item, history) return score # ------------ selection @@ -138,7 +180,11 @@ def propose_item(self, history: list[Item | None]) -> Item | None: if not scored: return None best_score = max(s for s, _ in scored) - + print(best_score) + print(history) + if len(history)!=0 and best_score < 1: + return None + # All with best score tied = [it for s, it in scored if s == best_score] From 482c44d5daffc2f414309fc5e8a7a08982c25172 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 22:47:35 +0530 Subject: [PATCH 06/14] some changes with thresholding --- players/player_4/player.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index dad4aa7..5fca368 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -90,7 +90,7 @@ def _coherence_prev3_score(self, item: Item, history: list[Item | None]) -> floa # Total matched frequency across candidate subjects sum_match = sum(counts.get(s, 0) for s in item.subjects) - return sum_match/len(item.subjects) + return sum_match / len(item.subjects) def _preference_tiebreak_key(self, item: Item) -> tuple[int, int, str]: """ @@ -182,9 +182,9 @@ def propose_item(self, history: list[Item | None]) -> Item | None: best_score = max(s for s, _ in scored) print(best_score) print(history) - if len(history)!=0 and best_score < 1: + if len(history) != 0 and best_score < 1: return None - + # All with best score tied = [it for s, it in scored if s == best_score] From 4e20556c7094a119153ae6ce70f313147be307fc Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 22:53:57 +0530 Subject: [PATCH 07/14] remove some print statements --- players/player_4/player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 5fca368..f73499e 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -180,8 +180,8 @@ def propose_item(self, history: list[Item | None]) -> Item | None: if not scored: return None best_score = max(s for s, _ in scored) - print(best_score) - print(history) + #print(best_score) + #print(history) if len(history) != 0 and best_score < 1: return None From 5e337a4ec4564d30d7a82ce46b6e79c3c6da704c Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 15 Sep 2025 23:05:56 +0530 Subject: [PATCH 08/14] remove some print statements 2 --- players/player_4/player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index f73499e..dccdbba 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -180,8 +180,8 @@ def propose_item(self, history: list[Item | None]) -> Item | None: if not scored: return None best_score = max(s for s, _ in scored) - #print(best_score) - #print(history) + # print(best_score) + # print(history) if len(history) != 0 and best_score < 1: return None From e5bd8adcb9f73dd16a2c172ef852c5962cacbd80 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari <74658782+akshatbhandari15@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:18:27 +0530 Subject: [PATCH 09/14] player4 py resolving broke ruff --- players/player_4/player.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 72da77c..dccdbba 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -149,7 +149,6 @@ def _score_candidate(self, item: Item, history: list[Item | None]) -> float: context_items = self._take_preceding_block(history, 3) subj_counts = self._subjects_in(context_items) - if item.subjects and context_items: # If any subject of I is never mentioned in CI -> -1 if any(subj_counts.get(s, 0) == 0 for s in item.subjects): @@ -181,20 +180,16 @@ def propose_item(self, history: list[Item | None]) -> Item | None: if not scored: return None best_score = max(s for s, _ in scored) - #print(best_score) - #print(history) + # print(best_score) + # print(history) if len(history) != 0 and best_score < 1: return None - best_score = max(s for s, _ in scored) # All with best score tied = [it for s, it in scored if s == best_score] choice = tied[0] if len(tied) == 1 else min(tied, key=self._preference_tiebreak_key) - # All with best score - tied = [it for s, it in scored if s == best_score] - choice = tied[0] if len(tied) == 1 else min(tied, key=self._preference_tiebreak_key) # Track contribution if you care downstream self.contributed_items.append(choice) return choice From 8539200e2961f4cdbda0a6abd008809c022865aa Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Wed, 17 Sep 2025 21:29:39 +0530 Subject: [PATCH 10/14] added preferences scores for ranking items to propose --- players/player_4/player.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index dccdbba..caa3752 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -6,6 +6,7 @@ class Player4(Player): def __init__(self, snapshot: PlayerSnapshot, ctx: GameContext) -> None: # noqa: F821 super().__init__(snapshot, ctx) + self.ctx = ctx @staticmethod def _is_pause(x: Item | None) -> bool: @@ -46,11 +47,29 @@ def _take_window_before_pause(history: list[Item | None], k: int) -> list[Item]: if x is None: break out.append(x) - if count == k: + if count + 1 == k: break out.reverse() return out + def _preference_bonus(self, item: Item) -> float: + """ + Average of (1 - k/|S|) over the item's subjects, where k is 1-based rank + in self.preferences (a permutation of all subjects). Unknown subjects -> 0. + Only called when history ends with a pause. + """ + S = len(self.preferences) + if S == 0 or not item.subjects: + return 0.0 + + def subj_bonus(s: int) -> float: + # worst-case (unknown) -> k = S -> 1 - S/S = 0 + k = self.preferences.index(s) + 1 if s in self.preferences else S + return 1.0 - (k / S) + + bonuses = [subj_bonus(s) for s in item.subjects] + return sum(bonuses) / len(bonuses) + def _coherence_prev3_score(self, item: Item, history: list[Item | None]) -> float: """ Coherence over the previous up to 3 non-pause items: @@ -157,6 +176,7 @@ def _score_candidate(self, item: Item, history: list[Item | None]) -> float: elif all(subj_counts.get(s, 0) >= 2 for s in item.subjects): score += 1.0 + score += self._preference_bonus(item) score += self._coherence_prev3_score(item, history) return score @@ -182,7 +202,9 @@ def propose_item(self, history: list[Item | None]) -> Item | None: best_score = max(s for s, _ in scored) # print(best_score) # print(history) - if len(history) != 0 and best_score < 1: + max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence + threshold = max_possible * 0.3 + if len(history) != 0 and best_score < threshold: return None # All with best score From 18c1ca2901db375dd088aba9010575e750698e7f Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 22 Sep 2025 22:14:30 +0530 Subject: [PATCH 11/14] updated threshold --- players/player_4/player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index caa3752..2831336 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -203,10 +203,10 @@ def propose_item(self, history: list[Item | None]) -> Item | None: # print(best_score) # print(history) max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence - threshold = max_possible * 0.3 + threshold = 1 if len(history) != 0 and best_score < threshold: return None - + # All with best score tied = [it for s, it in scored if s == best_score] From b3d32a44834b8e0509bbe3a959985dd26c0d8c93 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 22 Sep 2025 22:20:16 +0530 Subject: [PATCH 12/14] formatting --- players/player_4/player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 2831336..f360667 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -202,11 +202,11 @@ def propose_item(self, history: list[Item | None]) -> Item | None: best_score = max(s for s, _ in scored) # print(best_score) # print(history) - max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence + #max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence threshold = 1 if len(history) != 0 and best_score < threshold: return None - + # All with best score tied = [it for s, it in scored if s == best_score] From 36f7408f9fb8f38a5076d33b3c61f2d68ceac153 Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Mon, 22 Sep 2025 22:22:13 +0530 Subject: [PATCH 13/14] formatting --- players/player_4/player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index f360667..9a0bf09 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -202,7 +202,7 @@ def propose_item(self, history: list[Item | None]) -> Item | None: best_score = max(s for s, _ in scored) # print(best_score) # print(history) - #max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence + # max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence threshold = 1 if len(history) != 0 and best_score < threshold: return None From 2fd16474796543ea702814ea37b8808cc58dfecb Mon Sep 17 00:00:00 2001 From: Akshat Bhandari Date: Wed, 24 Sep 2025 22:47:34 +0530 Subject: [PATCH 14/14] formatting --- players/player_4/player.py | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/players/player_4/player.py b/players/player_4/player.py index 9a0bf09..bfd76d9 100644 --- a/players/player_4/player.py +++ b/players/player_4/player.py @@ -74,13 +74,8 @@ def _coherence_prev3_score(self, item: Item, history: list[Item | None]) -> floa """ Coherence over the previous up to 3 non-pause items: - Hot-streak penalty: if any subject in `item` appears in *each* of the last 3 -> -1.0 - - Otherwise, reward based on total matched frequency across prev-3: + - Otherwise, reward based on total matched frequency across prev-3 for each subject: sum_match/len(item.subjects) - sum_match >= 4 -> +1.5 (e.g., 2+2) - sum_match == 3 -> +1.0 (e.g., 2+1) - sum_match == 2 -> +0.5 - sum_match == 1 -> +0.25 - else -> 0.0 The window does not cross pauses. """ prev3 = self._take_preceding_block(history, 3) @@ -93,15 +88,6 @@ def _coherence_prev3_score(self, item: Item, history: list[Item | None]) -> floa common_all3 = sets[0] & sets[1] & sets[2] if any(s in common_all3 for s in item.subjects): return -1.0 - """if sum_match >= 4: - elif sum_match == 3: - return 1.0 - elif sum_match == 2: - return 0.5 - elif sum_match == 1: - return 0.25 - else: - return 0.0""" # Count subject frequencies across prev-3 counts = Counter() for it in prev3: @@ -200,9 +186,7 @@ def propose_item(self, history: list[Item | None]) -> Item | None: if not scored: return None best_score = max(s for s, _ in scored) - # print(best_score) - # print(history) - # max_possible = 1.0 + 2.0 + 1.5 # importance + pause + coherence + threshold = 1 if len(history) != 0 and best_score < threshold: return None @@ -212,6 +196,6 @@ def propose_item(self, history: list[Item | None]) -> Item | None: choice = tied[0] if len(tied) == 1 else min(tied, key=self._preference_tiebreak_key) - # Track contribution if you care downstream + # Track contribution self.contributed_items.append(choice) return choice