# Torbert, 12.2.2004
# Modified by Schafer/Hayes 2005

import sys, traceback, os, signal, select, time
from os import system, listdir
from sys import argv
from time import time, sleep
from random import shuffle

tourney = False
if len(argv) > 1:
	tourney = True
time_pool, allowed_time = 60.0, 1.0

black, white, empty, outer = 1, 2, 0, 3
directions = [-11, -10, -9, -1, 1, 9, 10, 11]

def printState(board, lastMove, currTest, b, w, s, bl, wl):
	if board[currTest] == black:
		if currTest == lastMove:
			return bl
		else:
			return b
	if board[currTest] == white:
		if currTest == lastMove:
			return wl
		else:
			return w
	if board[currTest] == empty:
		return s

def display(state, lastMove):
	start = chr(27) + "[32;42m" + chr(27) + "[1m"
	end = chr(27) + "[0m"
	LeftUpperCorner = start + "+" + end
	LeftSide = start + "|" + end
	LeftInterSection = start + "+" + end
	LeftLowerCorner = start + "+" + end
	RightUpperCorner = start + "+" + end
	RightSide = start + "|" + end
	RightInterSection = start + "+" + end
	RightLowerCorner = start + "+" + end
	LowerSide = start + "-" + end
	LowerInterSection = start + "+" + end
	UpperSide = start + "-" + end
	UpperInterSection = start + "+" + end
	VerticalBar = start + "|" + end
	HorizontalBar = start + "-" + end
	MiddleInterSection = start + "+" + end

	blackMarker = chr(27) + "[30;42m" + chr(27) + "[1m" + " * " + chr(27) + "[0m"
	whiteMarker = chr(27) + "[37;42m" + chr(27) + "[1m" + " * " + chr(27) + "[0m"
	spaceMarker = chr(27) + "[31;42m" + chr(27) + "[1m" + "   " + chr(27) + "[0m"
	blackLast = chr(27) + "[30;46m" + chr(27) + "[1m" + " * " + chr(27) + "[0m"
	whiteLast = chr(27) + "[37;46m" + chr(27) + "[1m" + " * " + chr(27) + "[0m"

	string = ""

	string += LeftUpperCorner
	string += UpperSide
	string += UpperSide
	string += UpperSide
	for i in range(7):
		string += UpperInterSection
		string += UpperSide
		string += UpperSide
		string += UpperSide
	string += RightUpperCorner
	string += "\n"

	for i in range(7):
		string += LeftSide
		for j in range(7):
			string += printState(state, lastMove, 10*i+j+11, blackMarker, whiteMarker, spaceMarker, blackLast, whiteLast)
			string += VerticalBar
		string += printState(state, lastMove, 10*i+18, blackMarker, whiteMarker, spaceMarker, blackLast, whiteLast)
		string += RightSide
		string += "\n"

		string += LeftInterSection
		string += HorizontalBar
		string += HorizontalBar
		string += HorizontalBar
		for i in range(7):
			string += MiddleInterSection
			string += HorizontalBar
			string += HorizontalBar
			string += HorizontalBar
		string += RightInterSection
		string += "\n"

	string += LeftSide
	for j in range(7):
		string += printState(state, lastMove, 81+j, blackMarker, whiteMarker, spaceMarker, blackLast, whiteLast)
		string += VerticalBar
	string += printState(state, lastMove, 88, blackMarker, whiteMarker, spaceMarker, blackLast, whiteLast)
	string += RightSide
	string += "\n"



	string += LeftLowerCorner
	string += LowerSide
	string += LowerSide
	string += LowerSide
	for i in range(7):
		string += LowerInterSection
		string += LowerSide
		string += LowerSide
		string += LowerSide
	string += RightLowerCorner
	string += "\n"
	
	print string

def show(board):
	print "  " + "".join(map(str,range(1,9)))
	for row in range(10, 90, 10):
		s = str(row) + "" 
		for col in range(1, 9):
			square = board[row + col]
			if square is empty:
				s += chr(27) + "[32;42"
			elif square is white:
				s += chr(27) + "[37;42"
			else:
				s += chr(27) + "[30;42"
			s += "m"
			s += chr(27) + "[1m";
			if square is empty:
				s += " "
			else:
				s += "+"
		print s + chr(27) + "[0m"
	print

def bracket(board, player, square):
	opp = opponent_color(player)
	for d in directions:
		k = square + d
		if board[k] is not opp:
			continue
		while board[k] is opp:
			k = k + d
		if board[k] is player:
			k = k - d
			while k != square:
				board[k] = player
				k = k - d

def would_bracket(board, player, square):
	opp = opponent_color(player)
	for d in directions:
		k = square + d
		if board[k] is not opp:
			continue
		while board[k] is opp:
			k = k + d
		if board[k] is player:
			return True
	return False

def get_legal_moves(board, player):
	possible = []
	for row in range(10, 90, 10):
		for col in range(1, 9):
			square = row + col
			if board[square] is not empty:
				continue
			if would_bracket(board, player, square):
				possible.append(square)
	return possible

def opponent_color(player):
	if player is black: 
		return white
	return black

def count(board, player):
	total = 0
	for row in range(10, 90, 10):
		for col in range(1, 9):
			square = board[row + col]
			if square is player:	
				total = total + 1
	return total

def play_one(strategies, flag, outfile, bPlayer, wPlayer):
	whiteForfeit = 64
	blackForfeit = -64
	board = [empty] * 100
	board[0:10] = [outer] * 10
	board[90:100] = [outer] * 10
	for k in range(10, 90, 10):
		board[k + 0] = outer
		board[k + 9] = outer
	board[44], board[55] = white, white
	board[45], board[54] = black, black
	if flag:
		system("clear")
		display(board, None)
	player, squares, stuck = black, 4, 0
	one, two = 0, 0
	while squares < 64 and stuck < 2:
		start = time()
		if player is white:
			square = strategies[player].pick(board[:], player)
		else:
			square = strategies[player].pick(board[:], player)
		outfile.write(str(square)+"\n")
		finish = time()
		total_time = finish - start
		if player is white:
			two += total_time
			if two > time_pool and total_time > allowed_time:
				if flag:
					print "White is disqualified for taking too much time."
				return whiteForfeit
		else:
			one += total_time
			if one > time_pool and total_time > allowed_time:
				if flag:
					print "Black is disqualified for taking too much time."
				return blackForfeit
		possible = get_legal_moves(board, player)
		if square is not None:
			if square not in possible:
				if player is white:
					if flag:
						print "White is disqualified for an illegal move."
					return whiteForfeit
				else:
					if flag:
						print "Black is disqualified for an illegal move."
					return blackForfeit
			board[square] = player
			bracket(board, player, square)
			squares += 1
			stuck = 0
		elif len(possible) == 0:
			stuck += 1
		else:
			if player is white:
				if flag:
					print "White is disqualified for passing illegally."
				return whiteForfeit
			else:
				if flag:
					print "Black is disqualified for passing illegally."
				return blackForfeit			
		player = opponent_color(player)
		if flag:
			system("clear")
			display(board, square)
			w, b = count(board, white), count(board, black)
			print "Black (" + bPlayer + "): "+str(b)+"\t["+str(time_pool-one)+"]"
			print "White (" + wPlayer + "): "+str(w)+"\t["+str(time_pool-two)+"]"
	w, b = count(board, white), count(board, black)
	if flag:
		system("clear")
		display(board, None)
		print "Black (" + bPlayer + "): "+str(b)
		print "White (" + wPlayer + "): "+str(w)
		print
	return b-w

def showTourneyResults(results, files):
	print
	print "RESULTS TABLE"
	print
	print "\t",
	for i in range(len(files)):
		print str(i+1)+" ",
	print "BLACK"
	for i in files:
		print i[0:7]+"\t",
		for j in files:
			print results[i][j],
		print
	print "WHITE"
	print "Number given = Black pieces - White pieces."
	print

def sortStandings(results, files):
	sortedFiles = files[:]
	l = len(files)
	for a in range(l):
		for b in range(l):
			if a != b:
				i = sortedFiles[a]
				j = sortedFiles[b]
				if 2*results[i]['W']+results[i]['D'] > 2*results[j]['W']+results[j]['D']:
					sortedFiles[a], sortedFiles[b] = sortedFiles[b], sortedFiles[a]
					continue
				if 2*results[i]['W']+results[i]['D'] < 2*results[j]['W']+results[j]['D']:
					continue
				if results[i]['W'] > results[j]['W']:
					sortedFiles[a], sortedFiles[b] = sortedFiles[b], sortedFiles[a]
					continue
				if results[i]['W'] < results[j]['W']:
					continue
				if results[i]['L'] < results[j]['L']:
					sortedFiles[a], sortedFiles[b] = sortedFiles[b], sortedFiles[a]
					continue
				if results[i]['L'] > results[j]['L']:
					continue
				if results[i]['+/-'] > results[j]['+/-']:
					sortedFiles[a], sortedFiles[b] = sortedFiles[b], sortedFiles[a]
					continue
				if results[i]['+/-'] < results[j]['+/-']:
					continue
	return sortedFiles

	

def showTourneyStandings(results, files, displayV):
	numPlayers = len(files)
	standings = {}
	for i in files:
		standings[i] = {'W':0, 'L':0, 'D':0, '+/-':0}
	for i in results.keys():
		for j in results[i].keys():
			gameResult = results[i][j]
			if gameResult == "--" or gameResult == "XX":
				continue
			gameResult = int(gameResult)
			if gameResult == 0:
				standings[i]['D'] += 1
				standings[j]['D'] += 1
			if gameResult > 0:
				standings[i]['W'] += 1
				standings[i]['+/-'] += gameResult
				standings[j]['L'] += 1
				standings[j]['+/-'] -= gameResult
			if gameResult < 0:
				standings[i]['L'] += 1
				standings[i]['+/-'] += gameResult
				standings[j]['W'] += 1
				standings[j]['+/-'] -= gameResult
	sortedFiles = sortStandings(standings, files[:]) 
	if displayV:
		print
		print "STANDINGS"
		print
		print "Player\t\tW\tL\tD\tP\t+/-"
		for i in sortedFiles:
			print i[0:7] + "\t\t" + str(standings[i]['W']) + "\t" + str(standings[i]['L']) + "\t" + str(standings[i]['D']) + "\t" + str(2*standings[i]['W']+standings[i]['D']) + "\t" + str(standings[i]['+/-'])
		print
	return standings,sortedFiles
			
def printUpcomingGames(gamesList, i, standings):
	nextGame = gamesList[i]
	player_one = nextGame['B']
	player_two = nextGame['W']
	record_one = str(standings[player_one]['W'])+"-"+str(standings[player_one]['L'])+"-"+str(standings[player_one]['D'])
	record_two = str(standings[player_two]['W'])+"-"+str(standings[player_two]['L'])+"-"+str(standings[player_two]['D'])
	print "Now playing:\t "+player_one+" ("+record_one+") \tvs.\t "+player_two+ " ("+record_two+")."
	if i < len(gamesList)-1:
		nextGame = gamesList[i+1]
		player_one = nextGame['B']
		player_two = nextGame['W']
		record_one = str(standings[player_one]['W'])+"-"+str(standings[player_one]['L'])+"-"+str(standings[player_one]['D'])
		record_two = str(standings[player_two]['W'])+"-"+str(standings[player_two]['L'])+"-"+str(standings[player_two]['D'])
		print "Next:   \t "+player_one+" ("+record_one+") \tvs.\t "+player_two+ " ("+record_two+")."
	if i < len(gamesList)-2:
		nextGame = gamesList[i+2]
		player_one = nextGame['B']
		player_two = nextGame['W']
		record_one = str(standings[player_one]['W'])+"-"+str(standings[player_one]['L'])+"-"+str(standings[player_one]['D'])
		record_two = str(standings[player_two]['W'])+"-"+str(standings[player_two]['L'])+"-"+str(standings[player_two]['D'])
		print "Soon:   \t "+player_one+" ("+record_one+") \tvs.\t "+player_two+ " ("+record_two+")."

def runTournament():
	#TOURNAMENT MODE
	system("clear")
	files = [k[:-4] for k in listdir(".") if k[-3:] == "pyc" and k[:-4] != "delegate"]
	k = 1
	print "The Players:"
	for f in files:
		print "%3d. %s" % (k, f)
		k += 1
	print
	numPlayers = len(files)
	results = {}
	for i in files:
		results[i] = {}
		for j in files:
			results[i][j] = "--"
		results[i][i] = "XX"
	standings,sortedFiles = showTourneyStandings(results, files, True)
	numGamesToPlay = numPlayers * numPlayers - numPlayers
	gamesList = []
	for i in range(numPlayers):
		for j in range(numPlayers):
			if i != j:
				gamesList.append({'B':files[i], 'W':files[j]})
	shuffle(gamesList)
	for i in range(len(gamesList)):
		printUpcomingGames(gamesList, i, standings)
		nextGame = gamesList[i]
		player_one = nextGame['B']
		player_two = nextGame['W']
		sleep(8)
		system("clear")
		module_one = __import__(player_one)
		module_two = __import__(player_two)
		module_one = reload(module_one)
		module_two = reload(module_two)
		strategies = [None, module_one, module_two]
		outfile = open("Games/" + player_one + "V" + player_two + ".ogf", "w")
		outfile.write(player_one+"\n")
		outfile.write(player_two+"\n")
		gameResult = play_one(strategies, True, outfile, player_one, player_two)

		if gameResult == 0:
			print "%s draws %s." % (player_one, player_two)
		elif gameResult > 0:
			print "%s defeats %s." % (player_one, player_two)
		elif gameResult < 0:
			print "%s defeats %s." % (player_two, player_one)

		results[player_one][player_two] = gameResult
		sleep(3)
		system("clear")
		standings,sortedFiles = showTourneyStandings(results, files, True)
	standings,sortedFiles = showTourneyStandings(results, files, False)
	standingsfile = open("TournamentResults.csv", "w")
	standingsfile.write("Program,Wins,Losses,Draws,Points,+/-\n")
	for i in sortedFiles:
		t = standings[i]
		standingsfile.write(str(i)+","+str(t['W'])+","+str(t['L'])+","+str(t['D'])+","+str(2*int(t['W'])+int(t['D']))+","+str(t['+/-'])+"\n")


def main():
	system("mkdir Games")
	if not tourney:
		system("clear")
		files = [k[:-4] for k in listdir(".") if k[-3:] == "pyc" and k[:-4] != "delegate"]
		k = 1
		print "The Players:"
		for f in files:
			print "%3d. %s" % (k, f)
			k += 1
		print
		player_one = files[int(raw_input("Black: "))-1]
		player_two = files[int(raw_input("White: "))-1]
		module_one = __import__(player_one)
		module_two = __import__(player_two)
		strategies = [None, module_one, module_two]
		outfile = open("Games/" + player_one + "V" + player_two + ".ogf", "w")
		outfile.write(player_one+"\n")
		outfile.write(player_two+"\n")
		result = play_one(strategies, True, outfile, player_one, player_two)
		if result == 0:
			print "It's a tie!"
		elif result < 0:
			print "The winner is %s." % player_two
		else:
			print "The winner is %s." % player_one
	else:
		runTournament()

	print

if __name__ == "__main__":
	main()

