Skip to content

Instantly share code, notes, and snippets.

@popey456963
Created April 2, 2021 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save popey456963/40857326a7fc0c60f9d619b710da902e to your computer and use it in GitHub Desktop.
Save popey456963/40857326a7fc0c60f9d619b710da902e to your computer and use it in GitHub Desktop.
Codenames bot
import math
import random
import numpy as np
import time
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
beginInit = time.time()
gloves = {row[0]: (np.array([float(val) for val in row[1:]])) for row in (
[line.split() for line in open('glove.6B.300d.txt').read().strip().split("\n")])}
mags = {word: np.sqrt(np.dot(vec, vec)) for (word, vec) in gloves.items()}
print("took", str(time.time() - beginInit), "seconds to start up")
expected = []
findWordsTime = 0
app = FastAPI()
def cosSim(word1, word2):
# safely returns cosine similarity
if word1 not in gloves or word2 not in gloves:
return 0
vec1 = gloves[word1]
vec2 = gloves[word2]
num = np.dot(vec1, vec2)
denom = mags[word1]*mags[word2]
return num/denom
def cut(simScore):
# reduces noise of unassociated words
thres = 0.2
if simScore < thres and simScore > -1*thres:
return 0
else:
return simScore
def scoreWord(word1, roles):
# returns a list of associated words to word1 from the `good side`
wordscores = [(role, cut(cosSim(word1, word2)), word2)
for word2, (role, revealed) in roles.items()
if not revealed]
sorted_scores = sorted(wordscores, key=lambda x: x[1])
sorted_scores.reverse()
for x in range(len(wordscores)):
if (sorted_scores[x][0] < 0 or sorted_scores[x][1] == 0) and x > 0:
return sorted_scores[:x]
elif sorted_scores[x][0] < 0:
return []
return []
def findWords(roles):
# for each number, returns the best list of words of that length
start = time.time()
bests = {}
bestScores = [0] * 25
for word1 in gloves.keys():
exp = scoreWord(word1, roles)
count = len(exp)
score = sum([x[1] for x in exp])
if score > bestScores[count] and word1 not in roles.keys():
bestScores[count] = score
bests[count] = (word1, bestScores[count], exp)
print("took", str(time.time() - start), "seconds to find words")
print(bests)
return bests
def pickBest(bests):
# picks the best length of list
# bests cannot be empty
global expected
bestScore = 0
bestList = []
for wordList in bests.items():
if wordList[1][1] > bestScore:
bestScore = wordList[1][1]
bestList = wordList
print(bestList[1][0], bestList[0])
expected = bestList[1][2]
return {
'word': bestList[1][0],
'count': bestList[0],
'expected': bestList[1][2]
}
class Entry(BaseModel):
word: str
team: str
picked: bool
class Board(BaseModel):
board: List[Entry]
team: str
def other_team(team):
if team == 'red':
return 'blue'
if team == 'blue':
return 'red'
@app.post('/api/v1/word')
async def pickWord(board: Board):
roles = {}
for entry in board.board:
score = 0
if board.team == entry.team:
score = 1
if entry.team == 'civilian':
score = -8
if entry.team == 'assassin':
score = -20
if other_team(board.team) == entry.team:
score = -8
roles[entry.word.lower()] = (score, entry.picked)
print(roles)
print(len(roles.keys()))
res = pickBest(findWords(roles))
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment