• Basic set solution by sirpengi
  • 5 years, 4 months ago
  • Download | Raw
import os
import sys
import itertools
from collections import Counter
from functools import total_ordering

debug = False

def maxs(itr, n):
	for i in sorted(itr, reverse=True):
		if n < 1:
			raise StopIteration
		yield i
		n = n - 1

def chain(*args):
	ret = []
	for i in args:
		if not hasattr(i, "__iter__"):
			i = [i,]
		ret.append(i)
	return list(itertools.chain(*ret))

@total_ordering
class card(object):
	def __init__(self, s=None, suit=None, value=None):
		if s is not None:
			self.s = s
			self.value = card.s_to_value(s[0])
			self.suit = card.s_to_suit(s[1])
		else:
			self.value = value
			self.suit = suit

	def __eq__(self, other):
		return (self.value == other.value)

	def __lt__(self, other):
		return self.value < other.value
	
	@property
	def hash(self):
		return "{}{}".format(self.value, self.suit)

	def __repr__(self):
		return self.hash

	def next_card(self):
		v = self.value + 1
		s = self.suit
		if v == 15:
			v = 2
		return card(suit=s, value=v)

	@staticmethod
	def s_to_value(s):
		try:
			v = int(s)
		except (TypeError, ValueError):
			v = {"T":10, "J":11, "Q":12, "K":13, "A":14}.get(s)
		return v

	@staticmethod
	def s_to_suit(s):
		return s

@total_ordering
class cardset(object):
	def __init__(self, playern, cards):
		self.playern = playern
		self.cards = sorted(cards)
		self.card_hashes = set(c.hash for c in cards)
		self.v_hashes = set(c.value for c in cards)
		self._result = None

	@property
	def result(self):
		if self._result == None:
			self._result = self.get_result()
		return self._result

	def get_result(self):
		value_counts = Counter()
		suit_counts = Counter()
		run_starts = []
		for c in self.cards:
			value_counts[c.value] += 1
			suit_counts[c.suit] += 1
			_c = c
			for _ in range(4):
				_c = _c.next_card()
				if _c.value not in self.v_hashes:
					break
			else:
				if _c.value >= 5:
					run_starts.append(c)

		max_same_suit = max(suit_counts.values())
		max_same_value = max(value_counts.values())
		has_flush = max(suit_counts.values()) > 4
		has_straight = len(run_starts) > 0

		# STRAIGHT FLUSH
		if (has_flush and has_straight):
			for i in run_starts:
				_c = i
				for c in range(4):
					_c = _c.next_card()
					if _c.hash not in self.card_hashes:
						break
				else:
					v = _c.value
					return (8, v)

		# FOUR OF A KIND
		if (max_same_value >= 4):
			fourk = [k for k, v in value_counts.items() if v == 4]
			v = max(fourk)
			sub = max(i for i in self.v_hashes if i != v)
			return chain(7, v, sub)

		# FULL HOUSE
		if (max_same_value >= 3):
			majors = [k for k, v in value_counts.items() if v == 3]
			minors = [k for k, v in value_counts.items() if v == 2]
			if len(majors) > 1:
				return chain(6, list(maxs(majors, 2)))
			if len(majors) and len(minors):
				return (6, max(majors), max(minors))

		# FLUSH
		if (has_flush):
			suits = [k for k, v in suit_counts.items() if v == max_same_suit]
			# only one possible flush suit
			suit = suits[0]
			cards = sorted([c.value for c in self.cards if c.suit == suit], reverse=True)
			return chain(5, cards)

		# STRAIGHT
		if (has_straight):
			v = max(i.value for i in run_starts)
			if v == 14:
				v = 1
			return (4, v)

		# THREE OF A KIND
		if max_same_value >= 3:
			trips = [k for k,v in value_counts.items() if v == 3]
			v = max(trips)
			subs = list(maxs([c.value for c in reversed(self.cards) if c.value != v], 2))
			return chain(3, v, subs)

		if max_same_value >= 2:
			pairs = [k for k,v in value_counts.items() if v == 2]
			if len(pairs) > 1:
				# TWO PAIR
				twop = sorted(list(maxs(pairs, 2)), reverse=True)
				sub = max(c.value for c in self.cards if c.value not in twop)
				return chain(2, twop, sub)
			else:
				# ONE PAIR
				v = max(pairs)
				subs = list(maxs([c.value for c in self.cards if c.value != v], 3))
				return chain(1, v, subs)

		subs = list(maxs([c.value for c in self.cards], 5))
		return chain(0, subs)
	
	def __eq__(self, other):
		a = tuple(self.result)
		b = tuple(other.result)
		return a == b

	def __lt__(self, other):
		a = tuple(self.result)
		b = tuple(other.result)
		return a < b

class gamestate(object):
	def __init__(self, community, players):
		self.community = community
		self.players = players

	def who_won(self):
		ret = []
		for i, p in enumerate(self.players):
			ret.append(cardset(i, chain(p, self.community)))
		results = list(reversed(sorted(ret)))
		best = results[0]
		if debug:
			print [(r.playern, r.result) for r in results]
		return sorted([cs.playern for cs in results if cs.result == best.result])

def run(fn):
	with open(fn) as fh:
		data = fh.readlines()
	i = data.__iter__()
	i.next()
	j = 0
	while 1:
		j += 1
		if debug:
			print "========", j, "============"
		try:
			num_players = int(i.next())
			community = [card(s) for s in i.next().split()]
			players = []
			for p in range(num_players):
				players.append([card(s) for s in i.next().split()])
			if debug:
				print community
				print players
			gs = gamestate(community, players)
			res = gs.who_won()
			print " ".join([str(_) for _ in res])
		except StopIteration:
			break

if __name__ == "__main__":
	if len(sys.argv) > 1:
		run(sys.argv[1])
	else:
		print "You need to pass in a file yo"

Scoreboard

lzm bas adv bon 200
sirpengi bas adv bon 200
sixthgear bas adv bon 190
mserrano bas adv bon 190
robbinsr bas adv bon 190
synx bas adv bon 50

What do?

  1. Write your program according to the problem description
  2. Download the basic input set. The timer will start.
  3. Feed the input file to your program and save the output.
  4. Upload the output file along with your source code. If it is correct, you will receive points. If not you may try again until the timer expires.
  5. If the timer expires. You may try again, but a new input file will be generated.
  6. Repeat fot each set.

Note: The input sets use unix line endings (\n) and the verifier expects them as well.


Come Chat!

Join channel ##proggit on freenode.

Bugs

Having issues with the the site? Let us know.