Last active
May 17, 2016 10:23
-
-
Save littmus/4b119461f47287668ced to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
E4 | |
C5 | |
G4 | |
B1 | |
D7 | |
C1 | |
D5 | |
B2 | |
D4 | |
C8 | |
A1 | |
D8 | |
B1 | |
E8 | |
A2 | |
L7 | |
B2 | |
L9 | |
A15 | |
I8 | |
A13 | |
L8 | |
B14 | |
K8 | |
(4, 4) - ok | |
J2 | |
A1 | |
L2 | |
B1 | |
J4 | |
C15 | |
K3 | |
B2 | |
M5 | |
J12 | |
A1 | |
L12 | |
B1 | |
J14 | |
C15 | |
L14 | |
B2 | |
K13 | |
D2 | |
A1 | |
F2 | |
B1 | |
D4 | |
C15 | |
G5 | |
B2 | |
E3 | |
D12 | |
A1 | |
F12 | |
B1 | |
D14 | |
C1 | |
F14 | |
B2 | |
E13 | |
G7 | |
A1 | |
I7 | |
B1 | |
I9 | |
C15 | |
G9 | |
B2 | |
H8 | |
A1 | |
G2 | |
A2 | |
G4 | |
A3 | |
I2 | |
A4 | |
I4 | |
B1 | |
H3 | |
F1 | |
B6 | |
G1 | |
B8 | |
H1 | |
D6 | |
I1 | |
D8 | |
C1 | |
C7 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
import argparse | |
import time | |
import itertools | |
from subprocess import Popen, PIPE | |
import logging | |
from threading import Timer | |
import signal | |
import re | |
WHITE = '●' | |
BLACK = '○' | |
CON = ('0011100','001110','011100') | |
JUMP1 = ('00110100','0011010','0110100') | |
JUMP2 = ('00101100','0010110','0101100') | |
def mybin(n, s): | |
b=bin(n)[2:] | |
if len(b) < s: | |
b=b.zfill(s) | |
elif len(b) > s: | |
b = b[:s] | |
return b | |
def mybin2(n, s): | |
b=bin(n)[2:] | |
if len(b) < s: | |
b=b.zfill(s) | |
elif len(b) > s: | |
b = b[len(b)-s:] | |
return b | |
#mybin = lambda n,s: bin(n)[2:].zfill(s) | |
board_iter = lambda size:itertools.product(range(size), range(size)) | |
logger = logging.getLogger(__name__) | |
logger.setLevel(logging.INFO) | |
formatter = logging.Formatter('%(message)s') | |
handler = logging.FileHandler('game.log') | |
handler.setLevel(logging.INFO) | |
handler.setFormatter(formatter) | |
logger.addHandler(handler) | |
def print_board(b, size): | |
for i in b: | |
print (mybin(i, size)) | |
print() | |
def draw(n, cords, marker=None): | |
if os.name == 'posix': | |
os.system('clear') | |
else: | |
os.system('cls') | |
print(' '+' '.join([chr(d) for d in range(ord('A'), ord('A') + n)])) | |
for i, j in board_iter(n): | |
if j == 0: | |
sys.stdout.write("%2d"%(n-i)) | |
if (j, i, WHITE) in cords: | |
sys.stdout.write(WHITE) | |
elif (j, i, BLACK) in cords: | |
sys.stdout.write(BLACK) | |
else: | |
if i==0: | |
if j==0: | |
sys.stdout.write('┌') | |
elif j==n-1: | |
sys.stdout.write('┐') | |
else: | |
sys.stdout.write('┬') | |
elif i==n-1: | |
if j==0: | |
sys.stdout.write('└') | |
elif j==n-1: | |
sys.stdout.write('┘') | |
else: | |
sys.stdout.write('┴') | |
else: | |
if j==0: | |
sys.stdout.write('├') | |
elif j==n-1: | |
sys.stdout.write('┤') | |
else: | |
sys.stdout.write('┼') | |
if j == n - 1: | |
sys.stdout.write("%2d\n"%(n-i)) | |
print(' '+' '.join([chr(d) for d in range(ord('A'), ord('A') + n)])) | |
#print('x '+' '.join([str(d - ord('A')) for d in range(ord('A'), ord('A') + n)])) | |
def rotate(board, size): | |
rotate = [0]*size | |
for i, j in board_iter(size): | |
if board[i] & 2**j: | |
rotate[size-j-1] ^= 2**(size-i-1) | |
""" | |
to_rotate = [] | |
for j, i in board_iter(size): | |
if board[i] & 2**j: | |
to_rotate.append((i, j)) | |
for j, i in to_rotate: | |
rotate[size-j-1] ^= 2**(size-i-1) | |
""" | |
return rotate | |
def rotate2(board, size): | |
rotate = [[c for c in mybin(n, size)] for n in board] | |
to_rotate = [['0' for _ in range(size)] for _ in range(size)] | |
for j, i in board_iter(size): | |
if rotate[j][i] == '1': | |
to_rotate[i][j] = '1' | |
for i in range(size): | |
to_rotate[i] = int(''.join(to_rotate[i]), 2) | |
return to_rotate | |
def check_win(win, board): | |
size = len(board) | |
def check(board): | |
is_win = False | |
for j in range(size - win + 1): | |
is_win = board[j] | |
for k in range(1, win): | |
is_win = is_win & board[j+k] | |
if is_win: | |
if j > 0: | |
if is_win & board[j-1]: | |
return False | |
if j+k+1 < size: | |
if is_win & board[j+k+1]: | |
return False | |
break | |
#is_win = False | |
return is_win | |
win_vertical = check(board) | |
if win_vertical: | |
return win_vertical | |
board_rotate = rotate(board, size) | |
win_horizontal = check(board_rotate) | |
if win_horizontal: | |
return win_horizontal | |
sl_board = [0]*size | |
sr_board = [0]*size | |
for j in range(size): | |
sl_board[j] = board[j] << j | |
sr_board[j] = board[j] << (size - j - 1) | |
win_diagonal_left = check(sl_board) | |
if win_diagonal_left: | |
return win_diagonal_left | |
win_diagonal_right = check(sr_board) | |
if win_diagonal_right: | |
return win_diagonal_right | |
def open_three(x, y, board, op_board): | |
size = len(board) | |
if x == 0 or x == size-1 or y == 0 or y == size-1: | |
return False | |
r = 0 | |
#r = [0] * (4 * 3) | |
#r_near = [None] * (4 * 3) | |
whole_board = [0]*size | |
for j in range(size): | |
whole_board[j] = board[j] ^ op_board[j] | |
board_rotate = rotate(board, size) | |
whole_board_rotate = rotate(whole_board, size) | |
def check(patterns, row, wrow, pos, isnear=True): | |
if isinstance(row, int): | |
row = mybin(row, size) | |
if isinstance(wrow, int): | |
wrow = mybin(wrow, size) | |
pattern, op_pattern1, op_pattern2 = patterns | |
limit = len(pattern) - 1 | |
l = max(0, pos-limit) | |
r = min(size, pos+limit+2) | |
index = row.find(pattern, l, r) | |
if index != -1: | |
#print(patterns, pos) | |
#print(row[l:r], wrow[l:r]) | |
w1 = wrow.find(op_pattern1, l, r) | |
w2 = wrow.find(op_pattern2, l, r) | |
#print (w1, w2) | |
windex = w1 != -1 or w2 != -1 | |
if windex: | |
return True | |
#print(index, windex) | |
""" | |
if index == windex: | |
near = None | |
if isnear: | |
diff = pos - index | |
if pattern == CON: | |
if diff == 1: | |
near = (+1, +2) | |
elif diff == 2: | |
near = (-1, +1) | |
elif diff == 3: | |
near = (-2, -1) | |
elif pattern == JUMP1: | |
if diff == 1: | |
near = (+1, +3) | |
elif diff == 2: | |
near = (-1, +2) | |
elif diff == 4: | |
near = (-3, -2) | |
elif pattern == JUMP2: | |
if diff == 1: | |
near = (+2, +3) | |
elif diff == 3: | |
near = (-2, +1) | |
elif diff == 4: | |
near = (-3, -1) | |
return True | |
""" | |
return False | |
#print(mybin(board[y], size), mybin(whole_board[y], size)) | |
#print(mybin(board_rotate[x], size), mybin(whole_board_rotate[x], size)) | |
for patterns in (CON, JUMP1, JUMP2): | |
rr = check(patterns, board[y], whole_board[y], x) | |
if rr: | |
#print(patterns, 'found horizontal') | |
break | |
r += rr | |
for patterns in (CON, JUMP1, JUMP2): | |
rr = check(patterns, board_rotate[x], whole_board_rotate[x], y) | |
if rr: | |
#print(patterns, 'found vertical') | |
break | |
r += rr | |
if r >= 2: | |
return True | |
# diagonal | |
def flat_diagonal(x_, y_, b, wb): | |
diagonal_left = [] | |
whole_diagonal_left = [] | |
diagonal_right = [] | |
whole_diagonal_right = [] | |
lb = x_ + y_ # y=-x+b / | |
rb = y_ - x_ # y=x+b \ | |
crx_l = range(max(0, lb-(size-1)), min(size-1, lb)+1) | |
cry_l = range(min(size-1, lb), max(0, lb-(size-1))-1, -1) | |
for _x, _y in zip(crx_l, cry_l): | |
s = mybin(b[_y], size) | |
ws = mybin(wb[_y], size) | |
diagonal_left.append(s[_x]) | |
whole_diagonal_left.append(ws[_x]) | |
diagonal_left = ''.join(diagonal_left) | |
whole_diagonal_left = ''.join(whole_diagonal_left) | |
crx_r = range(max(0, 0-rb), min(size-1, size-1-rb)+1) | |
cry_r = range(max(0, 0+rb), min(size-1, size-1+rb)+1) | |
for _x, _y in zip(crx_r, cry_r): | |
s = mybin(b[_y], size) | |
ws = mybin(wb[_y], size) | |
diagonal_right.append(s[_x]) | |
whole_diagonal_right.append(ws[_x]) | |
diagonal_right = ''.join(diagonal_right) | |
whole_diagonal_right = ''.join(whole_diagonal_right) | |
adjusted_lx = x_ | |
adjusted_rx = x_ | |
if x_ + y_ > size - 1: | |
adjusted_lx = x_ - (lb - (size - 1)) | |
if x_ > y_: | |
adjusted_rx = x_ + rb | |
return diagonal_left, whole_diagonal_left, diagonal_right, whole_diagonal_right, adjusted_lx, adjusted_rx | |
dl, wdl, dr, wdr, lx, rx = flat_diagonal(x, y, board, whole_board) | |
#print(dl, wdl) | |
#print(dr, wdr) | |
for patterns in (CON, JUMP1, JUMP2): | |
rr = check(patterns, dl, wdl, lx) | |
if rr: | |
#print(patterns, 'found left diag') | |
break | |
r += rr | |
if r >= 2: | |
return True | |
for patterns in (CON, JUMP1, JUMP2): | |
rr = check(patterns, dr, wdr, rx) | |
if rr: | |
#print(patterns, 'found right diag') | |
break | |
r += rr | |
if r >= 2: | |
return True | |
""" | |
if sum(r) == 1: # 다른 pos에서 완성이 될 수 있는 경우 | |
for i in range(3 * 4): | |
if r_near[i]: | |
for nx, ny in r_near[i]: | |
rr = False | |
if i != 0: | |
rr, near = check(CON, board[ny], whole_board[ny], nx, False) | |
if rr: return True | |
if i != 1: | |
rr, near = check(CON, board_rotate[nx], whole_board_rotate[nx], ny, False) | |
if rr: return True | |
if i != 2: | |
rr, near = check(JUMP1, board[ny], whole_board[ny], nx, False) | |
if rr: return True | |
if i != 3: | |
rr, near = check(JUMP1, board_rotate[nx], whole_board_rotate[nx], ny, False) | |
if rr: return True | |
if i != 4: | |
rr, near = check(JUMP2, board[ny], whole_board[ny], nx, False) | |
if rr: return True | |
if i != 5: | |
rr, near = check(JUMP2, board_rotate[nx], whole_board_rotate[nx], ny, False) | |
if rr: return True | |
dl, wdl, dr, wdr, lx, rx = flat_diagonal(nx, ny, board, whole_board) | |
if i != 6: | |
rr, near = check(CON, dl, wdl, lx, False) | |
if rr: return True | |
if i != 7: | |
rr, near = check(JUMP1, dl, wdl, lx, False) | |
if rr: return True | |
if i != 8: | |
rr, near = check(JUMP2, dl, wdl, lx, False) | |
if rr: return True | |
if i != 9: | |
rr, near = check(CON, dr, wdr, rx, False) | |
if rr: return True | |
if i != 10: | |
rr, near = check(JUMP1, dr, wdr, rx, False) | |
if rr: return True | |
if i != 11: | |
rr, near = check(JUMP2, dr, wdr, rx, False) | |
if rr: return True | |
""" | |
return False | |
def exit_game(loser): | |
loser.kill() | |
print(str(loser), 'Lose') | |
os.kill(os.getpid(), signal.SIGTERM) | |
def readline_timeout(player, timeout): | |
t = Timer(timeout, exit_game, [player]) | |
t.start() | |
r = player.stdout.readline() | |
t.cancel() | |
if t.isAlive(): | |
return r | |
else: | |
return None | |
def main(args): | |
p1 = args.p1 | |
p2 = args.p2 | |
size = args.n | |
win_condition = args.w | |
if size < win_condition: | |
print('Invalid Game!') | |
return | |
cords = set() | |
p1_board = [0]*size | |
p2_board = [0]*size | |
draw(size, cords) | |
if p1 != 'human': | |
p1 = Popen(p1, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True, bufsize=1, shell=True) | |
#p1 = Popen(' '.join([p1, "-n", str(size), "-w", str(win_condition)]), stdin=PIPE, stdout=PIPE, universal_newlines=True, bufsize=1, shell=True) | |
if p2 != 'human': | |
p2 = Popen(p2, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True, bufsize=1, shell=True) | |
else: | |
p2 = 'human2' | |
timer = {p1:0., p2:0.} | |
_x, _y = -1, -1 | |
win = None | |
first = True | |
for player, marker, board, op_board in itertools.cycle([(p1, BLACK, p1_board, p2_board), (p2, WHITE, p2_board, p1_board)]): | |
failed = False | |
while True: | |
start = time.time() | |
if player == 'human' or player == 'human2': | |
if first: | |
first = False | |
r = input("Input position : ") | |
else: | |
if first: | |
print ("START", file=player.stdin, flush=True) | |
first = False | |
else: | |
print('%c%d'%(_x+ord('A'), size - _y), file=player.stdin, flush=True) #send | |
r = player.stdout.readline() | |
#r = readline_timeout(player, 1) | |
elapsed = time.time() - start | |
if player not in ['human', 'human2'] and elapsed > 1 + 0.05: # 랙 고려 | |
failed = True | |
print('Time out') | |
break | |
timer[player] += elapsed | |
try: | |
x = ord(r[0]) - ord('A') | |
y = size - int(r[1:]) | |
if x not in range(size) or y not in range(size): | |
raise Exception | |
if (x,y,WHITE) in cords or (x,y,BLACK) in cords: | |
print('You can not input there ', r) | |
failed = True | |
else: | |
cords.add((x,y,marker)) | |
draw(size, cords) | |
board[y] ^= 2**(size-x-1) | |
_x, _y = x, y | |
break | |
except: | |
print('Invalid input : ', r) | |
failed = True | |
break | |
if failed: | |
win = BLACK if marker == WHITE else WHITE | |
break | |
if check_win(win_condition, board): | |
win = marker | |
break | |
elif len(cords) == size**2: | |
print ('DRAW') | |
break | |
elif len(cords) > 8: | |
failed = open_three(_x, _y, board, op_board) | |
if failed: | |
print('3*3 DETECTED!') | |
win = BLACK if marker == WHITE else WHITE | |
break | |
print(win, 'WIN') | |
logger.info('TIME - P1 {} / P2 {}'.format(timer[p1], timer[p2])) | |
#print('TIME - P1 {} / P2 {}'.format(timer[p1], timer[p2])) | |
logger.info('winner : {}'.format('BLACK' if win == BLACK else 'WHITE')) | |
return | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-n', type=int, default=15) | |
parser.add_argument('-w', type=int, default=5) | |
parser.add_argument('p1', type=str, default=None) | |
parser.add_argument('p2', type=str, default=None) | |
args = parser.parse_args() | |
main(args) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
import sys | |
import time | |
import argparse | |
import copy | |
import itertools | |
import logging | |
logger = logging.getLogger(__name__) | |
logger.setLevel(logging.INFO) | |
handler = logging.FileHandler('player.log') | |
handler.setLevel(logging.INFO) | |
formatter = logging.Formatter('%(message)s') | |
handler.setFormatter(formatter) | |
logger.addHandler(handler) | |
mybin = lambda n,s: bin(n)[2:].zfill(s) | |
conv = lambda x,y,size: "%c%d" % (chr(x + ord('A')), size-y) | |
board_iter = lambda size:itertools.product(range(size), range(size)) | |
bit = lambda n, k:(n & 2**k) != 0 | |
def print_board(b, size): | |
for i in range(size): | |
logger.info ('%2d %s'%(size-i, mybin(b[i], size))) | |
logger.info(' '+''.join([str(d+1) for d in range(size)])) | |
def check_open_three(board, size, x, y): | |
if x == 0 or x == size - 1 or y == 0 or y == size - 1: | |
return False | |
test_board = copy.deepcopy(board) | |
# case 1 | |
test_board[y] ^= 2**(size-x-1) | |
print_board(test_board, size) | |
""" | |
가로에 2개 | |
010 010 | |
010 1x1 | |
1x1 010 | |
""" | |
row = test_board[y] | |
horizontal = 0 | |
vertical = 0 | |
for i in range(max(0, x-2), min(x+1, size-2)): | |
x1 = bit(row, size-i-1) | |
x2 = bit(row, size-i-2) | |
x3 = bit(row, size-i-3) | |
logger.info('{} hor : {} {} {}'.format(i, x1, x2, x3)) | |
b = x1 & x2 & x3 | |
if b: | |
horizontal = i + 1 | |
y = size - y - 1 | |
for j in range(max(0, y-2), min(y+1, size-2)): | |
y1=bit(test_board[size-j-1], size-x-1) | |
y2=bit(test_board[size-j-2], size-x-1) | |
y3=bit(test_board[size-j-3], size-x-1) | |
logger.info('{} ver : {} {} {}'.format(size-j, y1, y2, y3)) | |
b = y1 & y2 & y3 | |
if b: | |
vertical = j + 1 | |
logger.info('hor : %d / ver : %d' % (horizontal, vertical)) | |
if horizontal and vertical: | |
# 가로 세로 삼삼 | |
return True | |
if x not in [0, size-1] and y not in [0, size - 1]: | |
diagonal_left = 0 | |
diagonal_right = 0 | |
left_up = bit(test_board[y-1], ) | |
left_down = bit(test_board[y+1], ) | |
right_up = bit(test_board[y-1], ) | |
right_down = bit(test_board[y+1], ) | |
def check_win(size, win, board): | |
def check(board): | |
is_win = False | |
for j in range(size - win + 1): | |
is_win = board[j] | |
for k in range(1, win): | |
is_win = is_win & board[j+k] | |
if is_win: | |
break | |
is_win = False | |
return is_win | |
win_vertical = check(board) | |
if win_vertical: | |
return win_vertical | |
rotate = [0]*size | |
for i, j in board_iter(size): | |
#if board[i] & 2**j: | |
if bit(board[i], j): | |
rotate[size-j-1] ^= 2**(size-i-1) | |
win_horizontal = check(rotate) | |
if win_horizontal: | |
return win_horizontal | |
sl_board = [0]*size | |
sr_board = [0]*size | |
for j in range(size): | |
sl_board[j] = board[j] << j | |
sr_board[j] = board[j] << (size - j - 1) | |
#print_board(sl_board, size) | |
#print_board(sr_board, size) | |
win_diagonal_left = check(sl_board) | |
if win_diagonal_left: | |
return win_diagonal_left | |
win_diagonal_right = check(sr_board) | |
if win_diagonal_right: | |
return win_diagonal_right | |
def score(my_board, op_board): | |
if check_win(my_board): | |
return 10 | |
elif check_win(op_board): | |
return -10 | |
else: | |
return 0 | |
def main(args): | |
logger.info("New Game START================\n") | |
size = args.n | |
win = args.w | |
board = set() | |
my_board = [0]*size | |
op_board = [0]*size | |
def play(m_board, o_board): | |
lose_candidate = [] | |
for i, j in board_iter(size): | |
if (i, j) not in board: | |
copy_my_board = copy.deepcopy(m_board) | |
copy_my_board[j] ^= 2**(size-i-1) | |
#print_board(copy_my_board, size) | |
#print_board(copy_op_board, size) | |
if check_win(size, win, copy_my_board): | |
logger.info('i win if ' + conv(i, j, size) + ' %d %d' % (j, i)) | |
#win_candidate.append((i,j)) | |
return (i,j) | |
copy_op_board = copy.deepcopy(o_board) | |
copy_op_board[j] ^= 2**(size-i-1) | |
if check_win(size, win, copy_op_board): | |
logger.info('op win if ' + conv(i, j, size) + ' %d %d' % (j, i)) | |
lose_candidate.append((i,j)) | |
if lose_candidate: | |
return lose_candidate[0] | |
while True: | |
x = random.randint(0, size-1) | |
y = random.randint(0, size-1) | |
if (x, y) not in board: | |
break | |
return (x, y) | |
while True: | |
r = input() | |
logger.info('op : ' + r) | |
if r != 'START': | |
try: | |
x = ord(r[0]) - ord('A') | |
y = size - int(r[1:]) | |
except: | |
print(r) | |
break | |
#check_open_three(op_board, size, x, y) | |
op_board[y] ^= 2**(size-x-1) | |
board.add((x,y)) | |
x, y = play(my_board, op_board) | |
my_board[y] ^= 2**(size-x-1) | |
board.add((x,y)) | |
output = conv(x, y, size) | |
print(output) | |
logger.info('I : ' + output) | |
#check_open_three(my_board, size, x, y) | |
logger.info('\n') | |
return | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-n', type=int, default=15) | |
parser.add_argument('-w', type=int, default=5) | |
#parser.add_argument('-d', type=int, default=0) | |
args = parser.parse_args() | |
main(args) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from threading import Timer | |
def input_timeout(timeout): | |
t = Timer(timeout, print, ['Timeout!']) | |
t.start() | |
r = input() | |
t.cancel() | |
if t.isAlive(): | |
return r | |
else: | |
return None | |
r = input_timeout(1) | |
print(r) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment