Skip to content

Instantly share code, notes, and snippets.

@KiJeong-Lim
Last active February 19, 2024 13:48
Show Gist options
  • Save KiJeong-Lim/1944529b4b1093f9506b5a374857fdcc to your computer and use it in GitHub Desktop.
Save KiJeong-Lim/1944529b4b1093f9506b5a374857fdcc to your computer and use it in GitHub Desktop.
Dev-C++ works
#include <cstdint>
#include "scratch.hpp"
struct MotorInput {
float p;
float v;
float kp;
float kd;
float t_ff;
};
class MotorInputHandle : public MotorInput {
private:
std::uint8_t p_lock_lv;
std::uint8_t v_lock_lv;
std::uint8_t kp_lock_lv;
std::uint8_t kd_lock_lv;
std::uint8_t t_ff_lock_lv;
public:
MotorInputHandle(const MotorInput &initial_motor_input);
#if 0
void pack(CANMessage *can_msg) const;
#endif
void set(const MotorInput &new_motor_input);
};
void MotorInputHandle::set(const MotorInput &new_motor_input)
{
if (p_lock_lv != 0) {
p = new_motor_input.p;
}
if (v_lock_lv != 0) {
v = new_motor_input.v;
}
if (kp_lock_lv != 0) {
kp = new_motor_input.kp;
}
if (kd_lock_lv != 0) {
kd = new_motor_input.kd;
}
if (t_ff_lock_lv != 0) {
t_ff = new_motor_input.t_ff;
}
}
MotorInputHandle::MotorInputHandle(const MotorInput &initial_motor_input)
{
p = initial_motor_input.p;
v = initial_motor_input.v;
kp = initial_motor_input.kp;
kd = initial_motor_input.kd;
t_ff = initial_motor_input.t_ff;
p_lock_lv = 0;
v_lock_lv = 0;
kp_lock_lv = 0;
kd_lock_lv = 0;
t_ff_lock_lv = 0;
}
void test_cancomm()
{
MotorInputHandle handle = MotorInput({ .p = 1.0, .v = 1.0, .kp = 1.0, .kd = 1.0, .t_ff = 1.0 });
}
#include "scratch.hpp"
#define USE_PID 1
static bool areSameString(const char *lhs, const char *rhs);
static int PID_START_TICK = 390;
bool areSameStr(const char *const lhs, const char *const rhs)
{
if (lhs == NULL || rhs == NULL) {
return false;
}
return std::string{ lhs } == std::string{ rhs };
}
static
void prompt(const char *const msg)
{
char var_name[16];
char op_name[16];
int sscanf_res = 0;
int pid_start_tick = 0;
int motor_id = 0;
float value = 0.0;
bool res = false;
if (msg == NULL) {
printf("\n\r%% Leaving listening mode %%\n");
return;
}
#if USE_PID
sscanf_res = sscanf(msg, "%s %d = %f", var_name, &motor_id, &value);
if (sscanf_res == 3) {
if (areSameStr("Kp", var_name)) {
printf("Kp of motor #%d = %lf\n", motor_id, value);
res = true;
return;
}
else if (areSameStr("Ki", var_name)) {
printf("Ki of motor #%d = %lf\n", motor_id, value);
res = true;
return;
}
else if (areSameStr("Kd", var_name)) {
printf("Kd of motor #%d = %lf\n", motor_id, value);
res = true;
return;
}
else {
res = false;
}
goto RET;
}
#endif
#if USE_PID
sscanf_res = sscanf(msg, "pid start tick = %d", &pid_start_tick);
if (sscanf_res == 1) {
PID_START_TICK = pid_start_tick;
res = true;
goto RET;
}
#endif
sscanf_res = sscanf(msg, "%s", op_name);
if (sscanf_res == 1) {
if (areSameStr(op_name, "jump")) {
printf("operation=jump\n");
res = true;
}
else if (areSameStr(op_name, "standUp")) {
printf("operation=standUp\n");
res = true;
}
#if USE_PID
else if (areSameStr(op_name, "jump1")) {
printf("operation=jump1\n");
res = true;
}
else if (areSameStr(op_name, "standUp1")) {
printf("operation=standUp1\n");
res = true;
}
#endif
else {
res = false;
}
goto RET;
}
RET:
if (res) {
printf("\n\rCommand well recieved\n");
}
else {
printf("\n\rUnknown command or wrong command\n");
}
}
void proto_test_prompt(void)
{
char msg[64] = {};
gets(msg);
prompt(msg);
}
#include <time.h>
#include <windows.h>
#include <conio.h>
#include "cscratch.h"
static long long int my_time(void);
static void clear_console(void);
struct OS_C_API os = {
.sleep = Sleep,
.kbhit = kbhit,
.getch = getch,
.itime = my_time,
.clear = clear_console,
};
time_t my_time()
{
return time(NULL);
}
void clear_console()
{
system("cls");
}
#ifndef CSCRATCH_H
#define CSCRATCH_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define len(xs) (sizeof(xs)/sizeof((xs)[0]))
struct OS_C_API {
void (*sleep)(long unsigned int sleeping_time);
int (*kbhit)(void);
int (*getch)(void);
long long int (*itime)(void);
void (*clear)(void);
};
#endif
#include "scratch.hpp"
Gear::Gear(const int gear)
: gear{ gear }
, gear_cnt{ 0 }
{
}
Gear::Gear(const Gear &other)
: gear{ other.gear }
, gear_cnt{ other.gear_cnt }
{
}
Gear::~Gear()
{
}
bool Gear::go()
{
if ((gear_cnt + 1) % gear == 0) {
gear_cnt = 0;
return true;
}
if (gear_cnt >= 0) {
gear_cnt++;
}
else {
gear_cnt = 0;
}
return false;
}
void Gear::reset()
{
gear = 0;
}
#include "scratch.hpp"
std::vector<int> IntegerHelper::reads(const std::string str)
{
std::stringstream ss;
std::vector<int> ret;
std::string temp;
int found;
ss << str;
while (!ss.eof()) {
ss >> temp;
if (std::stringstream(temp) >> found) {
ret.push_back(found);
}
temp = "";
}
return ret;
}
void IntegerHelper::shows(std::vector<int> ns)
{
const size_t sz = ns.size();
for (int i = 0; i < sz; i++) {
std::cout << ns[i] << ' ';
}
std::cout << std::endl;
}
#include "scratch.hpp"
#define ESC 27
#define LEFT_DIRECTION 75
#define RIGHT_DIRECTION 77
void IO::setPrompt(void (*const prompt)(const char *msg))
{
this->prompt = prompt;
this->clear();
}
bool IO::runPrompt()
{
char *msg = NULL;
int ch = '\0';
bool prompt_routine_breaked = false;
while (1) {
ch = getc();
if (ch == 0) {
return false;
}
if (ch == ESC) {
return true;
}
prompt_routine_breaked = takech(ch);
if (prompt_routine_breaked) {
sync(msg);
prompt(msg);
clear();
return true;
}
}
}
int IO::getc()
{
int res = 0;
if (os.kbhit()) {
res = os.getch();
}
return res;
}
void IO::clear()
{
for (int i = 0; i < len(buffer); i++) {
buffer[i] = '\0';
}
cursor = 0;
theend = 0;
}
bool IO::takech(const int ch)
{
switch (ch) {
default:
if (cursor < 0) {
result = NULL;
return false;
}
if (cursor > theend) {
result = NULL;
return false;
}
if (theend + 1 >= len(buffer)) {
result = NULL;
return false;
}
for (int i = theend; i >= cursor; i--) {
buffer[i + 1] = buffer[i];
}
buffer[cursor++] = ch;
buffer[++theend] = '\0';
print();
result = NULL;
return false;
case '\b':
if (cursor > theend) {
result = NULL;
return false;
}
if (theend + 1 >= len(buffer)) {
result = NULL;
return false;
}
if (cursor <= 0) {
result = NULL;
return false;
}
for (int i = --cursor; i < theend; i++) {
buffer[i] = buffer[i + 1];
}
if (theend > 0) {
buffer[theend--] = '\0';
}
print();
result = NULL;
return false;
case '\n':
case '\r':
result = buffer;
return true;
case '\0':
return false;
case ESC:
clear();
printf("\n");
result = NULL;
return true;
case 224:
if (theend + 1 >= len(buffer)) {
result = NULL;
return false;
}
switch (getc()) {
case LEFT_DIRECTION:
if (cursor > 0) {
cursor--;
}
print();
result = NULL;
return false;
case RIGHT_DIRECTION:
if (cursor < theend) {
cursor++;
}
print();
result = NULL;
return false;
}
}
return false;
}
void IO::sync(char *&msg)
{
msg = result;
}
void IO::print()
{
int i = 0;
printf("\r");
for (i = 0; i < len(buffer); i++) {
printf(" ");
}
printf("\r");
for (i = 0; i < cursor; i++) {
printf(" ");
}
for (i = cursor; i < theend; i++) {
printf("%c", buffer[i]);
}
buffer[i] = '\0';
printf("\r");
for (int i = 0; i < cursor; i++) {
printf("%c", buffer[i]);
}
std::cout.flush();
}
static
void delta(const char *const msg)
{
printf("\n[ECHO] %s\n", msg);
}
void test_io()
{
IO comm;
bool prompt_finished = false;
comm.setPrompt(delta);
while(!prompt_finished) {
os.sleep(10);
prompt_finished = comm.runPrompt();
}
}
#include "scratch.hpp"
int main(void)
{
nonogramsolver_test();
return 0;
}
#include "scratch.hpp"
#define DEBUG 0
template <typename A> using Array = std::vector<A>;
using Generator1D = NonogramSolver::Generator1D;
static void debug_Generator1D_callback(Generator1D::cell_t *line, size_t sz);
void nonogramsolver_test() // A test function for Nonogram Solver!
{
NonogramSolver solver = {};
Array<NonogramSolver::Answer> solutions = {};
int n = 0;
solver.scanPuzzle("nonogramtest.txt");
solver.solve();
solutions = solver.getSolutions();
n = solutions.size();
for (int i = 0; i < n; i++) {
solutions[i].print();
}
}
void debug_Generator1D_callback(Generator1D::cell_t *const line, const size_t line_sz)
{
printf("================\n");
printf("0123456789ABCDEF\n");
for (int i = 0; i < line_sz; i++) {
printf("%d", line[i]);
}
printf("\n");
printf("================\n");
printf("\n");
}
void nonogramsolverlogic_test()
{
Generator1D gen = {};
int info[] = { 2, 2, 3, 1, };
Generator1D::cell_t line[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
bool well_formed = gen.init(line, len(line), info, len(info));
if (well_formed) {
gen.attach(debug_Generator1D_callback);
gen.exec();
}
}
Generator1D::Generator1D()
: callback{ nullptr }, line{ nullptr }, line_sz{ 0 }
{
}
void Generator1D::exec()
{
int block_cnt = 0;
bool last_was_black = false;
for (int i = 0; i < line_sz; i++) {
line[i] = WHITE;
}
run(line, info_sz, 0, 0);
}
bool Generator1D::attach(void (*const callback)(Generator1D::cell_t *line, size_t line_sz))
{
if (callback == nullptr) {
return false;
}
this->callback = callback;
return true;
}
void Generator1D::print() const
{
for (int i = 0; i < line_sz; i++) {
switch (line[i]) {
case BLACK:
std::cout << '#';
break;
case WHITE:
std::cout << '.';
break;
default:
std::cout << 'E';
break;
}
}
std::cout << std::endl;
}
bool Generator1D::init(Generator1D::cell_t *const line, const std::size_t line_sz, int *const info, const std::size_t info_sz)
{
this->line_sz = line_sz;
this->line = line;
this->info = info;
this->info_sz = info_sz;
return true;
}
int Generator1D::run(Generator1D::cell_t *const start, const int depth, const int block_num, const int combo)
{
#if DEBUG == 2
char char128[128];
print();
gets(char128);
#endif
#if DEBUG
printf("[CALLED: depth = %d, start = %d] ", depth, start - line);
print();
printf("\n");
#endif
if (depth == 0) {
callback(line, line_sz);
return 0;
}
else {
const int block_sz = info[block_num];
cell_t *left = start, *right = start;
int go = combo, t = 0, res = 0;
if (left + block_sz > line + line_sz) {
return 1;
}
for (int b = 0; b < block_sz; b++) {
*right++ = BLACK;
}
t = run(right + 1, depth - 1, block_num + 1, combo + 1);
switch (t) {
case 0:
while (right < line + line_sz) {
*left++ = WHITE;
*right++ = BLACK;
t = run(right + 1, depth - 1, block_num + 1, 0);
if (t > 0) {
break;
}
}
case 1:
while (right > left)
*--right = WHITE;
break;
default:
if (t >= combo)
res = combo + 1;
else
res = 1;
while (right > left)
*--right = WHITE;
}
return res;
}
}
NonogramSolver::Exception::Exception(const char *const err_msg)
: err_msg{ err_msg }
{
}
const char *NonogramSolver::Exception::what() const throw ()
{
return err_msg.c_str();
}
NonogramSolver::~NonogramSolver()
{
clear();
}
NonogramSolver::Answer::Answer(Array<Array<Cell>> board)
: board{ board }
{
}
void NonogramSolver::Answer::print() const
{
for (int i = 0; i < board.size(); i++) {
for (int j = 0; j < board[i].size(); j++) {
switch (board[i][j]) {
case BLACK:
std::cout << '#';
break;
case WHITE:
std::cout << '.';
break;
default:
std::cout << 'E';
break;
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
bool NonogramSolver::setPuzzle(const Array<Array<int>> &rows, const Array<Array<int>> &cols)
{
const int m = rows.size(), n = cols.size();
bool well_formed = false;
this->rows = rows;
this->cols = cols;
this->m = m;
this->n = n;
well_formed = puzzleWellFormed();
if (well_formed) {
this->board = new Cell [m * n];
for (int i = 0; i < m * n; i++)
board[i] = WHITE;
}
else
this->board = nullptr;
return well_formed;
}
bool NonogramSolver::puzzleWellFormed() const
{
const int m = rows.size(), n = cols.size();
int t = 0;
if (m != this->m || n != this->n)
return false;
if (m == 0 || n == 0)
return false;
for (int i = 0; i < m; i++)
if (rows[i].size() == 0)
return false;
for (int j = 0; j < n; j++)
if (cols[j].size() == 0)
return false;
for (int i = 0; i < m; i++)
if (rows[i].size() == 1 && rows[i][0] == 0)
continue;
else {
t = 0;
for (int k = 0; k < rows[i].size(); k++)
if (rows[i][k] <= 0)
return false;
else {
if (t == 0)
t += rows[i][k];
else
t += rows[i][k] + 1;
}
if (t > m)
return false;
}
for (int j = 0; j < n; j++)
if (cols[j].size() == 1 && cols[j][0] == 0)
continue;
else {
t = 0;
for (int k = 0; k < cols[j].size(); k++)
if (cols[j][k] <= 0)
return false;
else {
if (t == 0)
t += cols[j][k];
else
t += cols[j][k] + 1;
}
if (t > n)
return false;
}
return true;
}
Array<Array<NonogramSolver::Cell>> NonogramSolver::toMatrix() const
{
Array<Array<Cell>> ret = {};
for (int i = 0; i < m; i++) {
Array<Cell> line = {};
for (int j = 0; j < n; j++)
line.push_back(at(i, j));
ret.push_back(static_cast<Array<Cell> &&>(line));
}
return ret;
}
void NonogramSolver::printBoard() const
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
switch (at(i, j)) {
case BLACK:
std::cout << '#';
break;
case WHITE:
std::cout << '.';
break;
default:
std::cout << 'E';
break;
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
bool NonogramSolver::scanPuzzle(const char *const file_name)
{
Array<Array<int>> rows, cols;
std::ifstream file;
std::string line;
bool okay = false;
try {
board = nullptr;
file.open(file_name, std::ios::in);
if (file.bad()) {
throw Exception("***scanPuzzle: cannot open the file\n");
}
getline(file, line);
if (line != std::string{ "rows" }) {
throw Exception("***scanPuzzle: expected \'rows\'\n");
}
while (getline(file, line)) {
if (line == std::string{ "cols" })
break;
rows.push_back(IntegerHelper::reads(line));
}
while (getline(file, line)) {
if (line == std::string{ "end" })
break;
cols.push_back(IntegerHelper::reads(line));
}
file.close();
okay = setPuzzle(rows, cols);
}
catch (const std::exception &e) {
std::cerr << e.what();
file.close();
}
return okay;
}
void NonogramSolver::clear()
{
delete board;
board = nullptr;
m = 0;
n = 0;
rows.clear();
cols.clear();
solutions.clear();
}
const Array<NonogramSolver::Answer> &NonogramSolver::getSolutions() const
{
return solutions;
}
void NonogramSolver::solve()
{
int num = 0;
for (int i = 0; i < m; i++)
num += rows[i].size();
run(board, num, 0, 0);
}
bool NonogramSolver::isAnswer()
{
int black_cnt = 0, k = 0;
for (int j = 0; j < n; j++) {
black_cnt = 0;
k = 0;
for (int i = 0; i < m; i++)
if (at(i, j) == BLACK)
black_cnt++;
else {
if (black_cnt > 0) {
if (cols[j][k] == black_cnt)
k++;
else
return false;
}
black_cnt = 0;
}
if (black_cnt > 0) {
if (cols[j][k] != black_cnt)
return false;
else
k++;
}
if (cols[j].size() == 1 && cols[j][0] == 0) {
if (k != 0)
return false;
}
else {
if (k != cols[j].size())
return false;
}
}
return true;
}
int NonogramSolver::run(NonogramSolver::Cell *const start_point, const int depth, const int i, const int block_num)
{
#if DEBUG
char char128[128];
printf("[CALLED: start_point = %d, depth = %d, i = %d, block_num = %d]\n", start_point - board, depth, i, block_num);
printBoard();
printf("\n");
gets(char128);
#endif
if (depth == 0) {
if (isAnswer())
solutions.push_back(Answer{toMatrix()});
return 1;
}
else {
const int block_sz = rows[i][block_num], next_depth = depth - 1;
Cell *left = start_point, *right = start_point, *next_floor = nullptr;
int next_i = i, next_block_num = block_num + 1;
if (rows[i].size() == 1 && rows[i][0] == 0)
return run(&board[(i + 1) * n], next_depth, i + 1, 0);
if (left + block_sz > &board[(i + 1) * n])
return 0;
if (block_num + 1 == rows[i].size()) {
next_i = i + 1;
next_floor = &board[(i + 1) * n];
next_block_num = 0;
}
for (int b = 0; b < block_sz; b++)
*right++ = BLACK;
if (next_floor == nullptr)
while (run(right + 1, next_depth, next_i, next_block_num)) {
if (right >= &board[(i + 1) * n])
break;
*left++ = WHITE;
*right++ = BLACK;
}
else
while (run(next_floor, next_depth, next_i, next_block_num)) {
if (right >= &board[(i + 1) * n])
break;
*left++ = WHITE;
*right++ = BLACK;
}
while (right > left)
*--right = WHITE;
return 1;
}
}
NonogramSolver::Cell &NonogramSolver::at(const int i, const int j)
{
return board[i * n + j];
}
const NonogramSolver::Cell &NonogramSolver::at(const int i, const int j) const
{
return board[i * n + j];
}
rows
6
2 2
2 2
2
2
4
2
0
2
2
cols
0
2
3
1
1 2 2
1 2 2
1 1
6
4
0
end
#include "scratch.hpp"
template <typename Real_t>
Real_t middle(const Real_t x, const Real_t y, const Real_t z)
// returns the 2nd largest value among x, y and z
{
if (y <= x && x <= z || z <= x && x <= y) {
return x;
}
if (x <= y && y <= z || z <= y && y <= x) {
return y;
}
return z;
}
/// PV = y(t): Process variable -- measured value;
/// MV = u(t): Manipulated variable -- PID output;
/// SP = r(t): Setpoint -- reference value.
PIDController::PIDController(const Real_t Kp, const Real_t Ki, const Real_t Kd, Real_t *const PV, Real_t *const MV, Real_t *const SP, const Real_t MV_MIN, const Real_t MV_MAX)
: last_error{ 0.0 }, error_sum{ 0.0 }
, Kp{ Kp }, Ki{ Ki }, Kd{ Kd }
, PV{ PV }, MV{ MV }, SP{ SP }
, MV_MIN{ MV_MIN }, MV_MAX{ MV_MAX }
{
}
/// Check whether the PID controller is set up properly.
bool PIDController::init()
{
using namespace std::chrono;
if (PV == NULL || MV == NULL || SP == NULL) {
return false;
}
if (Kp < 0.0f || Ki < 0.0f || Kd < 0.0f) {
return false;
}
if (MV_MIN >= MV_MAX) {
return false;
}
last_time = high_resolution_clock::now();
last_error = (*SP - *PV);
error_sum = 0.0f;
return true;
}
/// Calculate u(t) with the PID algorithm and assign it to MV.
bool PIDController::compute()
{
using namespace std::chrono;
if (PV == NULL || MV == NULL || SP == NULL) {
return false;
}
else {
const auto now = high_resolution_clock::now();
Real_t dt = 0.001 * ((now - last_time) / milliseconds(1));
Real_t errval = (*SP - *PV);
Real_t derrval = (errval - last_error);
error_sum += errval * dt;
*MV = middle<Real_t>(MV_MIN, Kp * errval + Ki * error_sum + Kd * (derrval / dt), MV_MAX);
last_time = now;
last_error = errval;
return true;
}
}
void test_pidController()
{
using namespace std::chrono;
using Time_t = time_point<high_resolution_clock>;
PIDController::Real_t r = -0.1;
PIDController::Real_t u = 0.0;
PIDController::Real_t y = -0.01;
PIDController pid = { .Kp = 1, .Ki = 1, .Kd = 1, .PV = &y, .CV = &u, .SP = &r, .MV_MIN = -10, .MV_MAX = 10 };
Gear gear = { .gear = 2 };
int i = 0;
Time_t last = high_resolution_clock::now();
pid.init();
while (1) {
os.sleep(100);
pid.compute();
if (gear.go()) {
const int j = ++i;
const Time_t present = high_resolution_clock::now();
const double dt = (present - last) / milliseconds(1);
printf("r(%d) = %lf; u(%d) = %lf; y(%d) = %lf; %% dt = %.lf[ms]\n", j, r, j, u, j, y, dt);
last = present;
}
}
}
#ifndef SCRATCH_HPP
#define SCRATCH_HPP
#include <iostream>
#include <chrono>
#include <vector>
#include <functional>
#include <exception>
#include <fstream>
#include <sstream>
#include "cscratch.h"
extern "C" {
extern const struct OS_C_API os;
};
class IntegerHelper {
public:
static std::vector<int> reads(std::string str);
static void shows(std::vector<int> nums);
};
class IO {
char buffer[64];
int cursor;
int theend;
char *result;
void (*prompt)(const char *msg);
public:
IO() = default;
IO(const IO &other) = default;
~IO() = default;
void setPrompt(void (*prompt)(const char *msg));
bool runPrompt(void);
static int getc(void);
private:
bool takech(int ch);
void print(void);
void clear(void);
void sync(char *&msg);
};
class PIDController {
public:
typedef double Real_t;
private:
std::chrono::time_point<std::chrono::high_resolution_clock> last_time;
volatile Real_t last_error;
volatile Real_t error_sum;
public:
Real_t Kp;
Real_t Ki;
Real_t Kd;
Real_t *PV;
Real_t *MV;
Real_t *SP;
Real_t MV_MIN;
Real_t MV_MAX;
public:
PIDController(Real_t Kp, Real_t Ki, Real_t Kd, Real_t *PV, Real_t *MV, Real_t *SP, Real_t MV_MIN, Real_t MV_MAX);
bool init(void);
bool compute(void);
};
class Gear {
public:
int gear;
private:
int gear_cnt;
public:
Gear(int gear);
Gear(const Gear &other);
~Gear();
bool go(void);
void reset(void);
};
class NonogramSolver {
public:
class Generator1D {
public:
typedef int cell_t;
public:
void (*callback)(Generator1D::cell_t *line, size_t line_sz);
cell_t *line;
std::size_t line_sz;
int *info;
std::size_t info_sz;
public:
Generator1D();
~Generator1D() = default;
Generator1D(const Generator1D &other) = default;
void exec(void);
bool attach(void (*callback)(cell_t *line, size_t line_sz));
void print(void) const;
bool init(Generator1D::cell_t *line, std::size_t line_sz, int *info, std::size_t info_sz);
private:
int run(Generator1D::cell_t *rel_coord, int depth, int block_num, int combo);
};
typedef int Cell;
static constexpr Cell BLACK = 1;
static constexpr Cell WHITE = 0;
class Exception : public std::exception {
std::string err_msg;
public:
Exception(const char *err_msg);
~Exception() = default;
Exception(const Exception &other) = default;
const char *what(void) const throw ();
};
class Answer {
std::vector<std::vector<Cell>> board;
public:
Answer(std::vector<std::vector<Cell>> board);
~Answer() = default;
Answer(const Answer &other) = default;
void print(void) const;
};
private:
std::vector<std::vector<int>> rows;
std::vector<std::vector<int>> cols;
Cell *board;
int m;
int n;
std::vector<Answer> solutions;
public:
NonogramSolver() = default;
~NonogramSolver();
NonogramSolver(const NonogramSolver &other) = default;
bool setPuzzle(const std::vector<std::vector<int>> &rows, const std::vector<std::vector<int>> &cols);
bool puzzleWellFormed(void) const;
std::vector<std::vector<Cell>> toMatrix(void) const;
bool scanPuzzle(const char *file_name);
void clear(void);
void solve(void);
const std::vector<Answer> &getSolutions(void) const;
private:
bool isAnswer(void);
int run(Cell *start_point, int depth, int i, int block_num);
Cell &at(int i, int j);
const Cell &at(int i, int j) const;
void printBoard(void) const;
};
void test_io(void);
void test_pid(void);
void test_variable(void);
void test_cancomm(void);
void test_pidController(void);
void proto_test_prompt(void);
void nonogramsolver_test(void);
void nonogramsolverlogic_test(void);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment