0

I am a relatively new to coding and new to stackoverflow. I am creating a game of gomoku, where need to get five pieces in a row to win the game. I have initialized the board, 2d array, all to zero at beginning. The board size is based from an input file. I have created two algorithms the first one being random, and the second is meant to place a piece, one block away from its previous move. The second is meant to be the "smarter" algorithm. I have also printed the array and couted a lot of "tests" / "moves"to see which path is being taken. For some reason the second algorithm seems to not to be placing pieces the whole time, as therefore leads to zeroes appearing when the maximum number of turns is played to fill the board. I have also used a class. I am also aware that I will need to eventually make my functions in the class private not public in the end.

Here is the code of the input

6

Here is the int main

#include <iostream>
#include <fstream>
#include "game.h"
#include <iomanip>
#include <ctime>
using namespace std;



int main() {
    string inputSize = "input.txt";
    int size =0;
    srand(time(0));

    int arr[15][15];

    game Gomuko;

    size = Gomuko.getSize(inputSize, arr);

    Gomuko.initZero(arr, size);

    Gomuko.switchPlayers(arr, size);

    Gomuko.printArr(arr,size);




    return 0;
}

The .cpp of the class

#include "game.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <ctime>
using namespace std;

game::game() {
    // TODO Auto-generated constructor stub

}

int game::getSize(string inputFileName, int dataArray[15][15]) {
    ifstream inputData;

    int size = 0;
    int counter = 0;

    inputData.open(inputFileName);

    if (!inputData) {
        cout << "Cannot open the file \"" << inputFileName << "\"" << endl;
    }
    while (inputData >> size) {
        counter++;
    }
    cout << "There are " << counter << " board sizes in the inputFile" << endl;
    cout << "The size of the board is " << size << "x" << size << endl << endl;
    return size;
}

void game::initZero(int arr[][15], int size) {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            arr[i][j] = 0;
        }
    }
}

void game::printArr(int arr[][15], int size) {

    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }

    cout << endl << endl;
}

int game::randRow(int size) {

    int randNoRow = 0;
    randNoRow = rand() % size;
    return randNoRow;
}

int game::randCol(int size) {

    int randNoCol = 0;
    randNoCol = rand() % size;
    return randNoCol;
}
void game::movePlayerOneFirstMove(int arr[][15], int size) {
    int randNoRow = 0;
    int randNoCol = 0;
    int counter2 = 0;

    randNoRow = randRow(size);
    cout << "randNoRow = " << randNoRow << endl;

    randNoCol = randCol(size);
    cout << "randNoCol = " << randNoCol << endl;

    cout << endl;

    arr[randNoRow][randNoCol] = 1;
    counter2++;
}

int game::findFirstMoveRow(int arr[][15], int size) {
    int positionRow;
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (arr[i][j] == 1) {
                positionRow = i;
            }
        }
    }

    return positionRow;
}

int game::findFirstMoveCol(int arr[][15], int size) {
    int positionCol;
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (arr[i][j] == 1) {
                positionCol = j;
            }
        }
    }

    return positionCol;
}

int game::PlayerOneSurroundRow(int arr[][15], int size) {

    int positionRow = game::findFirstMoveRow(arr, size);
    cout << "The old row is " << positionRow << endl;

    int oldRow = positionRow;
    int randChoice = 0;
    int newRow = 0;

    randChoice = (rand() % 3);
    cout << "randChoice Row case:  " << randChoice << endl;

    switch (randChoice) {
    case 0:
        newRow = oldRow - 1;
        break;
    case 1:
        newRow = oldRow;
        break;
    case 2:
        newRow = oldRow + 1;
        break;
    }
    cout << "Test2" << endl << endl;
    if (newRow > size - 1) {
        cout << "Row too big as Row is " << newRow << endl;
        newRow = newRow - 1;
        cout << "Row is now " << newRow << endl;

    }
    if (newRow < 0) {
        cout << "Row too small as row is " << newRow << endl;
        newRow = newRow + 1;
        cout << "Row is now " << newRow << endl;

    }

    cout << "The new row is: " << newRow << endl;

    return newRow;
}

int game::PlayerOneSurroundCol(int arr[][15], int size) {

    int positionCol = findFirstMoveCol(arr, size);
    cout << "The old col is " << positionCol << endl;

    int oldCol = positionCol;
    int randChoice = 0;
    int newCol = 0;

    randChoice = (rand() % 3);
    cout << "randChoice Col case: " << randChoice << endl;

    switch (randChoice) {
    case 0:
        newCol = oldCol - 1;
        break;
    case 1:
        newCol = oldCol;
        break;
    case 2:
        newCol = oldCol + 1;
        break;
    }
    cout << "Test2" << endl << endl;
    if (newCol > size - 1) {
        cout << "Col too big as is " << newCol << endl;
        newCol = newCol - 1;
        cout << "Col is now " << newCol << endl;
    }
    if (newCol < 0) {
        cout << "Col too small as is " << newCol << endl;
        newCol = newCol + 1;
        cout << "Col is now " << newCol << endl;

    }

    cout << "The new col is: " << newCol << endl;

    return newCol;
}

