Python 2: 399 401 349 333 317 370 bytes
2x Correção de bug: crédito em l4m2
-52 caracteres: crédito para undergroundmonorail
-16 caracteres: crédito para Jonathan Frech
-26 caracteres: crédito para o usuário202729
def f(b):
t=4,9,2,3,5,7,8,1,6;n=lambda k:[t[i]for i,j in enumerate(b)if j==k];p,o,a,I=n(2),n(1),n(0),t.index
for i in p:
for j in p:
for k in a:
if i+j+k==15and-j+i:return I(k)
for i in o:
for j in o:
for k in a:
if i+j+k==15and-j+i:return I(k)
for i in 9,3,7,1:
if i in a and 5 in p:return I(i)
for i in 5,4,2,8,6:
if i in a:return I(i)
return I(a[0])
Experimente Online!
No primeiro dia de um curso de álgebra linear que fiz no semestre passado, meu astuto instrutor de pós-graduação propôs que, se você representa a placa do jogo da velha como matriz:
4 | 9 | 2
--+---+--
3 | 5 | 7
--+---+--
8 | 1 | 6
então, obter três em linha é equivalente a escolher três números no intervalo [1,9] que somam 15. Essa resposta explora essa idéia. A função pega uma lista contendo nove números que representam o quadro. 0 indica um espaço vazio, 1 é ocupado pelo oponente e 2 representa uma jogada anterior feita pelo programa. As três primeiras linhas descobrem quais números o programa selecionou (p), a oposição selecionou (o) e ainda estão disponíveis (a). Em seguida, ele examina os números disponíveis e vê se algum deles, combinado com dois números que já escolheu, somados a quinze. Se isso acontecer, ele escolherá o quadrado e vencerá. Se não houver jogadas vencedoras imediatas, ele verificará se o oponente pode ganhar usando o mesmo método. Se puderem, será o quadrado vencedor. Se não houver um movimento vencedor ou de bloqueio disponível, ele se moverá em um canto. Isso evita que os tolos acasalem:
- - -
- X -
- - -
- O - # Bad Move
- X -
- - -
- O X
- X -
- - -
- O X
- X -
O - -
- O X
- X -
O - X
Se nenhuma dessas situações ocorrer, ele escolherá um quadrado arbitrariamente. A função gera um número [0,8] representando o quadrado indexado 0 escolhido pelo algoritmo.
Edit: O algoritmo agora prioriza o centro sobre a diagonal, o que impedirá outra possibilidade de acasalamento apontada por l4m2 e estratégias relacionadas.
Editar: para esclarecer, a função recebe uma placa na forma de uma matriz e gera um movimento como um número inteiro em [0,8]. Como essa estratégia de E / S é tão desajeitada, aqui está um script de wrapper que a torna mais interativa. É necessário um único argumento de linha de comando, que deve ser 1 se o jogador for o primeiro e 0 se o programa for o primeiro.
import sys
def f(b):
t=4,9,2,3,5,7,8,1,6;n=lambda k:[t[i]for i,j in enumerate(b)if j==k];p,o,a,I=n(2),n(1),n(0),t.index
for i in p:
for j in p:
for k in a:
if i+j+k==15and-j+i:return I(k)
for i in o:
for j in o:
for k in a:
if i+j+k==15and-j+i:return I(k)
for i in 9,3,7,1:
if i in a and 5 in p:return I(i)
for i in 5,4,2,8,6:
if i in a:return I(i)
return I(a[0])
board = [0,0,0,0,0,0,0,0,0]
rep = {0:"-",1:"X",2:"O"}
turn = int(sys.argv[1])
while True:
for i in range(3):
print rep[board[i*3]]+" "+rep[board[i*3+1]]+" "+rep[board[i*3+2]]
print
if turn:
move = int(raw_input("Enter Move [0-8]: "))
else:
move = f(board)
board[move] = turn+1
turn = (turn+1)%2
we can assume that all previous moves of the 2nd player were also played by our engine