I am a c++ beginner and this is my first time to write c++ in a mac environment using clang++, I had make sure clang++ had been used correctly by compile a simple program, and it runs perfectly.
The problem is I cannot compile the program in mac environment after separating the files to multiple files and using include
to link them, as well as trying to implement OOP to my sudoku and link 2 class together.
So I believe there might be something wrong related to the linker or my OOP method.
I found this article might be useful but I had tried to follow the recommend method but seems doesn't work:
https://stackoverflow.com/questions/73864774/ld-symbols-not-found-for-architecture-arm64-c
There are some other information in the internet related to "I defined a function / variable in header files but did not implemented it in the .cpp files", I don't think this is the case for me. As all defined function in header files has been implemented already. There is a few line that I am not sure did the contributor do it properly and it might be related (most likely they are able to compile with gnu g++ in wsl/linux without the most correct syntax) which are:
Sudoku.cpp
Sudoku::Sudoku(int boardHeight, int boardWidth) : Board(boardHeight, boardWidth) {}
as well as how he defined and implemented the relationship between the board and sudoku
The error message is at bellow
compile to compile : clang++ -std=c++20 main.cpp
//Error message
Undefined symbols for architecture arm64:
"Sudoku::initialize(int)", referenced from:
_main in main-ec9303.o
"Sudoku::drawBoard()", referenced from:
_main in main-ec9303.o
"Sudoku::Sudoku(int, int)", referenced from:
_main in main-ec9303.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Here is the source code: https://github.com/potatochick2020/Sudoku-core
Minimal code to post here (might not be that minimal):
main.cpp
//main.cpp
#include "Sudoku.h"
int main()
{
Sudoku sudoku;
sudoku.initialize();
sudoku.drawBoard();
}
Sudoku.h
//Sudoku.h
#pragma once
#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
#include <set>
#include <unordered_set>
#include <stack>
#include <map>
#include <numeric>
#include "Board.h"
#define SHUFFLE(x) shuffle(x.begin(), x.end(), mt19937{ random_device{}() });
#define CANDIDATE_ARRAY { 1, 2, 3, 4, 5, 6, 7, 8, 0 }
using namespace std;
class Sudoku : public Board
{
private:
bool GenerateSudoku(void);
public:
Sudoku(int boardHeight = 9, int boardWidth = 9);
// default argument only in decleration
void initialize(int difficulty = 3);
//overloading for a Board::setBoard
void setBoard(int, int, int);
void setBoard(vector<vector<int>>);
virtual void drawBoard();
bool isCorrect(void);
bool isComplete(void);
bool isValid(void);
bool isPlacable(int, int, int);
int SudokuSolution(void);
};
Board.h
#pragma once
#include <vector>
using namespace std;
// Abstract Class since it has an abstract function
class Board
{
protected:
vector<vector<int>> board;
int boardWidth, boardHeight;
Board(int, int);
// Abstaract function that must be defined by children
virtual void drawBoard() = 0;
public:
vector<vector<int>> getBoard();
void setBoard(vector<vector<int>> newBoard);
};
Board.cpp
#pragma once
#include <vector>
using namespace std;
// Abstract Class since it has an abstract function
class Board
{
protected:
vector<vector<int>> board;
int boardWidth, boardHeight;
Board(int, int);
// Abstaract function that must be defined by children
virtual void drawBoard() = 0;
public:
vector<vector<int>> getBoard();
void setBoard(vector<vector<int>> newBoard);
};
Sudoku.cpp
#include "Sudoku.h"
Sudoku::Sudoku(int boardHeight, int boardWidth) : Board(boardHeight, boardWidth) {}
bool Sudoku::isValid()
{
unordered_set<int> set;
int tar = 0;
// check horizontal
for (int i = 0; i < 9; i++)
{
set.clear();
for (int j = 0; j < 9; j++)
{
if (board[i][j] != tar && set.find(board[i][j]) != set.end())
{
return false;
}
else
{
set.insert(board[i][j]);
}
}
}
// check vertical
for (int i = 0; i < 9; i++)
{
set.clear();
for (int j = 0; j < 9; j++)
{
if (board[j][i] != tar && set.find(board[j][i]) != set.end())
{
return false;
}
else
{
set.insert(board[j][i]);
}
}
}
// check 3x3 box
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
set.clear();
for (int k = 0; k < 3; k++)
{
for (int l = 0; l < 3; l++)
{
if (board[i * 3 + k][j * 3 + l] != tar && set.find(board[i * 3 + k][j * 3 + l]) != set.end())
{
return false;
}
else
{
set.insert(board[i * 3 + k][j * 3 + l]);
}
}
}
}
}
return true;
}
bool Sudoku::isComplete()
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
if (board[row][col] == 0)
return false;
}
}
return true;
}
bool Sudoku::isCorrect(void)
{
return isValid() && isComplete();
}
bool Sudoku::isPlacable(int i, int j, int value)
{
for (int idx = 0; idx < 9; idx++)
{
if (board[i][idx] == value)
return false;
if (board[idx][j] == value)
return false;
if (board[(i / 3) * 3 + (idx / 3)][(j / 3) * 3 + (idx % 3)] == value)
return false;
}
return true;
}
void Sudoku::setBoard(int row, int col, int value)
{
board[row][col] = value;
}
bool Sudoku::GenerateSudoku()
{
vector<int> numbers(9);
while (isComplete() == false)
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
if (board[row][col] == 0)
{
// fills out the numbers vector with numbers from 1 -> numbers.size()
iota(begin(numbers), end(numbers), 1);
SHUFFLE(numbers);
for (int number : numbers)
{
if (isPlacable(row, col, number))
{
// if (true){
board[row][col] = number;
if (Sudoku::GenerateSudoku())
return true;
board[row][col] = 0;
}
}
return false;
}
}
}
}
return true;
}
int Sudoku::SudokuSolution()
{
int ans = 0;
vector<int> numbers(9);
// fills out the numbers vector with numbers from 1 -> numbers.size()
iota(begin(numbers), end(numbers), 1);
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
if (board[row][col] == 0)
{
for (int number : numbers)
{
if (isPlacable(row, col, number))
{
board[row][col] = number;
if (isCorrect())
ans++;
else
ans += Sudoku::SudokuSolution();
board[row][col] = 0;
}
}
return ans;
}
}
}
return 0;
}
void Sudoku::initialize(int difficulty)
{
GenerateSudoku();
vector<int> rowsCandidates = CANDIDATE_ARRAY;
SHUFFLE(rowsCandidates);
vector<int> colsCandidates = CANDIDATE_ARRAY;
SHUFFLE(colsCandidates);
pair<pair<int, int>, int> backup = {{rowsCandidates[0], colsCandidates[0]}, board[rowsCandidates[0]][colsCandidates[0]]};
board[rowsCandidates[0]][colsCandidates[0]] = 0;
int attempt = 0;
while (attempt < difficulty)
{
rowsCandidates = CANDIDATE_ARRAY;
SHUFFLE(rowsCandidates);
colsCandidates = CANDIDATE_ARRAY;
SHUFFLE(colsCandidates);
backup = {{rowsCandidates[0], colsCandidates[0]}, board[rowsCandidates[0]][colsCandidates[0]]};
board[rowsCandidates[0]][colsCandidates[0]] = 0;
if (SudokuSolution() > 1)
{
board[backup.first.first][backup.first.second] = backup.second;
attempt++;
}
}
};
void Sudoku::drawBoard()
{
// this implementation done by @AshishRaikwar1290
for (int row = 0; row < boardHeight; row++)
{
for (int col = 0; col < boardHeight; col++)
{
if (col == 3 || col == 6)
cout << " | ";
cout << board[row][col] << " ";
}
if (row == 2 || row == 5)
{
cout << endl;
for (int i = 0; i < boardHeight; i++)
cout << "---";
}
cout << endl;
}
}
I expect it could compile properly, and when i do ./a.out
, it should print a sudoku out. (see drawBoard() in Sudoku.cpp)