Is there a way to implement AI to the computer in TicTacToe? - c++

I have this program that runs the game of Tictactoe, but i'd like to add AI to the computer function so it can be more difficult in order to play with
I tried by rand(); but it just make the computer put the decision in whatever slot is available.
void ia_turn(){
while (true){
int ia_tu = (rand() % 9) +1;
int ia_op = ia_tu - 1;
int row = ia_op / 3;
int column = ia_op % 3;
char matrix_pos = matrix[row][column];
if (matrix_pos == 'X' || matrix_pos == 'O'){
continue;
}else{
cout << "The AI selected the position: "<<ia_tu<<endl;
matrix[row][column] = 'O';
break;
}
}
}
I expect the movements of the ComputerAI to block my movements, but it can't be done with the rand() function.
This is the checking for wins function that i have
void checking_for_wins(){
const char* wins_possibilities[8] = {"123","456","789","159","753","147","258","369"};
for (int i =0;i<8;i++){
bool win = true;
char prev_op = '0';
const char* win_possibility = wins_possibilities[i]; //funciona como puntero en caso de que se cumpla uno de las wins_possibilities[]
for (int rcl = 0;rcl<dim_m;rcl++){
char alphaChar = win_possibility[rcl];
int intr_number = alphaChar - '0';
int op_sp = intr_number - 1;
int row = op_sp / dim_m; //busca la posiciĆ³n de la fila
int column = op_sp % dim_m; //busca la posiciĆ³n de la columna
char current_op = matrix[row][column];
if (prev_op == '0'){
prev_op = current_op;
}else if (prev_op == current_op){
continue;
}else{
win = false;
break;
}
}
if (win){
cout << "Felicidades, ganaste!! \n";
cout << "El jugador "<<prev_op<<" gana, felicidades! \n";
exit(0);
break;
}
}
}

The best way to start is to write a function which looks for possible victories (instead of looking to see if there are three in a row, check to see if there are two in a row instead). Then have the function return the space that would be a victory and have the AI move there instead. Ex: If the matrix looks like
X X _
_ _ _
_ O O
Have the function return 0,2 and 2,0.
Then have your AI pick from that randomly.
After that you can modify that function to return who's possible victory it is, and then have your AI always prefer to go where it would win.
Implementation can look something like this:
#include <vector> // Vector comes from this
#include <utility> // Pair comes from this
std::vector<std::pair<bool, Point>> GetPossibleVictories()
{
std::vector<std::pair<bool, Point>> retVal;
// Check for two in a row Horitzontally, Vertically, and Diagonally.
{
if (/*IsPossibleWin*/)
{
retVal.push_back(std::pair<bool, Point>(isAIsVictory, Point{ X, Y }));
}
}
return retVal;
}
In addition I would also investigate more modern C++ constructs which can help you such as containers (std::vector, std::list, std::set, and etc) which can help you store your matrix in a easier to manipulate way.
In the example above I'm using a custom type (Point) which in its simplest way can be programmed like this:
struct Point
{
int X = 0;
int Y = 0;
};
By using a struct (or a class where every member is public by default) you can store coordinates for your matrix in a single object. In addition I'm using a vector which acts like a automatically resizing array. You can go through each thing in the vector like this:
for(const auto& possibleWin : possibleWins) // possibleWins is the vector returned from the previous example.
{
// possibleWin in this block will be the same value as if you used a for loop and did possibleWins[x]
}
Finally the example above uses Pair, which just holds two different types of things. It can be used as follows:
std::pair<bool, Point> myPair;
myPair.first = true;
myPair.second = Point{0, 2};
For more reading (Scroll to the bottom for examples on how to use them):
Vector
Pair
Hopefully this can give you some ideas on how to start making your AI a little smarter.

Related

Problems creating Stack! (arcade game) in C++

im a beginner amateur in C++ and i recently had the idea to remake the popular arcade game Stack! in the C++ console.
The problem occours when the player has got to place the pad:
the pad places well, but if you make an error it doesn't resize properly (you'll understand better when you'll run the code).
Don't care about the graphic that sometimes bugs, because i can fix that on my own.
Please help me!
Here is the code:
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <windows.h>
#include <string>
using namespace std;
bool bDirection = true; /* Bool for the direction:
true = dx, false = sx */
string sPad;
int nPadLenght = 6;
int x = 40, y =21; // Referement tile's position
int nSpeed = 200;
bool loop = true; // main loop
int nScore = 0; // score
int nPlaceX = 40;
int nTileX = 35, nTileY = 20; // Player's actual postition
int nEndTileX, nEndTileY;
void RenderLine(int *x, int *y);
int main();
// Void for the coordinates
void gotoxy (int x, int y){
COORD coord;
coord.X = x ;
coord.Y = y ;
SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void Victory(){
x = 10;
y = 4;
Beep(698.5, 300);
Beep(698.5, 100);
Beep(1047, 500);
system("color a");
gotoxy(x,y); cout << "You win!\n\n Score = " << nScore;
system("pause >nul");
}
void PadLenght(int *x){
// Each number is equal to a possible pad lenght
switch (*x){
case 6:
sPad = "[][][]";
nEndTileX = nTileX + 5;
break;
case 5:
sPad = "[][]]";
nEndTileX = nTileX + 4;
break;
case 4:
sPad = "[][]";
nEndTileX = nTileX + 3;
break;
case 3:
sPad = "[][";
nEndTileX = nTileX + 2;
break;
case 2:
sPad = "[]";
nEndTileX = nTileX + 1;
break;
case 1:
sPad = "[";
nEndTileX = nTileX;
break;
}
}
void SwitchDirection(bool *x){
// Switches the bool of the direction
switch (*x){
case true:
*x = false;
break;
case false:
*x = true;
break;
}
}
void Speed(){
// For each line from 500ms to 20ms speed increments of 10ms
if (nSpeed > 20)
nSpeed -= 20;
}
// void for placing the pad
void Place() {
int i = nPlaceX - nTileX;
if (i < 0)
i * -1;
nPadLenght -= i;
}
void collision(){
// Collisions with the border
if (nTileX > 45 || nTileX < 35)
SwitchDirection(&bDirection);
}
void movement(){
int nLastX = nTileX;
// Place the pad if pressing down arrow
if(GetKeyState(VK_DOWN) & 0x8000){
nTileY--;
Place();
Speed();
Beep(698.5, 50);
Beep(880.0, 50);
Beep(1047, 50);
nScore += 10;
Sleep(60);
}
// Movement of the pad
switch (bDirection){
case true:
gotoxy (nLastX, nTileY); cout << " ";
nTileX++;
break;
case false:
gotoxy (nLastX - nPadLenght, nTileY); cout << " ";
nTileX--;
break;
}
}
int main(){
system("color 0");
while (loop = true){
char a = '"';
gotoxy(x,y); cout << a << a << a << a << a << a;
collision();
PadLenght(&nPadLenght);
movement();
gotoxy (nTileX, nTileY); cout << sPad;
Sleep (nSpeed);
if (nScore > 160) {
Victory();
break;
}
}
return 0;
}
Here are some issues I found:
"using namespace std;"
This is bad. This brings in all of the identifier names from the std namespace. The preference is to use the std prefix (e.g. std::cout) or choose from the std namespace, (e.g. using std::cout;).
Global variables
Prefer to not have global variables. Create them in main and pass them to functions.
For example, you have global x and y, and you use x and y as parameters in functions. This may lead to confusion between you, readers and the compilers, as to which variables you are referring to.
Passing by pointer
Prefer not to use pointers.
Pass by value (without pointers) for variables that can fit into a processor's register, like float, double, int, bool and char.
For classes and structures, pass by reference. If you are not modifying the parameter, pass by constant reference.
Don't create functions for simple content
Functions require an overhead to execute, usually at least 3 instructions (save parameters, branch to function, return from function). Some operations can be performed with less statements:
// Switch directions:
direction = ! direction;
If you must use functions, give the compiler the hint that you want them inline. This means that the compiler will paste the content of the function where the function call is made. Some compilers may do this for optimizations, but you have to tell the compiler to optimize.
Boolean switch statements
Switch statements are kind of overkill for Boolean varibles, since there are only 2 outcomes. Common coding guidelines are to use if and else.
'=' in conditional expressions
Remember, one = for assignment, two for comparison.
The language allows for an assignment in a comparison, but most likely, you were not thinking of assignment, but testing for equality.
Declare variables closest to usage
Make life easier on you, the compiler and reader, by declaring variables closest to where they are used. For example, in main, there is a loop variable. As a reader, I have to scroll to the top of your source to find the definition, when a better idea is to declare it in the main function, where it is used.
One variable declaration per line
A common coding guideline is one variable per line. Multiple lines have a negligible effect on the build time. However, this makes modifications easier. And when declaring pointers, reduces injected defects. Let your compiler optimize the code, your task should be write clear (easily readable) and concise code.
Increase the compiler's warning level
Force your compiler to turn on the warning level to its highest level.
Resolve all warnings.
A clean compilation has zero errors and zero warnings.
With compiler warnings at full, you would have noticed some of the issues I have identified.

Connect 4 PVP Function

I can't seem to find something that specifically answers my question. I am looking for a solution to my problem. The connect 4 player versus player seems to just ask the first player to drop then the second player to drop, but the first if statement is no longer true so it continues to ask the second player to drop. I am using eclipse for mac osx although the game is programmed for ASCII character set.
display();
int hold;
int hold2 = 0;
int charsPlaced = 0;
bool gamewon = false;
char player = 15;
string r;
while (!gamewon)
{
if (hold2 != -1)
{
if (player == 15)
{
cout << ax << " what column would you like to drop in?";
player = 178;
}
else
{
cout << bx << " what column would you like to drop in?";
player = 176;
}
}
You need to switch the players' turn after each action. If P1 took an action, you need to update the "turn" so that the next time the code loops it will ask for P2. Then, after you've done the stuff you need to do for P2, you need to update the "turn" so that the next time it loops it will ask for P1 action.
Here's a different approach on your code by using an enum. You can use a bool type variable which is false for P1 and true for P2, or an int that's 1 or 2, but that's a bit harder to understand from the outisde.
// omitted code
enum PlayerTurn { ePlayer1 = 0, ePlayer2 };
// omitted code
PlayerTurn plTurn = ePlayer1;
while (!gamewon)
{
if (pTurn == ePlayer1)
{
cout << ax << " what column would you like to drop in?";
// TODO: stuff to do for Player #1
}
else
{
cout << bx << " what column would you like to drop in?";
// TODO: stuff to do for Player #2
}
// TODO: decide if game has been won, mechanics etc.
// move to the next player without overflowing the 2 possible values (0 and 1)
plTurn = (plTurn + 1) % 2;
}
Then, on your display() function, you can show any ASCII character you wish.

c++ tron 2d array repeating

I am trying to get a trail to appear behind the player bike but for some reason instead of a "x" appearing behind the player every time it moves, the player would actually duplicate itself. It sounds a little confusing but you should compile this code yourself and see what i mean. What I am trying to do is just have a trail of "x" behind the player instead of the player leaving a trail of "P". thanks
#include <iostream>
#include "windows.h"
#include <conio.h>
#include <ctime>
using namespace std;
//prototype functions used
void DisplayMap();
void PlayerBike();
void setCursorTo();
void SetBike();
//global variables that will be used by different functions
int PlayerX = 10;
int PlayerY = 70;
bool GameOver = false;
const int H = 25; // const variable so it doesnt change size
const int W = 82;// const variable so it doesnt change size
char Map[H][W]; // char map with HxW
char trail = 'x'; // this is where the trail is initialized as a *
int main()
{
SetBike();
DisplayMap();
while (GameOver == false){
setCursorTo();
PlayerBike();
} // end while loop
return 0;
}//end main
void DisplayMap(){ // display map function
for(int i = 0; i < H; i++ ){
for(int j = 0; j < W; j++){
if(i == 0 || i == 24 || j == 0 || j == 81 ){ Map[i][j] = 'x';} // characters in row 24x81 are changed to x
cout << Map[i][j]; // output map
} // end for loop
cout << "\n"; // create new line to output the map correctly
} //end for loop
} // end DisplayMap function
void SetBike(){
Map[PlayerX] [PlayerY] = 'P';
}
void PlayerBike(){
Map[PlayerY][PlayerX]= trail; // I would like this trail to repeat behind the player but it does not appear at all.
if (kbhit()) {// get user key input
char GetCh = getch(); // GetCh equal to the button the user presses
if (GetCh == 'w'){PlayerX = PlayerX - 1; Trailx = Trailx -1;}
else if (GetCh == 's'){PlayerX = PlayerX +1; Trailx = Trailx +1;}
else if (GetCh == 'd'){PlayerY = PlayerY +1;}
else if (GetCh == 'a'){PlayerY = PlayerY - 1;}
}// end kbhit
}// end PlayerBike function
void setCursorTo() // stops constant flashing on the map
{
HANDLE handle;
COORD position;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
position.X = 0;
position.Y = 0;
SetConsoleCursorPosition(handle, position);
}
Your DisplayMap function is flawed.
First, it seems you are not only displaying the map, you are also actively modifying it. Put the drawing-a-border into a separate initMap function, which also zeros out all other positions with a space (it seems you didn't do that yet, so perhaps that is where it goes wrong). You only need to call initMap once.
Next, do not draw the player P in the DisplayMap function. Draw this once, before entering the game loop. Then: if the user pressed a valid move key,
put an x on the player's position
update player position
put a P on the new position
redraw the screen by calling DisplayMap
and you'll see the trail stays put.
Possible refinements: before accepting a 'move' command by updating the position, check if the map contains a space or something else. If it contains a space, you can execute the move; if not, play an explosion animation (*oO*+.). Also, consider looking up the switch statement in your favourite C reference, to avoid endless long sequences of if..else.

Can I have a single-dimension array of booleans that skip indexes?

I'm pretty new to Arduino programming, but am getting the hang of it. I've got a pretty strong PHP & Javascript background, so that's where I'm coming from.
I've been working on a project with an LCD touchscreen, with grids of buttons that I expect other developers to customize to their needs. There's an array that a developer can freely add items to, and additional pages of buttons are added dynamically. Clicking one simply sends that button's index to a receiver.
Now I want to make some buttons "sticky" so they stick on until turned off. My idea was to set up a simple array of booleans, like so:
boolean stickyTriggers[1] = 1;
boolean stickyTriggers[2] = 0;
boolean stickyTriggers[3] = 0;
boolean stickyTriggers[9] = 1;
What I'd expect is that buttons 1, 2, 3, and 9 are sticky, and buttons 1 and 9 are "on" by default. I figured when I'm rendering the buttons, I can simply say something like:
if (stickyTriggers[i]) {
// highlight button
}
The error I'm getting on compile is:
array must be initialized with a brace-enclosed initializer
I sort of realize I'm re-declaring the variable 3 times here, but I've tried other ways and got other errors.
What is the correct way to hold a simple array of flags? I want to be able to look up a key and get a true or false (or null), without having to hard-code an array length. I'm sure it's all possible, but is there a simple way?
Thanks
Clarification: The key here is that triggers 4-8 are NOT in the stickyTriggers array at all, since they are NOT sticky. I want to be able to skip indexes, or use arbitrary IDs as keys, as the title suggests. Most of the answers miss this.
I think you need somethig like this
#include <iostream>
using namespace std;
int main()
{
bool b[5] = {true, false, true, false, true};
cout << "Hello World" << endl;
for (int i=0; i < 5; i++) {
if (b[i]) {
cout<< "Index " << i << " is true" <<endl;
} else {
cout<< "Index " << i << " is false"<<endl;
}
}
return 0;
}
Try this:
#define ARRAY_SIZE 10
#define BOOL unsigned int
#define TRUE 1
#define FALSE 0
int main()
{
BOOL stickyTriggers[ARRAY_SIZE] = { FALSE };
stickyTriggers[1] = TRUE ;
stickyTriggers[9] = TRUE ;
return 0;
}
Yes, you are re-defining the array several times.
In C++, you may want to use bitset, check this link
http://en.cppreference.com/w/cpp/utility/bitset
You can try vector (which can dynamically change its size) too, like this
#include<iostream>
#include<vector>
using namespace std;
enum trigger_status {ON, OFF, NON_STICKY};
int main(){
vector<trigger_status> sticky_triggers(251, trigger_status::OFF); // you can add element to it dynamically, default all to off
sticky_triggers[0] = trigger_status::ON;
sticky_triggers[9] = trigger_status::ON;
sticky_triggers.push_back(trigger_status::ON); // sticky_triggers[251] = true, now u have 252 elements
}
Maybe I should have left out the C++ tag, to only invite Arduino-specific solutions.
But here's what I found, which solves my problem:
Alexander Brevig's HashMap Library:
http://playground.arduino.cc/Code/HashMap
As discussed here: http://forum.arduino.cc/index.php?PHPSESSID=q7rt05n43aa4enp6hepri50pi1&topic=42114.msg305435#msg305435
#include <HashMap.h>
const byte HASH_SIZE = 5;
HashType<int,boolean> hashRawArray[HASH_SIZE];
HashMap<int,boolean> hashMap = HashMap<int,boolean>(hashRawArray, HASH_SIZE);
void setup() {
Serial.begin(9600);
hashMap[0](1,true);
hashMap[1](2,false);
hashMap[2](3,false);
hashMap[3](4,false);
hashMap[4](9,true);
Serial.println(hashMap.getValueOf(1));
Serial.println(hashMap.getValueOf(2));
Serial.println(hashMap.getValueOf(9));
}
I can add a quick wrapper to add items to the hashMap without having to hard-code the index, but this gives me an easy way to set up an associative array of booleans, using arbitrary integers as the keys.
Thanks for trying everyone, sorry none of the answers worked on Arduino.
You might be able to use this it does not quite fulfil your desire to have no references to non-sticky triggers but it is fast and only uses 64 bytes of memory to map out 256 triggers.
I already had it in single boolean mode so I adapted it to make two maps and renamed it to suit your question..
Basically it is a bitmap.
Compiles and tests run OK for Arduino Duo.
// bitmapped booleans
const int IntBits = 16;
const int NumTriggers = 256;
const int idxSticky = 0;
const int idxDown = 1;
unsigned int TriggerMap[NumTriggers/IntBits][2];
void setup() {
Serial.begin(9600);
clearTriggerMap; // set all to not sticky and not down
// tests
setStickyTrigger(1, true, true);
setStickyTrigger(2, true, false);
setStickyTrigger(3, true, false);
setStickyTrigger(9, true, true);
setStickyTrigger(30, true, true);
setStickyTrigger(128, true, true);
setStickyTrigger(255, true, true);
}
void loop() {
// tests
Test(0);
Test(1);
Test(2);
Test(3);
Test(9);
Test(30);
Test(128);
Test(255);
delay(5000);
}
void Test( int ATrigger) {
// testing
if (IsStickyTrigger(ATrigger)) {
Serial.print( "Trigger ");
Serial.print(ATrigger);
Serial.print(" is sticky");
if (IsStickyTriggerDown(ATrigger)) {
Serial.print(" and it is down");
}
}
Serial.println();
}
void clearTriggerMap() {
for (int i = 0; i < NumTriggers/IntBits; i++) {
for (int j = 0; j < 2; j++){
TriggerMap[i][j] = 0;
}
}
}
void setStickyTrigger(int AIndex, boolean ASticky, boolean IsDown) {
unsigned int o;
unsigned int b = 1;
o = AIndex / IntBits;
b = b << (AIndex % IntBits);
if (ASticky) {
TriggerMap[o][idxSticky] = TriggerMap[o][idxSticky] | b;
} else {
b = ~b;
TriggerMap[o][idxSticky] = TriggerMap[o][idxSticky] & b;
}
if (IsDown) {
TriggerMap[o][idxDown] = TriggerMap[o][idxDown] | b;
} else {
b = ~b;
TriggerMap[o][idxDown] = TriggerMap[o][idxDown] & b;
}
}
boolean IsStickyTrigger(int AIndex) {
unsigned int b = 1;
b = b << (AIndex % IntBits);
return (TriggerMap[AIndex / IntBits][idxSticky] & b) != 0;
}
boolean IsStickyTriggerDown(int AIndex) {
unsigned int b = 1;
b = b << (AIndex % IntBits);
return (TriggerMap[AIndex / IntBits][idxDown] & b) != 0;
}

How to find out shared variables among functions by using LLVM API?

Recently I used LLVM API to test C++ program. Now I want to find out the shared variables among different functions, is there any way to do that? It seems that the AliasAnalysis doesn't work!
I write a Function Pass as following:
bool EscapeAnalysis::runOnFunction(Function& F) {
EscapePoints.clear();
TargetData& TD = getAnalysis<TargetData>();
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
Module* M = F.getParent();
// errs() << *M << "\n";
// Walk through all instructions in the function, identifying those that
// may allow their inputs to escape.
for(inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE; ++II) {
Instruction* I = &*II;
// The most obvious case is stores. Any store that may write to global
// memory or to a function argument potentially allows its input to escape.
if (StoreInst* S = dyn_cast<StoreInst>(I)) {
Type* StoreType = S->getOperand(0)->getType();
unsigned StoreSize = TD.getTypeStoreSize(StoreType);
Value* Pointer = S->getPointerOperand();
bool inserted = false;
for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end();
AI != AE; ++AI) {
if (!isa<PointerType>(AI->getType())) continue;
AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, AI, ~0UL);
if (R != AliasAnalysis::NoAlias) {
EscapePoints.insert(S);
inserted = true;
break;
}
}
if (inserted)
continue;
for (Module::global_iterator GI = M->global_begin(), GE = M->global_end();
GI != GE; ++GI) {
errs() << *GI << "\n";
AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, GI, ~0UL);
errs() << "R: " << R << " , NoAlias: " << AliasAnalysis::NoAlias << "\n";
if (R != AliasAnalysis::NoAlias) {
EscapePoints.insert(S);
break;
}
}
// Calls and invokes potentially allow their parameters to escape.
// FIXME: This can and should be refined. Intrinsics have known escape
// behavior, and alias analysis may be able to tell us more about callees.
} else if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
EscapePoints.insert(I);
// Returns allow the return value to escape. This is mostly important
// for malloc to alloca promotion.
} else if (isa<ReturnInst>(I)) {
EscapePoints.insert(I);
// Branching on the value of a pointer may allow the value to escape through
// methods not discoverable via def-use chaining.
} else if(isa<BranchInst>(I) || isa<SwitchInst>(I)) {
EscapePoints.insert(I);
}
// FIXME: Are there any other possible escape points?
}
return false;
}
Test the main.cpp as following:
#include
using namespace std;
int X = 0;
int foo() {
X = 1;
int b = 1;
return 0;
}
int bar(int param) {
int y = X;
int z = 9;
int a = z;
++a;
return 0;
}
int main(int argc, char *argv[])
{
cout << "Hello world!" << endl;
return 0;
}
the global variable X is the shared variable between function bar and function foo.
But when I use the command as following to run the pass:
opt -load ./EscapeAnalysis.so -escape-analysis main.o | llc > main.ss
I get the result:
R: 1 , NoAlias: 0
all result are the same.
I print out the variables in escapePoint, find that variable a, z, y in function bar are in escapePoint. It is not right!
Note: I write a opt pass to test program.
Alias analysis is required if you want to identify when two different variables might point to the same memory. If you just want to check which variables are shared with other functions in the same module, you can:
Iterate over all instructions, and for each:
Iterate over all its operands, and for each:
Check whether it's a GlobalVariable (via isa, for instance), and if so:
Iterate over all the global's uses (via use_begin and use_end), and for each:
Check whether it's an Instruction, and if so:
Retrieve the enclosing function (via getParent()->getParent()), and for that function:
Check whether it is the currently-processed function. If not, it means you found a variable shared between the current function and another function.
There are also other ways of checking this, for example going over all the globals in the current module.