void game::movePlayerOne(int arr[][15], int size, int counter2) {

    int newRow = 0;
    int newCol = 0;
    int oldRow = 0;
    int oldCol = 0;
    int count3 = 0;

    if (counter2 == 0) {
        game::movePlayerOneFirstMove(arr, size);
        cout << "Test1" << endl << endl << endl;
        counter2++;
    }

    else {

        cout << "Test 3" << endl;

        newRow = game::PlayerOneSurroundRow(arr, size);
        newCol = game::PlayerOneSurroundCol(arr, size);

        if (arr[newRow][newCol] == 0 && (newRow < size) && (newCol < size)
                && (newRow > 0) && (newCol > 0)) {
            arr[newRow][newCol] = 1;
            cout << "Test4" << endl;
            cout << "randNoRow = " << newRow << endl;
            cout << "randNoCol = " << newCol << endl;

            oldRow = newRow;
            oldCol = newCol;
        }

        else if ((arr[newRow][newCol] == 1) || (arr[newRow][newCol] == 2)
                || (newRow > size) || (newCol > size) || (newRow < 0)
                || (newCol < 0)) {
            cout
                    << "There has been a match, or even out of bounds, going again. "
                    << endl << endl;

            while ((arr[newRow][newCol] == 1) || (arr[newRow][newCol] == 2)) {

                cout << "Test5" << endl;
                newRow = game::PlayerOneSurroundRow(arr, size);
                newCol = game::PlayerOneSurroundCol(arr, size);

                cout << "randNoRow = " << newRow << endl;
                cout << "randNoCol = " << newCol << endl;

                count3++;
                if ((arr[newRow][newCol] != 1 && arr[newRow][newCol] != 2)
                        && (newRow < size) && (newCol < size) && (newRow >= 0)
                        && (newCol >= 0)) {
                    arr[newRow][newCol] = 1;
                    cout << "Test6" << endl;

                    cout << "randNoRow = " << newRow << endl;
                    cout << "randNoCol = " << newCol << endl;

                    oldRow = newRow;
                    oldCol = newCol;
                    break;
                }

                if (count3++ > 3) {
                    cout << "Test 7" << endl;
//                  newRow = randRow(size);
//                  newCol = randCol(size);
                    while (arr[newRow][newCol] == 1 || arr[newRow][newCol] == 2) {
                        newRow = randRow(size);
                        newCol = randCol(size);
                        cout << "Test 8" << endl;
                        cout << "randNoRow = " << newRow << endl;
                        cout << "randNoCol = " << newCol << endl;

                        if (arr[newRow][newCol] == 0) {
                            arr[newRow][newCol] = 1;
                            cout << "Test 9" << endl;
                            cout << "randNoRow = " << newRow << endl;
                            cout << "randNoCol = " << newCol << endl;
                            oldRow = newRow;
                            oldCol = newCol;
                            break;
                        }
                    }

                    break;
                }
            }

        }

//  else {
//      arr[newRow][newCol] = 1;
//  }
    }
}

void game::movePlayerTwo(int arr[][15], int size) {

    int randNoRow = 0;
    int randNoCol = 0;

    randNoRow = randRow(size);
    cout << "randNoRow = " << randNoRow << endl;

    randNoCol = randCol(size);
    cout << "randNoCol = " << randNoCol << endl;

    cout << endl;

    if ((arr[randNoRow][randNoCol] == 1) || (arr[randNoRow][randNoCol] == 2)) {
        //cout << "There has been a match, going again. " << endl << endl;
        while ((arr[randNoRow][randNoCol] == 1)
                || (arr[randNoRow][randNoCol] == 2)) {

            int randNoRow = 0;
            int randNoCol = 0;

            randNoRow = randRow(size);
            //cout << "randNoRow = " << randNoRow << endl;

            randNoCol = randCol(size);
            //cout << "randNoCol = " << randNoCol << endl;

            //cout << endl;

            if (arr[randNoRow][randNoCol] == 0) {
                arr[randNoRow][randNoCol] = 2;
                break;
            }
        }

    } else {
        arr[randNoRow][randNoCol] = 2;
    }
}

void game::switchPlayers(int arr[][15], int size) {
    int counter = 0;
    for (int i = 0; i < 36; i++) {
        cout << "This is turn " << counter + 1 << endl;
        if (counter % 2 == 0) {
            cout << "PlayerOne: " << endl;
            game::movePlayerOne(arr, size, counter);
        }
        if (counter % 2 == 1) {
            cout << "PlayerTwo:" << endl;
            game::movePlayerTwo(arr, size);
        }

        counter++;

    }

}

And the header file of the class

#ifndef GAME_H_
#define GAME_H_

#include <string>
#include <ctime>
using namespace std;

class game {
public:
    game();
    int getSize(string inputFileName, int dataArray[15][15]);
    void initZero(int arr[][15], int size);
    void printArr(int arr[][15], int size);
    void movePlayerOne(int arr[][15], int size, int counter2);
    void movePlayerOneFirstMove(int arr[][15], int size);
    void movePlayerTwo(int arr[][15], int size);
    void switchPlayers(int arr[][15], int size);
    int PlayerOneSurroundRow(int arr[][15],int size);
    int PlayerOneSurroundCol(int arr[][15],int size);
    int findFirstMoveRow(int arr[][15], int size);
    int findFirstMoveCol(int arr[][15], int size);
private:

    int randRow(int size);
    int randCol(int size);
};

#endif /* GAME_H_ */
Gabriella
  • 23
  • 5
  • Just stumbling over: `int arr[][15]` fixes your board to exactly 15 columns – which doesn't appear a good idea to me. Instead of raw arrays you might prefer a `std::vector`, that relieves you from any manual memory management. However a vector of vectors is rather inefficient (just as would be raw array of pointers), you might instead prefer a one-dimensional vector and de the index calculations manually (`fieldIndex = rowIndex * columnWidth + columnIndex`). – Aconcagua May 23 '22 at 08:53
  • In `movePlayerTwo` the expression `randCol(size);` is wrong for any `size` but 15... – Aconcagua May 23 '22 at 08:56
  • Your code is pretty complex – simpler would be single call to `rand` with values ranging from 0 to 7 inclusive – then 0 might correspond to one row less, one column less, 1 to one row less, same column, 2 to one row less, one column more, 3 and 4 same row, one column less or more respectively, finally 5, 6 and 7 one row more with analogous column assignment as for 0, 1, 2... – Aconcagua May 23 '22 at 09:06
  • Off-topic: `rand() % someMaximum` doesn't result in good distribution, by the way – provided no overflow can occur then `rand() * maximum / RAND_MAX` yields better results. As C++ you might want to prefer new C++ [pseudo random number facilities](https://en.cppreference.com/w/cpp/numeric/random) (since C++11). – Aconcagua May 23 '22 at 09:09
  • Just selecting randomly *any* field (or *any* neighbour) and then re-select, if occupied, might lead to too many collisions slowing down the game more and more the fuller the board gets. Recommending a new approach to select fields: 1. Random: Remember how many rows have free fields at all and use that number of rows as input for your maximum of a random value, then iterate over rows counting up until the random value is reached, *ignoring entirely* rows that have no free fields any more. Column you then can select analogously, ignoring the occupied fields. – Aconcagua May 23 '22 at 09:14
  • 2. Selecting neigbouring cells: Maintain a vector of cells that have been selected already *and* have remaining fields – of these select a cell randomly. Analogously to columns above select from number of free neighbourhood fields (see previous comment: values 0-7-number of occupied fields). Append the chosen cell to the vector, provided it has free neighbourhood yet, and drop the reference cell, if its last neighbour cell has been selected. – Aconcagua May 23 '22 at 09:18
  • Above has unweighted row selection; this effectively prefers selecting more occupied rows/neighbours of cells with less free fields as the fewer free fields share the same probability to get selected as the more ones in less occupied rows/neighbourhoods; if you want to avoid you'd additionally need to give a weight to rows/cells as its number of free columns/neighbour cells – but that would be for later... – Aconcagua May 23 '22 at 09:23
  • Weighted cell selection might look as follows (assuming appropriate `Cell` struct as provided): `std::vector m_occupied; /*class member storing cells occpied by player*/ size_t totalWeight = 0; for(auto& c : m_occupied) { totalWeight += c.freeNeighbours; }; auto selection = rand() * totalWeight / RAND_MAX; /* don't need totalWeight any more, can re-use... */ totalWeight = 0; for(auto& c : m_occupied) { totalWeight += c.freeNeighbours; if(totalWeight > selection) { /* you found the node! */ } }` – Aconcagua May 23 '22 at 09:32
  • With all above: Don't forget to adjust number of free columns/neighbours, too, if the *opponent* occupies such a field! To avoid one of the iterations you might, too, store the total weight as a member variable as well, being adjusted appropriately whenever cells are updated/added/removed. – Aconcagua May 23 '22 at 09:35
  • `switchPlayers`: Why are you making *exactly* 36 moves? Shouldn't that depend on the number of fields available? In this case 15 * size? – Aconcagua May 23 '22 at 09:39
  • Whichever algorithm you choose (yours, mine or yet another variant) – be aware that there might arise situations where *no* neighbouring node can be found any more! Most simple example: Player 2 (neighbour) starting top left corner filling up a square, Player 1 (random) selecting all of limiting row below and column at the right (+ some arbitrary additional cells not required for the situation just to make equal number of moves) – then when the square is filled player 2 has no further moves left to occupy a neighbouring cell, so it needs to select some random other free field! – Aconcagua May 23 '22 at 09:46
  • @Aconcagua Thank you so much, very appreciated. I'm doing this for the one assignment and they've limited certain parameters, like a board size of 15. I was just trying 36 moves at that moment to try see if all the moves are being put down as was having issues with the first algorithm not putting down all its moves on the board, but luckily was able to solve it just using an extra bracket for some reason I think and this allowed for all moves to be put down. I am definitely going to be looking to using vectors in future, just more comfortable with arrays at this present time. Thank you again – Gabriella May 23 '22 at 19:06

0 Answers0