What will be the terminal case of maxconnect4 game? - artificial-intelligence

I understand tic-tac-toe using minimax algorithm where terminal cases are win, lost and draw - 10,0,-10.
program termninates when some one wins, loose or draw. As connect four game do not have three terminal states, rather than a scoreboard after the game is finished, How do I determine its terminal cases from evaluation function? How to implement the evaluation function?
int minimax(char board[3][3], int depth, bool isMax)
{
int score = evaluate(board);
// If Maximizer has won the game return his/her
// evaluated score
if (score == 10)
return score;
// If Minimizer has won the game return his/her
// evaluated score
if (score == -10)
return score;
// If there are no more moves and no winner then
// it is a tie
if (isMovesLeft(board)==false)
return 0;
// If this maximizer's move
if (isMax)
{
int best = -1000;
// Traverse all cells
for (int i = 0; i<3; i++)
{
for (int j = 0; j<3; j++)
{
// Check if cell is empty
if (board[i][j]=='_')
{
// Make the move
board[i][j] = player;
// Call minimax recursively and choose
// the maximum value
best = max( best,
minimax(board, depth+1, !isMax) );
// Undo the move
board[i][j] = '_';
}
}
}
return best;
}
// If this minimizer's move
else
{
int best = 1000;
// Traverse all cells
for (int i = 0; i<3; i++)
{
for (int j = 0; j<3; j++)
{
// Check if cell is empty
if (board[i][j]=='_')
{
// Make the move
board[i][j] = opponent;
// Call minimax recursively and choose
// the minimum value
best = min(best,
minimax(board, depth+1, !isMax));
// Undo the move
board[i][j] = '_';
}
}
}
return best;
}
}
But for connect4, how do I calculate evaluation function and how it will define terminal cases (except when the board is full)?

As connect four game do not have three terminal states, rather than a scoreboard after the game is finished,
First of all, your are wrong in saying connect four doesn't have three terminal stages. It too can only end in either win, lose, or draw.
The problem is that connect four is sufficiently complex that it is impossible to evaluate the tree until those terminal stages are reached. That is why in games more complicated than the most basic (like tic tac toe), a predetermined search depth is given for the search, and all nodes at the end of that depth are viewed as terminal. This depthy is usually determined by time constraints in an iterative deepening framework.
Since in reality these nodes are not terminal, we can no longer evaluate them using 0, 1, and -1. Instead, we expand our range, treating wins as an arbitrarily high number, loses as arbitrarily low, and using a heuristic evaluation function to determine in between values. One possible heuristic is number of three in a rows a player has. For more complex connect four heuristics, read Victor Aliss's thesis on the topic.

Related

Triangle with Recursion

I have an assignment from my uni where I have to print a triangle using recursion in C language. I have tried writing my code as follows but I am not able to find my mistake. Kindly can anyone point out where I have to edit.
int tri(int x, int org);
int dreick(int x) {
return tri(x,x);
}
int tri(int x,int org) {
if (x == 0) {
return 0;
}
else {
return (x - 1, org);
}
for (int i = 0; i < (org - x); i++) {
printf("");
}
for (int j = 0; j <= x; j++) {
printf("*");
}printf("\n");
}
int main() {
int a = dreick(5);
printf("%d",a);
}
Recursion works as follows: each step receives a parameter which specifies what work still needs to be done; if no work needs to be done, then it returns without doing anything; otherwise, it does one step of the work, and then invokes itself with a new value for the parameter which specifies the remaining work to be done.
In your case, the parameter specifying what work still needs to be done can be the row number.
Your triangle-printing code can print the top (single star at row 0) and the bottom (row of stars at row N) outside of recursion, so as to keep things simple. Use recursion to print each line of text from 1 to N-1.
On each step of the recursion you print a number of spaces, an asterisk, some more spaces, and then another asterisk. The number of spaces depends on the row number. (How deep down the triangle you are.) You are done when you reach N-1.

Lock_pair function for CS50 Pset 3 Tideman - checking for cycles in a graph

I am working on a problem called tideman. The goal is to make a voting program that follows the tideman algorithm. Here is an explanation of the problem : https://cs50.harvard.edu/x/2020/psets/3/tideman/ Check50 (a provided test from the course CS50 that I am taking) always returns "lock_pairs skips middle pair if it creates a cycle. lock_pairs did not correctly lock all non-cyclical pairs" The purpose of the lock_pairs function is to go over a graph of winners and losers and make sure that a cycle is not being created (the link to the problem explains it better). I do not exactly understand what skipping the middle pair means, and the program works in situations where a cycle is created when I test it. Also, it passes the check "lock_pairs skips final pair if it creates cycle." I implemented lock_pairs by checking if all of the candidates have an edge on it (overlooking the current loser of the pair) and only locking in the pair if not all candidates have edges (therefore not creating a cycle). How do I fix this?
void lock_pairs(void)
{
//checks if a candidate has an edge on it, originally sets all to 0
bool candidatesEdge[candidate_count];
for(int i = 0; i < candidate_count; i ++)
{
candidatesEdge[i] = false;
}
for (int i = 0; i < pair_count; i ++)
{
//variable to see if all others have edges
bool full = true;
int j = 0;
//checks through all other candidates for an edge
while (j < candidate_count && full == true)
{
//if a candidate besides the current being checked doesn't have an edge, full is false
if (j != pairs[i].loser && candidatesEdge[j] == false)
{
full = false;
}
j++;
}
//if not all candidates have edges, gives the loser of the pair an edge
if (full == false)
{
candidatesEdge[pairs[i].loser] = true;
locked[pairs[i].winner][pairs[i].loser] = true;
}
}
}

C - How to find a winner of a norts and crosses

I am currently making a tic tac toe game using C. I am making a function Check(char sign) that i can call after each player makes a move which will check for a winner. I need help as the tic tac toe game can be played on different sized boards (3 up to 12).
I made the following code which can be used to find the winner of a 3 x 3 game:
**//For Rows**
for(i=0; i<3; i++)/***sign is the player symbol e.g. 'X'OR'O'***/
if(board[i][0] == sign && board[i][0] == board[i][1] && board[i][1] == `
board[i][2]){`
printf("the winner is %c", sign );
return 1;
}
**//For Columns**
for(i=0; i<3; i++)/***sign is the player symbol e.g. 'X'OR'O'***/
if(board[0][i] == sign && board[0][i] == board[1][i] && board[1][i] ==
board[2][i]){
printf("the winner is %c", sign );
return 1;
}
**//For Diagnal 1 \**
if(board[0][0] == sign && board[0][0] == board[1][1] && board[1][1] ==
board[2][2]){
printf("the winner is %c", sign );
return 1;
}
**//For Diagnal 2 /**
if(board[0][2] == sign && board[0][2] == board[1][1] && board[1][1] ==
board[2][0]){
printf("the winner is %c", sign );
return 1;
}
However as I mentioned my game can be played on different board sizes which is chosen by user input at the beginining of the game. This size is stored in a vreriable "int Size". How would I alter the above code to work with any size board?
I know that i could create a list if statements each one containing code for a specific board size but this seems like the incorrect and least efficient way of doing so.
I hope someone can help. Any help will be greatly appreciated.
Thank you.
Note that the if statement for each of your 4 cases could be written using a loop; for example, the first one could be written as:
int win = (board[i][0] == sign); // assume a win until we find out otherwise
// loop over the pairs to compare until we find a mismatch or exhaust them all
for ( int j = 1; (win == 1) && (j < size); j++ )
if ( board[i][j-1] != board[i][j] )
win = 0;
if ( win ) {
printf("the winner is %c", board[i][0] );
return 1;
}
Change which 2 elements of board are being compared, and the initialization of win, for each of the other 3 cases.
You could have three function, one that iterates through rows, one that iterates through cols, and one that iterates through the diagonal pair.
/* If the sign player won, return 1. Else return 0. */
int rowWinnerCheck(int n, char sign, char board[n][n]){
for(int i = 0; i < n; i++){
int sameSign = 1;
for(int j = 0; j < n; j++){
char letter = board[i][j];
if(letter != sign){
sameSign = 0;
}
}
if(sameSign == 1){
return 1;
}
}
return 0;
}
colWinnerCheck would be similar to how rowWinnerCheck is implemented.
Verifying if a player won diagonally is also similar.
/* This function checks if a player won diagonally from the top-left to bottom-right*/
int diagonalWinnerCheck(int n, char sign, char board[n][n]){
for(int i = 0; i < n; i++){
int sameSign = 1;
char letter = board[i][i];
if(letter != sign){
return 0;
}
}
return 1;
}
Solution without loops
Here is a possible solution without loops, which I believe scales better for a larger n.
I'll leave the C out for you to complete, and I'll just explain the concept for determining the winner on an n x n board. The code you gave uses loops to compare the contents on the board. This solution doesn't depend on loops as it makes use of a mathematical representation to determine the winner.
Board Representation
We first need to have a representation for the board using a 2D array of integer of size n x n. We will also make everything zero in the board from the start.
int board[n][n];
memset(board, 0, sizeof(board[0][0]) * n * n);
We define the letters that are used, X and O, and assign them to be the constants, 1 and -1 respectively. Note: 1, -1 were choose arbitrarily, but for the solution to work, they need to be some integer k, -k.
We define four more items for the solution. Two integer arrays, one to represent the rows and one for the cols, and two integers for the two diagonals.
int rows[n] = {0};
int cols[n] = {0};
int leftDiag = 0;
int rightDiag = 0;
How it Works
Let's assume a new game was started on a 3x3 board. I play X, and you play O. I make my move on location (2,0). The program first checks the board location at (2,0) and sees if it's zero. If it is, set it to be X, else raise an error since that spot has been played already. The program also adds X to rows[2] and cols[0].
You play O at (1,1). First check if board[1][1] has been already played, if not, set it to be O. Add O to rows[1] and cols[1]. Here is a special case. When you player played O on the diagonal i.e. for a move (a,b) a == b or a == (n-b-1), add O to the appropriate diagonal variable. Since (1,1) belongs to both diagonal, add O to leftDiag and rightDiag.
We alternate turns until one of these conditions are met:
A location i in rows such that rows[i] == n * X. This means X
won by filling the ith row. A location j in rows such that
rows[j] == n * O. This means O won
A location i in cols such that cols[i] == n * X. This means X
won by filling the ith col. A location j in cols such that
cols[j] == n * O. This means O won
leftDiag == n * X or rightDiag == n * X, X won. leftDiag == n * O or rightDiag == n * O, O won.
n*n moves have been made, but the previous conditions were
never met. This mean the game ended in a tie.
Notice that at the end, we don't need to iterate through rows, cols, or diagonals to verify if someone won. If a row, col, or diagonal, sums up throughout the game to be n * Character, then that Character player won. This reduces the complexity of verifying a winner from O(n^2) to O(1). The trade off is just O(n) more space.

A Star algorithm in C implementation with arrays?

I'm new here. I am trying to implement A-Star algorithm in C by myself. I don't know how to use Hashmaps or Lists (but i am open too learn as long as they are simple enough for me) so I use arrays.
The problem is simple: There is a NxN array. You can either go up/down or left/right, no diagonial. Horizontal is better (less cost =5) than vertical movement (high cost=10).
There are some obstacle-cells. Free cells are represented by number 0 in the NxN array, while obstacle cells with the number 9. The obstacle cells occur as a proportion of the area of the table (for example if the table is 10*10 and the independent possibility to have an obstacle in each cell is 0.1, there will be approximately 10 9's in the table.
With the number 1 the starting point is represented and with 2 and 3 the two final goals to go, G1 and G2.
I have tried this below:
#include<stdio.h>
#include <stdlib.h>
int main(void) {
//create a NxN array
int N, sX, sY, g1X,g1Y,g2X,g2Y,i,j,w;
double p;
float r;
printf("Give N\n");
scanf("%d",&N);
printf("Give p\n");
scanf("%lf",&p);
printf("Give S x k y\n");
scanf("%d",&sX);
scanf("%d",&sY);
printf("Give G1 x & y\n");
scanf("%d",&g1X);
scanf("%d",&g1Y);
printf("Give G2 x & y\n");
scanf("%d",&g2X);
scanf("%d",&g2Y);
int table[N][N];
for(i=0; i<N; i++){
for (j=0; j<N; j++){
r=(float)(rand() % 10)/10; // [0,1)
// printf("%f",&r);
if (sX==i && sY==j){
table[i][j]=1;
// printf("1");
}
else if(g1X==i && g1Y==j){
table[i][j]=2;
// printf("2");
}
else if( g2X==i && g2Y==j){
table[i][j]=3;
// printf("3");
}
else if (p>=0 && r<=p){
table[i][j]=9;
// printf("9");
}
else{
table[i][j]=0;
// printf("0");
}
printf("%d ",table[i][j]);
}
printf("\n");
}
// Create the open list
int cX=sX, cY=sY;
while (cX!=g1X && cY!=g1Y)
{
int openList[4][2];
//TOP
if(cX>0 && table[cX-1][cY]!=9){
openList[0][0]=(cX-1);
openList[0][1]=cY;
}
else{
openList[0][0]=-1;
openList[0][1]=-1;
}
//BOTTOM
if(cX+1<N && table[cX+1][cY]!=9 ){
openList[1][0]=(cX+1);
openList[1][1]=cY;
}
else{
openList[1][0]=-1;
openList[1][1]=-1;
}
//RIGHT
if(cY+1<N && table[cX][cY+1]!=9){
openList[2][0]=cX;
openList[2][1]=(cY+1);
}
else{
openList[2][0]=-1;
openList[2][1]=-1;
}
//LEFT
if(cY>0 && table[cX][cY-1]!=9){
openList[3][0]=cX;
openList[3][1]=(cY-1);
}
else{
openList[3][0]=-1;
openList[3][1]=-1;
}
printf("Open List of current cell:%d,%d\n",&cX, &cY);
for (i=0;i<4;i++){
printf("%d , %d\n",openList[i][0],openList[i][1]);
cX=g1X; cY=g2Y;
}
}
return 0;
}
Questions:
I know I didn't yet add the current cell in the open list. I should add it right?
Both the openlist and the closed list should be a Hashmap?
How do you think I should keep a connection with the parent of selected cell?
The open list needs to be a priority queue. That is a queue that allows new entrants to "push in" according to their priority or importance, but we always shrink by taking from the front. Now you can do this naively with an array and sorting on each insertion, but that will be slow. A linked list won't help much (linked lists have very bad cache performance). Really you need a specially-written priority queue which keeps as much as possible together in memory.

Minimum number of steps required to reach the last index

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
I have built a dp[] array from left to right such that dp[i] indicates the minimum number of jumps needed to reach arr[i] from arr[0]. Finally, we return dp[n-1].
Worst case time complexity of my code is O(n^2).
Can this be done in a better time complexity.
This question is copied from leetcode.
int jump(vector<int>& a) {
int i,j,k,n,jumps,ladder,stairs;
n = a.size();
if(n==0 || n==1)return 0;
jumps = 1, ladder = stairs = a[0];
for(i = 1; i<n; i++){
if(i + a[i] > ladder)
ladder = i+a[i];
stairs --;
if(stairs + i >= n-1)
return jumps;
if(stairs == 0){
jumps++;
stairs = ladder - i;
}
}
return jumps;
}
You can use a range-minimum segment tree to solve this problem. A segment tree is a data structure which allows you to maintain an array of values and also query aggregate operations on subsegments of the array. More information can be found here: https://cses.fi/book/book.pdf (section 9.3)
You will store values d[i] in the segment tree, d[i] is the minimum number of steps needed to reach the last index if you start from index i. Clearly, d[n-1] = 0. In general:
d[i] = 1 + min(d[i+1], ..., d[min(n-1, i+a[i])]),
so you can find all the values in d by computing them backwards, updating the segment tree after each step. The final solution is d[0]. Since both updates and queries on segment trees work in O(log n), the whole algorithm works in O(n log n).
I think, you can boost computing the dynamic with these technique:
You spend O(N) for compute current d[i]. But you can keep a set with d[j],
where j = 0..i - 1. And now all you need to use binary search to find:
such d[j], that is minimum among all(0..i-1) and from j position i-pos is reachable.
It will be O(n * logn) solution
That is a simple excercise in dynamic programming. As you have tagged it already, I wonder why you're not trying to apply it.
Let V[k] be the minimum number of steps to get from position k to the end of the list a = (a[0], a[1], ...., a[n-1]).
Then obviously V[n-1]=0. Now loop backwards:
for(int k=n-2;k>=0;--k)
{
int minStep = n + 1;
for(int j=k+1;j<=std::min(n-1,k+a[k]);++j)
{
minStep = std::min(minStep, V[j])
}
V[k]= minStep + 1;
}
Demo in C++
After the loop, which takes O(a[0]+a[1]+...+a[n-1]) time, V[0] contains the minimum number of steps to reach the end of the list.
In order to find the way through the list, you can then choose the action greedily. That is, from position k you always go to an allowed position l where V[l] is minimal.
(Note that I've assumed positive entries of the list here, not non-negative ones. Possible zeros can easily be removed from the problem, as it is never optimal to go there.)
https://leetcode.com/problems/jump-game-ii
class Solution {
public int jump(int[] nums) {
int n = nums.length;
if(n < 2){
return 0;
}
int ans = 1;
int rightBoundaryCovered = nums[0];
for(int i=1;i<n;i++){
if(rightBoundaryCovered >= n-1){
return ans;
}
int currMax = i+ nums[i];
while(rightBoundaryCovered>=i){
currMax = Math.max(currMax, i+nums[i]);
i++;
}
//missed this decrement statement and faced multiple WA's
i--;
ans++;
if(currMax>rightBoundaryCovered){
rightBoundaryCovered = currMax;
}
}
return ans;
}
}
Java solution (From Elements of Programming Interviews):
public boolean canJump(int[] nums) {
int maximumReach = 0;
for(int i = 0; i < nums.length; i++) {
// Return false if you jump more.
if(i > maximumReach) { return false; }
// Logic is we need to keep checking every index the
// farthest we can travel
// Update the maxReach accordingly.
maximumReach = Math.max(i + nums[i], maximumReach);
}
return true;
}

Resources