📄 ox.cxx
字号:
/* * Neural Net Noughts and Crosses (Tic Tac Toe if you're American) * * Adrian Bowyer * A.Bowyer@bath.ac.uk * * 10 July 2001 * * This uses the neural net library libneural by Daniel Franklin */// This program learns to play noughts and crosses by watching what you do// when you play against it. So don't make any mistakes...// It, and then you, start alternately. When a game is over it asks you// if you want to play again - say y to play again; if you say n it will// save what its learned and you will get a chance to load it back next time.#include <iostream.h>#include <nnwork.h>#define OH 0.5 // Value for an O#define EX 1.0 // Value for an X#define SP 0.0 // Value for space#define EPS 0.1 // Epsilon for floating-point comparisonsfloat board[9]; // The 9 squares of the boardnnwork ox(9,18,9); // The network// Return the value at the i-th row and j-th columnfloat bd_val(int i, int j){ return(board[i*3 + j]);}// Return the equivalent character at the i-th row and j-th columnchar bd_char(int i, int j){ float v = bd_val(i, j); if(v < SP + EPS) return(' '); if(v < OH + EPS) return('O'); return('X');}// Take the board, and change each O to X (and vice versa) into bdvoid swap(float bd[]){ for(int i = 0; i < 9; i++) { if(board[i] < SP + EPS) bd[i] = SP; else if(board[i] < OH + EPS) bd[i] = EX; else bd[i] = OH; }} // Print the state of play, with a reminder for square// numbers at the leftvoid print(){ cout << '\n'; for(int i = 0; i < 3; i++) { cout << " | | | |\n"; for(int j = 0; j < 3; j++) { cout << ' ' << i*3 + j << ' '; if(j != 2) cout << '|'; } cout << " "; for(int j = 0; j < 3; j++) { cout << ' '; cout << bd_char(i,j); cout << ' '; if(j != 2) cout << '|'; } cout << "\n | | | |\n"; if(i != 2) cout << "____________ ____________\n"; } cout << endl;}// Check for game over; if not the number of occupied squares// is returned; if someone's won it returns 'O' or 'X' as appropriate// (NB ASCII 'O' and 'X' are > 9)int done(){ int result = 0; // How many non-blank squares? for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) if(bd_char(i, j) != ' ') result++; if(result < 3) return(result); // can't win with < 3 squares full // Ckeck the winning patterns; could probably be cleverer here... if(bd_char(0, 0) != ' ') { if((bd_char(0, 0) == bd_char(0, 1)) && (bd_char(0, 0) == bd_char(0, 2))) return(bd_char(0, 0)); if((bd_char(0, 0) == bd_char(1, 1)) && (bd_char(0, 0) == bd_char(2, 2))) return(bd_char(0, 0)); if((bd_char(0, 0) == bd_char(1, 0)) && (bd_char(0, 0) == bd_char(2, 0))) return(bd_char(0, 0)); } if(bd_char(0, 1) != ' ') if((bd_char(0, 1) == bd_char(1, 1)) && (bd_char(0, 1) == bd_char(2, 1))) return(bd_char(0, 1)); if(bd_char(0, 2) != ' ') { if((bd_char(0, 2) == bd_char(1, 1)) && (bd_char(0, 2) == bd_char(2, 0))) return(bd_char(0, 2)); if((bd_char(0, 2) == bd_char(1, 2)) && (bd_char(0, 2) == bd_char(2, 2))) return(bd_char(0, 2)); } if(bd_char(1, 0) != ' ') if((bd_char(1, 0) == bd_char(1, 1)) && (bd_char(1, 0) == bd_char(1, 2))) return(bd_char(1, 0)); if(bd_char(2, 0) != ' ') if((bd_char(2, 0) == bd_char(2, 1)) && (bd_char(2, 0) == bd_char(2, 2))) return(bd_char(2, 0)); return(result);}// Put c into square lvoid move(int l, char c){ switch(c) { case ' ': board[l] = SP; break; case 'O': board[l] = OH; break; case 'X': board[l] = EX; break; default: cerr << "Dud move character\n"; }}// User makes a movevoid user_move(){ if(done() >= 9) return; // Can we play? float bd[9], op[9]; // Board position and desired output int l, p; print(); cout << "Your move, X, (type square number): "; cin >> p; // Assume the user knows what he or she is doing... // Weight all outputs other than the selected one low for(l = 0; l < 9; l++) op[l] = 0.05; op[p] = 0.95; // Swap all board O for X and all X for O into bd swap(bd); // For a board looking like bd, play p (i.e. pattern in op) ox.train(bd, op, 0.0001, 0.2); // Make the move move(p, 'X');}// Sort indices to array op in iop (decending)// Nasty bubble sort, but there are only 9 entriesvoid sort(float op[], int iop[]){ int i, j, k; for(i = 0; i < 9; i++) iop[i] = i; for(i = 0; i < 8; i++) for(j = i+1; j < 9; j++) if(op[iop[i]] < op[iop[j]]) { k = iop[i]; iop[i] = iop[j]; iop[j] = k; }}// Network makes a movevoid network_move(){ if(done() >= 9) return; // Can we play? float op[9]; // Desired output int iop[9]; // Index array float mx; // maximum output value int l, r; // working integers // Get the network's move in op ox.run(board, op); // Sort indices to op sort(op, iop); // Find the maximum free entry l = 0; do { r = iop[l]; // Check if the space is free... if (bd_char(r/3, r%3) != ' ') r = -1; l++; } while((r < 0) && (l < 9)); if(r < 0) cerr << "network_move(): no free squares\n"; move(r, 'O');}// Play games in a loopvoid games(){ int i, k; // Working integers char c = 'y'; // User's response int count = 0; // Game count while((c == 'y') || (c == 'Y')) // c == 'y' when the user says to play again { // Clear the board for(i = 0; i < 9; i++) move(i, ' '); // Play a game do { if(count%2) // User starts odd numbered games user_move(); // Let the network make a move network_move(); if(!(count%2)) // Network plays first on even-numbered games user_move(); } while((k = done()) < 9); // Keep going while game live // Print the final position print(); // Increment game count count++; cout << "Game " << count << ". "; // Say who's won if(k == 'X') cout << "You win! "; else if(k == 'O') cout << "I win! "; else cout << "Draw. "; // Play again? cout << " Another game? "; cin >> c; }}// Little main programint main(){ // Load up, or start from scratch? char c; cout << "Load network? "; cin >> c; if((c == 'y') || (c == 'Y')) ox.load("ox.net"); // Play a load of games games(); // Save what we've learned ox.save("ox.net"); return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -