Program 2
This program uses Inductive Learning to determine the weights for 5 features in the h() function.
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include <iostream.h>
//A state type is just an array of 9 integers, 1=x 2=o
struct state { int b[9]; };
typedef char string[200];
//Level to search in Minimax
int mm_level = 2;
//=========Standard weights and best weights used in Minimax
//Weight 0: Number of rows with 2 of your mark - num row 2 of his
float w0 = 0; float b0 = 0;
//Weight 1: Number of rows with 3 of your mark - num row 3 of his
float w1 = 0; float b1 = 0;
//Weight 2: Center square is yours = 1, his = -1, none = 0
float w2 = 0; float b2 = 0;
//Weight 3: Number of corners yours - number of corners his
float w3 = 0; float b3 = 0;
//Weight 4: Number of rows with 1 of your mark - num row 1 of his
float w4 = 0; float b4 = 0;
//Best number of matched boards
int bestmatch = -1;
//Number of trys
long trys = 0;
//increment for weights
float incr = 1;
//Ranges to check on the variables
float min4, max4;
float min3, max3;
float min2, max2;
float min1, max1;
float min0, max0;
//Number of board configs in file
int checkNum = 0;
//Best next move
int bestmv = 0;
state bestst;
//File that has board configurations
ifstream fin("create.dat");
//Board configurations
string perfect[1000];
//-=-=-Function Prototypes-=-=-=-
float minimax(int,float,int,state,int);
state getState(int);
char* best_move(int,state);
void takesOn(state*,state*);
state next_ith_state(state,int);
int diff(state);
//-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int main(int argc, char *argv[]) {
//Open the database of moves and store them into an array
while (!fin.eof())
{ fin >> perfect[checkNum];
checkNum++;}
fin.close();
//Depth of Minimax Search
cout << "Enter minimax Level:";
cin >> mm_level;
cout << "Min 4:"; cin >> min4; cout << "Max 4:"; cin >> max4;
cout << "Min 3:"; cin >> min3; cout << "Max 3:"; cin >> max3;
cout << "Min 2:"; cin >> min2; cout << "Max 2:"; cin >> max2;
cout << "Min 1:"; cin >> min1; cout << "Max 1:"; cin >> max1;
cout << "Min 0:"; cin >> min0; cout << "Max 0:"; cin >> max0;
state start;
for(w4 = min4; w4 <= max4; w4++)
for(w3 = min3; w3 <= max3; w3++)
for(w2 = min2; w2 <= max2; w2++)
for(w1 = min1; w1 <= max1; w1++)
for(w0 = min0; w0 <= max0; w0++) {
//Total matched is initialized
int total_correct =0;
//Go through the transitions
for(int i = 0; i < checkNum; i++)
{takesOn(&start,&getState(i));
if (diff(start) == 0)
{minimax(1,-999,mm_level,start,1);}
else
{minimax(0, 999,mm_level,start,2);}
if (best_move(i,bestst) != 0)
// Add in the below line if we want to represent diff. boards
// { total_correct = total_correct + (perfect[i][0]-'0');}
{ total_correct++;}
}
//---Output results---
if (trys % 100 == 0)
{int total = (max4 -min4+1)*(max3-min3+1)*(max2-min2+1)*(max1-min1+1);
total = total * (max0- min0+1);
total++;
cout << "Try " << trys << " (%"<< (100*trys)/total << ")";
cout << " got " << total_correct<<endl; }
if (total_correct > bestmatch)
{bestmatch = total_correct;
cout << "Best so far @ " << total_correct << " --> ";
cout << w0 << "," << w1 << "," << w2 << "," << w3 << "," << w4 << endl;
b0 = w0; b1 = w1; b2 = w2; b3 = w3; b4 = w4; }
trys++;
} //end for all weights loop
//Output the best reading
cout << "---------------------------" << endl;
cout << "Best reading" << endl;
cout <<b0<<","<<b1<<","<<b2<<","<<b3<<","<<b4<< endl;
cout <<"Best:"<<bestmatch<<endl;
return 1;
}
//-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Returns the number of x's minus the number of o's
int diff(state s) {
int dif = 0;
for(int i = 0; i < 9; i++)
{if (s.b[i] == 1) dif++;
if (s.b[i] == 2) dif--;}
return dif;}
//Checks if the state is terminal
int checkdone(state s) {
if (s.b[0] != 0 && s.b[0] == s.b[1] && s.b[1] == s.b[2]) {return 1;}
if (s.b[3] != 0 && s.b[3] == s.b[4] && s.b[4] == s.b[5]) {return 1;}
if (s.b[6] != 0 && s.b[6] == s.b[7] && s.b[7] == s.b[8]) {return 1;}
if (s.b[0] != 0 && s.b[0] == s.b[3] && s.b[3] == s.b[6]) {return 1;}
if (s.b[1] != 0 && s.b[1] == s.b[4] && s.b[4] == s.b[7]) {return 1;}
if (s.b[2] != 0 && s.b[2] == s.b[5] && s.b[5] == s.b[8]) {return 1;}
if (s.b[0] != 0 && s.b[0] == s.b[4] && s.b[4] == s.b[8]) {return 1;}
if (s.b[6] != 0 && s.b[6] == s.b[4] && s.b[4] == s.b[2]) {return 1;}
int total = 0;
while (total < 9 && s.b[total] != 0)
{total++;}
if (total == 9)
{return 1;}
return 0;}
//Returns the number of next possibles moves from the state
int nextPos(state s)
{ int totalfree = 0;
for(int i = 0; i < 9; i++)
{if (s.b[i] == 0) {totalfree++;}}
return totalfree; }
//equivalent to state a = state d
void takesOn(state* a, state* d)
{ for(int i = 0; i < 9; i++)
{(*a).b[i] = (*d).b[i];} }
//Returns the next ith state from state s
state next_ith_state(state s, int i)
{ state ret;
takesOn(&ret,&s);
int l = -1;
int xs = 0;
int os = 0;
for(int j = 0; j < 9; j++)
{if (ret.b[j] == 1) {xs++;}
if (ret.b[j] == 2) {os++;}}
while(i != 0)
{l++;
while(ret.b[l] != 0) {l++;}
i--; }
//l--;
if (xs == os) {ret.b[l] = 1;} else {ret.b[l] = 2;};
return ret;
}
//Calculates the h function for a player
float h(state s, int player) {
int opp = 2;
if (player == 2)
{opp = 1;}
int gene0 = 0;
int gene1 = 0;
int gene2 = 0;
int gene3 = 0;
int gene4 = 0;
int your_marks = 0; int opp_marks = 0; int nones = 0;
//check rows and columns
for(int i = 0; i < 3; i++)
{//====Check Rows
your_marks = 0; opp_marks = 0; nones = 0;
for(int x = 0; x < 3; x++)
{if (s.b[i*3+x] == player) your_marks++;
if (s.b[i*3+x] == opp ) opp_marks++;
if (s.b[i*3+x] == 0 ) nones++;}
if (your_marks == 2 && nones == 1) gene0++;
if (opp_marks == 2 && nones == 1) gene0--;
if (your_marks == 3) gene1++;
if (opp_marks == 3) gene1--;
if (your_marks == 1 && nones == 2) gene4++;
if (opp_marks == 1 && nones == 2) gene4--;
//====Check Columns
your_marks = 0; opp_marks = 0; nones = 0;
for(int x = 0; x < 3; x++)
{if (s.b[i+x*3] == player) your_marks++;
if (s.b[i+x*3] == opp ) opp_marks++;
if (s.b[i+x*3] == 0 ) nones++;}
if (your_marks == 2 && nones == 1) gene0++;
if (opp_marks == 2 && nones == 1) gene0--;
if (your_marks == 3) gene1++;
if (opp_marks == 3) gene1--;
if (your_marks == 1 && nones == 2) gene4++;
if (opp_marks == 1 && nones == 2) gene4--;
}
//====Check Diagonals
your_marks = 0; opp_marks = 0; nones = 0;
for(int x = 0; x < 3; x++)
{if (s.b[x*4] == player) your_marks++;
if (s.b[x*4] == opp ) opp_marks++;
if (s.b[x*4] == 0 ) nones++;}
if (your_marks == 2 && nones == 1) gene0++;
if (opp_marks == 2 && nones == 1) gene0--;
if (your_marks == 3) gene1++;
if (opp_marks == 3) gene1--;
if (your_marks == 1 && nones == 2) gene4++;
if (opp_marks == 1 && nones == 2) gene4--;
your_marks = 0; opp_marks = 0; nones = 0;
for(int x = 0; x < 3; x++)
{if (s.b[x*2+2] == player) your_marks++;
if (s.b[x*2+2] == opp ) opp_marks++;
if (s.b[x*2+2] == 0 ) nones++;}
if (your_marks == 2 && nones == 1) gene0++;
if (opp_marks == 2 && nones == 1) gene0--;
if (your_marks == 3) gene1++;
if (opp_marks == 3) gene1--;
if (your_marks == 1 && nones == 2) gene4++;
if (opp_marks == 1 && nones == 2) gene4--;
//Center Square
if (s.b[4] == player) gene2++;
if (s.b[4] == opp) gene2--;
//Corners
if (s.b[0] == player) gene3++;
if (s.b[2] == player) gene3++;
if (s.b[6] == player) gene3++;
if (s.b[8] == player) gene3++;
if (s.b[0] == opp) gene3--;
if (s.b[2] == opp) gene3--;
if (s.b[6] == opp) gene3--;
if (s.b[8] == opp) gene3--;
return gene0*w0+gene1*w1+gene2*w2+gene3*w3+gene4*w4;}
//Performs Minimax
float minimax(int max_t, float value, int level, state st,int p)
{
//Base Cases
if (level == 0)
return h(st,p);
if (checkdone(st) == 1)
return h(st,p);
float curm = -999;
if (max_t == 0)
curm = 999;
int best = -1;
float current = 0;
int possibleNextStates = nextPos(st);
for(int i = 1; i <= possibleNextStates; i++)
{state s_prime;
takesOn(&s_prime,&next_ith_state(st,i));
int opplook = 1;
if (max_t == 1)
{opplook = 0;}
current = minimax(opplook,curm,level-1,s_prime,p);
if (max_t ==1 && current > curm)
{curm = current; best = i;}
if (max_t ==0 && current < curm)
{curm = current; best = i;}
} //all possibilites
bestmv = best;
takesOn(&bestst,&next_ith_state(st,bestmv));
return curm;
}
//Return a state given an array index from the board database
state getState(int i) {
state s;
s.b[0] = perfect[i][2] - '0';
s.b[1] = perfect[i][3] - '0';
s.b[2] = perfect[i][4] - '0';
s.b[3] = perfect[i][5] - '0';
s.b[4] = perfect[i][6] - '0';
s.b[5] = perfect[i][7] - '0';
s.b[6] = perfect[i][8] - '0';
s.b[7] = perfect[i][9] - '0';
s.b[8] = perfect[i][10] - '0';
return s;}
//Checks if state s if a good move from database starting board i
char* best_move(int i, state s) {
string to_string;
for(int j = 0; j < 9; j++)
{to_string[j] = s.b[j] + '0';}
return strstr(perfect[i],to_string);
}