Last active
October 3, 2016 14:37
-
-
Save hugsy/d1fbc225c05b9191c951 to your computer and use it in GitHub Desktop.
VolgaCTF 2016 - TicTacToe (PPC 200)
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
#!/usr/bin/env python2 | |
# | |
# VolgaCTF 2016 - TicTacToe (PPC 200) | |
# | |
# @_hugsy_ | |
# $ ./tic-tac-toe.py | |
# [...] | |
# Blocking computer in 5 with X | |
# Declaring draw for round=500 | |
# Starting new round 500 | |
# Congratulations! Your flag is: VolgaCTF{tic_t@c_t0e_is_the_e@rly_step_t0wards_AI} | |
import telnetlib | |
HOST = "tic-tac-toe.2016.volgactf.ru" | |
PORT = 45679 | |
def build_socket(host, port): | |
s = telnetlib.Telnet(HOST, PORT) | |
print("Connected to %s:%d" % (host, port)) | |
return s | |
def get_configuration(s): | |
blocks = [] | |
for i in range(3): | |
line = s.read_until("\n").replace('\n', '') | |
for part in line.split("|"): | |
blocks.append( part.strip() ) | |
line = s.read_until("\n").replace('\n', '') | |
return blocks | |
def is_free(b): | |
return b == '' | |
def has_lost_setup(cfg, cpu): | |
return ( (cfg[0]==cpu and cfg[1]==cpu and cfg[2]==cpu) # horizontal | |
or (cfg[3]==cpu and cfg[4]==cpu and cfg[5]==cpu) | |
or (cfg[6]==cpu and cfg[7]==cpu and cfg[8]==cpu) | |
or (cfg[0]==cpu and cfg[3]==cpu and cfg[6]==cpu) # vertical | |
or (cfg[1]==cpu and cfg[4]==cpu and cfg[7]==cpu) | |
or (cfg[2]==cpu and cfg[5]==cpu and cfg[8]==cpu) | |
or (cfg[0]==cpu and cfg[4]==cpu and cfg[8]==cpu) # diagonale | |
or (cfg[2]==cpu and cfg[4]==cpu and cfg[6]==cpu) # diagonale | |
) | |
def block_attack(cfg, cpu): | |
# horizontal | |
if (cfg[0]==cpu and is_free(cfg[1]) and cfg[2]==cpu): return 1 | |
if (cfg[3]==cpu and is_free(cfg[4]) and cfg[5]==cpu): return 4 | |
if (cfg[6]==cpu and is_free(cfg[7]) and cfg[8]==cpu): return 7 | |
# vertical | |
if (cfg[0]==cpu and is_free(cfg[3]) and cfg[6]==cpu): return 3 | |
if (cfg[1]==cpu and is_free(cfg[4]) and cfg[7]==cpu): return 4 | |
if (cfg[2]==cpu and is_free(cfg[5]) and cfg[8]==cpu): return 5 | |
# diagonal | |
if (cfg[0]==cpu and is_free(cfg[4]) and cfg[8]==cpu): return 4 | |
if (cfg[2]==cpu and is_free(cfg[4]) and cfg[6]==cpu): return 4 | |
# horizontal | |
if (cfg[0]==cpu and cfg[1]==cpu and is_free(cfg[2]) ): return 2 | |
if (cfg[3]==cpu and cfg[4]==cpu and is_free(cfg[5]) ): return 5 | |
if (cfg[6]==cpu and cfg[7]==cpu and is_free(cfg[8]) ): return 8 | |
if (cfg[2]==cpu and cfg[1]==cpu and is_free(cfg[0]) ): return 0 | |
if (cfg[5]==cpu and cfg[4]==cpu and is_free(cfg[3]) ): return 3 | |
if (cfg[8]==cpu and cfg[7]==cpu and is_free(cfg[6]) ): return 6 | |
#vertical | |
if (cfg[0]==cpu and cfg[3]==cpu and is_free(cfg[6]) ): return 6 | |
if (cfg[1]==cpu and cfg[4]==cpu and is_free(cfg[7]) ): return 7 | |
if (cfg[2]==cpu and cfg[5]==cpu and is_free(cfg[8]) ): return 8 | |
if (cfg[6]==cpu and cfg[3]==cpu and is_free(cfg[0]) ): return 0 | |
if (cfg[7]==cpu and cfg[4]==cpu and is_free(cfg[1]) ): return 1 | |
if (cfg[8]==cpu and cfg[5]==cpu and is_free(cfg[2]) ): return 2 | |
#diagonal | |
if (cfg[0]==cpu and cfg[4]==cpu and is_free(cfg[8]) ): return 8 | |
if (cfg[6]==cpu and cfg[4]==cpu and is_free(cfg[2]) ): return 2 | |
if (cfg[8]==cpu and cfg[4]==cpu and is_free(cfg[0]) ): return 0 | |
if (cfg[2]==cpu and cfg[4]==cpu and is_free(cfg[6]) ): return 6 | |
return -1 | |
def is_winning_setup(cfg, me): | |
return block_attack(cfg, me) | |
def get_nb_busy(c): | |
n = 0 | |
for i in range(len(c)): | |
if not is_free(c[i]): | |
n+=1 | |
return n | |
def is_draw(c): | |
return get_nb_busy(c) == 9 | |
def pprint(cfg): | |
for i in range(0,9,3): | |
line = "| " | |
for j in range(3): | |
line += cfg[i+j] if cfg[i+j]!='' else ' ' | |
line += " | " | |
print(line) | |
print('') | |
return | |
def start_game(s): | |
print("Starting game") | |
for i in range(2000): | |
print("Starting new round %d" % i) | |
new_round(s) | |
return | |
def new_round(s): | |
rnd = s.read_until("\n").strip() | |
if "Final score:" in rnd: | |
while True: | |
print s.read_until("\n") | |
exit(0) | |
rnd = rnd.split()[2][:-1] | |
rnd = int(rnd) | |
score = s.read_until("\n").strip().split()[5:] | |
print("Score (cpu/me): %s" % ' '.join(score)) | |
is_first_move = True | |
computer_starts_first = False | |
computer = None | |
while True: | |
cfg = get_configuration(s) | |
print("Current configuration:") | |
pprint(cfg) | |
if is_first_move: | |
for b in cfg: | |
if len(b)=='': continue | |
if b in ('X', 'O'): | |
computer = b | |
me = 'O' if computer=='X' else 'X' | |
computer_starts_first = True | |
break | |
if computer is None: | |
computer_starts_first = False | |
computer = 'O' | |
me = 'X' | |
if computer_starts_first: | |
print("Computer starts first round=%d with %c" % (rnd, computer)) | |
else: | |
print("Player starts first round=%d with %c" % (rnd, computer)) | |
is_first_move = False | |
ret = is_winning_setup(cfg, me) | |
if ret >= 0: | |
# make winning move, and return | |
print("Winning round=%d" % rnd) | |
s.write("%d\n" % ret) | |
return | |
ret = block_attack(cfg, computer) | |
if ret >= 0: | |
print("Blocking computer in %d with %c" % (ret, me)) | |
s.write("%d\n" % ret) | |
if get_nb |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment