Hmm. Um dos pontos que regulam a atuação dos moderadores no Habré é formulado da seguinte forma: você não deve pular artigos que tenham pouca ou nenhuma relação com temas de informática. O que imediatamente fez o autor pensar se sua postagem, que fala sobre alguns estágios da programação de seu projeto de estimação engraçado e empolgante, uma IA simples, que constrói uma rede neural baseada no envoltório de rubi FANN para jogar cruzes, está diretamente relacionada aos zeros do "tópico de TI"? A pergunta não contém coquetismo oculto, porque a descrição da lógica do código do programa em minha história está longe de ser de suma importância. "Sim, isso é uma ironia do mal!" - você diz. - Não sei.
OK. Este desenvolvimento é, de fato, uma ilustração de uma série de observações estranhas do autor, uma série de conhecidos e até amigos-amigos dos quais nos últimos anos ... o fizeram relembrar as lições de literatura de uma vez, quando ele era muito, muito escola secundária soviética. Apesar de sua convicção permanente de que sempre é possível "passar" apenas por alguma coisa, certos personagens dos clássicos russos são lembrados cada vez mais com o tempo. Ou talvez devesse ser assim?
Então, logo de cara ... após o primeiro lançamento, o programa inicia o processo de autoaprendizagem, jogando consigo mesmo várias dezenas (um minuto - dois no máximo) de milhares de jogos (o número, claro, está disponível para edição na configuração; dado o algoritmo não muito comum descrito abaixo, subjacente à lógica desta IA (experimentos desse tipo também podem fornecer material interessante para inferências). Simula o processo de aprendizagem inerente a muitas outras Inteligências Artificiais, com a única diferença de que ambos os "jogadores" igualmente não sabem jogar, fazendo jogadas absolutamente aleatórias. Mas as regras do jogo se aplicam: se o movimento aleatório não coincidir, o programa deve prosseguir e, portanto, o lado vencedor irá para o lado vencedor. Tudo é justo: sem rasuras e hacks, sem preferências ocultas,sem testes de doping falsos para você, que muitas vezes anulam os resultados dos jogos esportivos na vida real.
Em seguida, o jogo começa com o usuário: o protocolo do jogo registrado em um arquivo csv é convertido em um array, e a IA jogando com o segundo número (zeros) resolve um problema filosófico, estranhamente muito russo, tentando extrair o absurdo e o caos dos movimentos aleatórios que lhe permitirão ganhar ou pelo menos reduzir a um empate um jogo com um adversário vivo e de pensamento bastante lógico.
, ? , : , . , , (, - "") : "" , ... , , .
- , ( ), - . - ... , - , , .
. : , . , , , , , , , : (/). -, Tic Tac Toe - , - ? - , . , , , , - , , ?... , "" ; , " " , - " ", , " !".
, Artificial Intelligence. , 3x3, -, ? , , , , , , , - , ? AI, " " ; - , .
, " ". () , , - . ? , :
if row[6].to_i - row[3].to_i == 1
x_data.push([row[0].to_i])
y_data.push([1]) # , .. , .
end
? - . , .. . ?
, Tic Tac Toe AI with Neural Network ( ). , – : , – – . , , , .
, , - , , . , , , ... ?
. “"... , ? – , , : “ , , ”. , “ ” ; , “ ”. , , ; , . , , , , , , , , : , “ , ”.
. , , , . , , - , ... , - , , , .
- ( - life style). , :
WINNING_TRIADS = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[6, 4, 2],
[0, 4, 8]
].freeze
, csv- , :
def fork?
WINNING_TRIADS.select do |x|
@board[x[0]] == @board[x[1]] && @board[x[2]].class != @board[x[0]].class &&
place_x?(x[0]) ||
@board[x[1]] == @board[x[2]] && @board[x[0]].class != @board[x[2]].class &&
place_x?(x[1]) ||
@board[x[0]] == @board[x[2]] && @board[x[1]].class != @board[x[2]].class &&
place_x?(x[0])
end
end
, ...
if @game.fork?.size > 1
... .
, . : , , , . , .
:
DANGEROUS_SITUATIONS_1 = [
[6, 4, 2],
[0, 4, 8]
].freeze
DANGEROUS_SITUATIONS_2 = [
[0, 4, 7],
[0, 4, 5],
[2, 4, 3],
[2, 4, 7],
[3, 4, 8],
[1, 4, 8],
[1, 4, 6],
[5, 4, 6]
].freeze
def fork_danger_1?
DANGEROUS_SITUATIONS_1.detect do |x|
@board[x[0]] == @board[x[2]] &&
@board[x[0]] != @board[x[1]]
end
end
def fork_danger_2?
DANGEROUS_SITUATIONS_2.detect do |x|
@board[x[0]] == @board[x[2]] &&
@board[x[0]] != @board[x[1]]
end
end
def fork_danger_3?
DANGEROUS_SITUATIONS_1.detect do |x|
@board[x[0]] != @board[x[2]] &&
@board[x[1]] == @board[x[2]]
end
end
, , , , , AI : 1. , 2. 3. (.. , , , ). , , . , Neural Network.
array_of_games.each do |row|
row.each do |e|
next unless e == current_position
if row[6].to_i - row[3].to_i == 2 && row[4] == 'O' && row[2].to_f != 0.2
unacceptable_moves_array << row[0]
# Find moves that inevitably lead to a fork:
elsif fork_danger_1 && row[3].to_i == 3 && row[0].to_i.odd?
unacceptable_moves_array << row[0]
elsif (fork_danger_2 || fork_danger_3) && row[3].to_i == 3 && row[0].to_i.even?
unacceptable_moves_array << row[0]
end
next if row[5].nil?
# Find moves that may lead to a fork:
array_of_moves_to_fork << row[0] if row[3].to_i == row[5].to_i
# Find attacking moves:
attack_moves_array << row[0] if row[3].to_i == row[5].to_i && row[6].to_i < 7
end
end
, , , AI , . ... , , , , ... , "" . , , - , , ... ? - ", , ", .
array_of_games.each do |row|
row.each do |e|
next unless e == current_position
next if arrays[0].include?(row[0])
unless arrays[1].include?(row[0]) && !arrays[2].include?(row[0])
if row[6].to_i - row[3].to_i == 1
x_data.push([row[0].to_i])
y_data.push([1])
elsif row[6].to_i - row[3].to_i == 3
if arrays[2].include?(row[0])
x_data.push([row[0].to_i])
y_data.push([0.9])
elsif arrays[1].include?(row[0])
x_data.push([row[0].to_i])
y_data.push([0.3])
end
else
x_data.push([row[0].to_i])
y_data.push([row[2].to_f])
end
end
end
:
data = nn_data(board, fork_danger_1, fork_danger_2, fork_danger_3, array_of_games)
fann_results_array = []
train = RubyFann::TrainData.new(inputs: data[0], desired_outputs: data[1])
model = RubyFann::Standard.new(
num_inputs: 1,
hidden_neurons: [4],
num_outputs: 1
)
model.train_on_data(train, 5000, 500, 0.01)
data[0].flatten.each do |i|
fann_results_array << model.run([i])
end
result = data[0][fann_results_array.index(fann_results_array.max)]
: ( csv-) Neural Network .
- , - , . csv- ( , ), . , - - , , .
PS O código descrito está sempre disponível na íntegra (e não de forma fragmentada, como o formato do artigo dita) no meu github , é claro, qualquer um pode fazer um clone do git e experimentar o código, ou apenas jogar. Não sou adepto da execução do aplicativo ruby no Windows, não é uma ideia muito boa, mas neste caso funcionará, experimentei. Talvez seja um pouco menos impressionante do que no console do Linux, mas a lógica funcionará.