Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Challenges

Three Number Monte

+3
−0

The Rules

In this game, each round, every player faces off against every other player in a round robin format. In each match, players pick 3 positive integers that sum to 360. Let's say player 1 picks [a, b, c] and player 2 picks [x, y, z] Now a is compared to x, b is compared to y, and c is compared to z. If a > x, player 1 gets a tally, and vice versa, for all 3 numbers.

If either player gets at least 2 tallies, they win the match and receive 1 point - otherwise, both players receive half a point.

To make this game more interesting, each match, the players get a data object that they can use for memory, and also a history object that contains all of their opponent's previous choices.

Submission

Write a Python function that takes in two arguments, data and history, described above, and returns an array of positive integers that sums to 360. You can find some example players in the driver code.

Driver

import random, itertools, math

def onethird(data, history):
	a = [120, 120, 120]
	random.shuffle(a)
	return a

def onehalf(data, history):
	a = [180, 180, 0]
	random.shuffle(a)
	return a

def rand(data, history):
	x = random.randint(0, 360)
	y = random.randint(0, 360 - x)
	return [x, y, 360 - x - y]

players = [onethird, onehalf, rand]

#Game logic
ROUNDS = 10000
pairs = list(itertools.combinations(players, 2))

data = {}
history = {}
scores = {}

for p in players:
	data[p] = {}
	history[p] = []
	scores[p] = 0

for _ in range(ROUNDS):
	random.shuffle(pairs)
	for pair in pairs:
		p1, p2 = pair
		a1 = p1(data[p1], history[p2])
		a2 = p2(data[p2], history[p1])

		assert sum(a1) == 360, (p1, a1)
		assert sum(a2) == 360, (p2, a2)
		assert all(isinstance(i, int) for i in a1), (p1, a1)
		assert all(isinstance(i, int) for i in a2), (p2, a2)
		assert all(0 <= i <= 360 for i in a1), (p1, a1)
		assert all(0 <= i <= 360 for i in a2), (p2, a2)

		history[p1].append(a1)
		history[p2].append(a2)

		p1c, p2c = 0, 0
		for i in range(3):
			if a1[i] > a2[i]:
				p1c += 1
			elif a2[i] > a1[i]:
				p2c += 1

		if p1c >= 2:
			scores[p1] += 1
		elif p2c >= 2:
			scores[p2] += 1
		else:
			scores[p1] += 0.5
			scores[p2] += 0.5

print(scores)

The tentative deadline for this competition is 8/16/21 00:00 UTC.

History
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

2 answers

+3
−0

MoshiBot

from numpy.polynomial import Polynomial
def MoshiBot(data, history):
	if len(history) < 10:
		return [180, 180, 0]

	lastmin = min(history[-1])
	lastmid = sorted(history[-1])[1]
	projectedmin = lastmin
	projectedmid = lastmid

	if len(history) >= 10:
		cutoff = len(history) - 10
		snapshot = history[cutoff:]
		minvalues = list(map(min, snapshot))
		midvalues = list(map(lambda vals: sorted(vals)[1], snapshot))
		
		xpoints = range(cutoff, cutoff + len(snapshot))
		minprojection = Polynomial.fit(xpoints, minvalues, deg=2)
		midprojection = Polynomial.fit(xpoints, midvalues, deg=2)

		projectedmin = minprojection(len(history))
		projectedmid = midprojection(len(history))

	safemin = max(0, min(360, math.ceil(projectedmin + 1)))

	if safemin >= 180:
		# The model broke down
		return [180, 180, 0]
	
	mid = math.floor(180 - safemin / 2)
	
	if mid > projectedmid:
		return [safemin, mid, 360 - safemin - mid]
	else:
		mid = max(safemin, min(360 - safemin, math.ceil(projectedmid + 1)))
		return [safemin, mid, 360 - safemin - mid]

Attempts to predict the opponents next move using a regressive model.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

1 comment thread

Imagine writing a simple bot and then you see someone else is literally writing linear regression (2 comments)
+2
−0

The "Uppers"

def oneup(data, history):
	if len(history) > 0:
		prev = history[-1]
		if prev[2] > 1:
			better = [prev[0] + 1, prev[1] + 1, prev[2] - 2]
		elif prev[1] > 1:
			better = [prev[0] + 1, prev[1] - 2, prev[2] + 1]
		else:
			better = [prev[0] - 2, prev[1] + 1, prev[2] + 1]
		random.shuffle(better)
		return better
	return [[180, 180, 0], [180, 0, 180], [0, 180, 180]][random.randint(0, 2)]

def avgup(data, history):
	if 't1' not in data:
		data['t1'] = 0
		data['t2'] = 0
		data['t3'] = 0
	if len(history) > 0:
		prev = history[-1]
		prev.sort()
		data['t1'] += prev[0]
		data['t2'] += prev[1]
		data['t3'] += prev[2]
		a1 = data['t1'] / len(history)
		a2 = data['t2'] / len(history)
		a3 = data['t3'] / len(history)
		if math.ceil(a1) + math.ceil(a2) <= 360:
			better = [math.ceil(a1), math.ceil(a2), 360 - math.ceil(a1) - math.ceil(a2)]
		else:
			better = [math.ceil(a1), 360 - math.ceil(a1), 0]
		random.shuffle(better)
		return better
	return [[180, 180, 0], [180, 0, 180], [0, 180, 180]][random.randint(0, 2)]

Two bots based off a single concept that seem to perform reasonably well. One takes the last submission the opponent made, and "one-ups" it - increments 2 values by 1 and decrements 1 value by 2. The other does the same thing, except with the average of all previous submissions by the opponent.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comment threads

Sign up to answer this question »