Commit 6893067c authored by Ing. Miroslav Biňas PhD.'s avatar Ing. Miroslav Biňas PhD.
Browse files

Merge branch 'develop' into 'master'

verzia 2019.2

See merge request !5
parents fc30a101 f5894068
......@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.9)
# Set project
project("Karel the Robot C Library" C)
set(PROJECT_VERSION_MAJOR 2019)
set(PROJECT_VERSION_MINOR 1)
set(PROJECT_VERSION_MINOR 2)
# for the Curses library to load
find_package(Curses REQUIRED)
......
......@@ -7,6 +7,25 @@ programming language*.
For more information about Karel the robot visit the Wikipedia page at
http://en.wikipedia.org/wiki/Karel_(programming_language)
## Usage
There are two libraries included in this package:
* `karel.h` - the basic _Karel the Robot_ library with the essential commands and sensors; suitable for beginneris in programming
* `superkarel.h` - the extended version of _Karel the Robot_ library, when _Karel_ is fully equipped with all of the sensors and commands; suitable for problem solvers
To compile program with _karel.h_ library:
```bash
gcc program.c -o program -lkarel -lcurses
```
To compile program with _superkarel.h_ library:
```bash
gcc program.c -o program -lkarel -lcurses
```
## Dependencies
......
......@@ -2,6 +2,19 @@
## Todo
### Version Info
* provide version info some way
* in credits?
* `--version` / `-v` ?
### Refactoring the Export
* move `internals.c` to `core.c`
* create module for exports only
* distinguish different export modes to at least separate functions (JSON, YAML, text, XML, ...)
### NCurses alternatives
- move from ncurses to s-lang
......@@ -11,13 +24,6 @@
- more interesting ;)
### `_error_shut_off()` update
* make it with variable length arguments
* as the `printf()`
* use it always for shut off. not only when Karel is initialized and runnig (in GUI mode)
### Support for CI
* make the tests pass first before delivery/deployment
......@@ -31,6 +37,12 @@
## Done
### `_error_shut_off()` update
* make it with variable length arguments
* as the `printf()`
* use it always for shut off. not only when Karel is initialized and runnig (in GUI mode)
### Internationalization
......@@ -65,4 +77,4 @@
### Naming Conventions
* rewrite from Java/C++ style to C style
* done in 2019.1
\ No newline at end of file
* done in 2019.1
......@@ -5,3 +5,8 @@
add_executable(stairs stairs.c)
target_link_libraries(stairs LINK_PUBLIC karel)
set_property(TARGET stairs PROPERTY CXX_STANDARD 11)
add_executable(training training.c)
target_link_libraries(training LINK_PUBLIC karel)
set_property(TARGET training PROPERTY CXX_STANDARD 11)
#include <karel.h>
void turn_right(){
loop(3){
turn_left();
}
}
void jump(){
turn_left();
step();
turn_right();
step();
turn_right();
step();
turn_left();
}
int main(){
// turn on karel in the world training.kw
turn_on("training.kw");
// pick all beepers on all stairs
while(!beepers_present()){
jump();
}
// turn off
turn_off();
}
6 2 1 1 E 0
W 1 1 E
W 2 1 E
W 3 1 E
W 4 1 E
W 5 1 E
B 5 1 1
......@@ -89,6 +89,23 @@ void _render();
void _update(int dx, int dy);
/**
* Exit Karel with error message
* Karel is exited with status code EXIT_FAILURE (1). Whole behaviour
* depends on the state, when the function is called:
*
* 1. when karel is not running:
* only the error message is print out
*
* 2. when karel is not running and the summary is on
* only error message is print out in the form of summary type
*
* 3. when karel is running and no summary is on
* error message is written to the Karel's UI
*
* 4. when karel is running and summary is on
* error message with the world representation without walls is print out in the form of summary type
*/
void _error_shut_off(const char *format, ...);
......@@ -104,7 +121,7 @@ void _deinit();
* Export is useful in summary mode only. Summary mode can be enabled
* with environment variable LIBKAREL_SUMMARY_MODE with it's value "true".
*/
void _export_data();
void _export_data(const char* format, ...);
/**
......
......@@ -7,6 +7,7 @@
#include <string.h>
#include <signal.h>
#include <libintl.h>
#include <stdarg.h>
#define _(STRING) gettext(STRING)
......@@ -34,7 +35,7 @@ struct summary _summary = {
void _print_beeper(int nr){
if(_summary.is_active == true){
if(_summary.is_active){
return;
}
......@@ -177,9 +178,11 @@ void _draw_world(){
}
/**
* update old position, if karel has moved
*/
void _update(int dx, int dy){
// update old position, if karel has moved
if(!(dx == 0 && dy == 0)){
if(dx != 0 || dy != 0){
int block = _world.data[_karel.y - 2*dy][_karel.x - 2*dx];
if(!_summary.is_active){
......@@ -195,7 +198,7 @@ void _update(int dx, int dy){
void _render(){
if(_summary.is_active == true){
if(_summary.is_active){
return;
}
......@@ -241,20 +244,38 @@ void _render(){
void _error_shut_off(const char* format, ...){
if(!_summary.is_active){
va_list args;
va_start(args, format);
if(_karel.is_running && !_summary.is_active){
if(has_colors()){
attron(COLOR_PAIR(RED_ON_BLACK));
}
mvprintw(0, 0, _("Error Shutoff! (%s)"), format);
// there is error message stored in the format
// no formatting is necessary
mvprintw(0, 0, _("Safety Shutdown: %s"), format);
refresh();
getchar();
endwin();
}else if(_summary.is_active && strcmp(_summary.type, "json") == 0){
if(_karel.is_running){
_export_data(format, args);
}else{
printf("{\"error\": \"");
vprintf(format, args);
printf("\"}\n");
}
}else{
fprintf(stderr, _("Error Shutoff! (%s)"), format);
fprintf(stderr, _("Error: "));
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
}
va_end(args);
exit(EXIT_FAILURE);
}
......@@ -294,6 +315,7 @@ void _deinit(){
if(has_colors()){
attron(COLOR_PAIR(YELLOW_ON_BLACK));
}
mvprintw(0, 0, _("Press any key to quit..."));
refresh();
getchar();
......@@ -301,7 +323,7 @@ void _deinit(){
}
void _export_data(){
void _export_data(const char* format, ...){
// prepare direction
char direction;
switch(_karel.direction){
......@@ -313,40 +335,58 @@ void _export_data(){
}
if(_summary.type && strcmp(_summary.type, "json") == 0){
printf("{\n"
"\"x\": %d,\n"
"\"y\": %d,\n"
"\"direction\": \"%c\",\n"
"\"bag\": %d,\n"
"\"beepers\": [\n",
// karel the robot
printf("{"
"\"karel\": {"
"\"x\": %d,"
"\"y\": %d,"
"\"direction\": \"%c\","
"\"bag\": %d"
"},"
"\"beepers\": [",
(_karel.x+2)/2, (_karel.y+2)/2, direction, _karel.beepers);
// export world
// export beepers from the world
bool any_beeper = false;
for(size_t row = 0; row < _world.height/2+1; row++){
for(size_t col = 0; col < _world.width/2+1; col++){
for(size_t row = 0; row < _world.height; row++){
for(size_t col = 0; col < _world.width; col++){
if(_world.data[row][col] > 0){
if(any_beeper == false){
any_beeper = true;
}else{
printf(",\n");
printf(",");
}
printf(" {\"x\": %zu, \"y\": %zu, \"count\": %d}", col, row, _world.data[row][col]);
printf("{\"x\": %zu, \"y\": %zu, \"count\": %d}", col/2+1, row/2+1, _world.data[row][col]);
}
}
}
printf("\n]}");
printf("]");
// export also error message
if(format != NULL){
va_list args;
va_start(args, format);
printf(",");
printf("\"error\": \"");
vprintf(format, args);
printf("\"");
va_end(args);
}
printf("}\n");
}else{
// header
printf("%d %d %c %d\n",
(_karel.x+2)/2, (_karel.y+2)/2, direction, _karel.beepers);
// export world
for(size_t row = 0; row < _world.height/2+1; row++){
for(size_t col = 0; col < _world.width/2+1; col++){
for(size_t row = 0; row < _world.height; row++){
for(size_t col = 0; col < _world.width; col++){
if(_world.data[row][col] > 0){
printf("B %zu %zu %d\n", col, row, _world.data[row][col]);
printf("B %zu %zu %d\n", col/2+1, row/2+1, _world.data[row][col]);
}
}
}
......
......@@ -87,8 +87,9 @@ void step() {
_karel.steps++;
_karel.last_command = _("STEP");
_render();
} else
_error_shut_off(_("Can't move this way"));
} else {
_error_shut_off(_("Can't move this way."));
}
}
......@@ -114,7 +115,7 @@ void turn_off() {
// if summary, then export data
if (_summary.is_active) {
_export_data();
_export_data(NULL);
}
// free memory
......@@ -150,8 +151,7 @@ void turn_on(const char *path) {
if(path != NULL){
fp = fopen(path, "r");
if (fp == NULL) {
fprintf(stderr, _("Error: World file '%s' not found.\n"), path);
exit(EXIT_FAILURE);
_error_shut_off(_("World file '%s' not found."), path);
}
}
......@@ -160,8 +160,7 @@ void turn_on(const char *path) {
if (fscanf(fp, "%d %d %d %d %c %d\n",
&_world.width, &_world.height, &_karel.x, &_karel.y, &direction, &_karel.beepers) != 6) {
fprintf(stderr, _("Error: The world information are not in correct format!\n"));
exit(EXIT_FAILURE);
_error_shut_off(_("The world information are not in correct format!"));
}
// world correction
......@@ -174,17 +173,13 @@ void turn_on(const char *path) {
// check the world dimensions
if (_world.width > MAX_WIDTH || _world.width < 1) {
fprintf(stderr,
_("Error: The world's width is outside the range [1, %d]!\n"),
_error_shut_off(_("The world's width is outside the range [1, %d]!"),
MAX_WIDTH);
exit(EXIT_FAILURE);
}
if (_world.height > MAX_HEIGHT || _world.height < 1) {
fprintf(stderr,
_("Error: The world's height is outside the range [1, %d]!\n"),
_error_shut_off(_("The world's height is outside the range [1, %d]!"),
MAX_HEIGHT);
exit(EXIT_FAILURE);
}
// format the direction
......@@ -202,8 +197,7 @@ void turn_on(const char *path) {
_karel.direction = NORTH;
break;
default :
fprintf(stderr, _("Error: Uknown Karel's direction\n"));
exit(EXIT_FAILURE);
_error_shut_off(_("Uknown Karel's direction."));
}
// create empty world
......@@ -222,14 +216,12 @@ void turn_on(const char *path) {
// read the data
if (fscanf(fp, "%d %d %c\n", &column, &row, &orientation) != 3) {
fprintf(stderr, _("Error: Line %d: Incorrect format.\n"), line);
exit(EXIT_FAILURE);
_error_shut_off(_("Line %d: Incorrect format."), line);
}
// check correct position
if (column > _world.width || row > _world.height) {
fprintf(stderr, _("Error: Line %d: Wall position is outside the world!\n"), line);
exit(EXIT_FAILURE);
_error_shut_off(_("Line %d: Wall position is outside the world!"), line);
}
column2 = column * 2 - 2;
......@@ -237,8 +229,7 @@ void turn_on(const char *path) {
// check, if the wall is correctly positioned
if (column2 % 2 == 1 || row2 % 2 == 1) {
fprintf(stderr, _("Error: Wrong position.\n"));
exit(EXIT_FAILURE);
_error_shut_off(_("Wrong position."));
}
// set walls
......@@ -256,11 +247,8 @@ void turn_on(const char *path) {
row2--;
break;
default :
fprintf(stderr,
_("Error: Uknown wall orientation '%c'"
" on line %d in world file.\n"),
orientation, line);
exit(EXIT_FAILURE);
_error_shut_off(_("Uknown wall orientation '%c' on line"
" %d in world file."), orientation, line);
}
_world.data[row2][column2] = WALL;
......@@ -287,16 +275,12 @@ void turn_on(const char *path) {
case 'B': {
if (fscanf(fp, "%d %d %d\n", &column, &row, &count) != 3) {
fprintf(stderr, _("Error: Line %d: Incorrect format.\n"), line);
exit(EXIT_FAILURE);
_error_shut_off(_("Line %d: Incorrect format."), line);
}
// check correct position
if (column > _world.width || row > _world.height) {
fprintf(stderr,
_("Error: Line %d: Beeper position is outside the world!\n"),
line);
exit(EXIT_FAILURE);
_error_shut_off(_("Line %d: Beeper position is outside the world!"), line);
}
_world.data[row * 2 - 2][column * 2 - 2] = count;
......@@ -304,9 +288,7 @@ void turn_on(const char *path) {
}
default :
fprintf(stderr, _("Error: Unknown block character %c "
"on line %d in world file.\n"), block, line);
exit(EXIT_FAILURE);
_error_shut_off(_("Unknown block character %c on line %d in world file."), block, line);
}
line++;
......@@ -335,7 +317,7 @@ void put_beeper() {
_karel.last_command = _("PUT BEEPER");
_render();
} else {
_error_shut_off(_("Karel has no beeper to put at the corner"));
_error_shut_off(_("Karel has no beeper to put at the corner."));
}
}
......@@ -350,7 +332,7 @@ void pick_beeper() {
_karel.last_command = _("PICK BEEPER");
_render();
} else {
_error_shut_off(_("There is no beeper at the corner"));
_error_shut_off(_("There is no beeper at the corner."));
}
}
......
......@@ -24,8 +24,8 @@ START_TEST(when_one_beeper_is_in_bag_then_return_true)
}
END_TEST
START_TEST(
when_beepers_gt_one_are_in_the_bag_then_return_true)
START_TEST(when_beepers_gt_one_are_in_the_bag_then_return_true)
{
_karel.beepers = rand() % (RAND_MAX - 1);
_karel.is_running = true;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment