Loading prj_c_training_2...
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # this GNU-makefile relies on the GCC toolchain # nb: on Windows, the Mingw-w64 package provides the mingw32-make.exe command # ( see https://web.enib.fr/~harrouet/dev_tools/#windows.mingw )
#~~~~ control global settings ~~~~ # make opt=2 --> enable optimisation, then disable debug, but keep symbols # make opt=1 --> enable optimisation, then disable debug # make opt=0 --> disable optimisation, then enable debug opt=0 # make clang=1 --> use clang/clang++, not gcc/g++ # make clang=0 --> use gcc/g++, not clang/clang++ clang=0 # make wasm=1 --> target webassembly rather than the native platform # make wasm=0 --> target the native platform rather than webassembly wasm=0
#~~~~ build library or programs ~~~~ # if LIB_TARGET is provided, this library will be built (with its # platform-specific name), otherwise ${EXE_PREFIX}* programs will be built LIB_TARGET= EXE_PREFIX=prog
#~~~~ detect operating system ~~~~ ifneq (${OS},Windows_NT) ifneq (,${findstring Ubuntu,${shell lsb_release -i 2>/dev/null}}) OS:=Ubuntu else ifneq (,${findstring Raspbian,${shell lsb_release -i 2>/dev/null}}) # Standard distribution for Raspberry-Pi OS:=Raspbian else OS:=${strip ${shell uname -s}} endif ifneq (,${findstring Microsoft,${shell cat /proc/version 2>/dev/null}}) # Windows-Subsystem-for-Linux OS:=${OS}_WSL endif endif
#~~~~ adjust project-specific settings ~~~~ CPPFLAGS= # CPPFLAGS+=-I header/path LDFLAGS=-lm # LDFLAGS+=-L library/path -Wl,-rpath,library/path -l library_name CFLAGS= CXXFLAGS= BINFLAGS= ifneq (,${findstring Windows_NT,${OS}}) # nothing special for now else ifneq (,${strip ${LIB_TARGET}}) BINFLAGS+=-fPIC endif ifneq (,${findstring Darwin,${OS}}) # nothing special for now else ifneq (,${findstring Ubuntu,${OS}}) # sanitizer sometimes requires gold-linker on Ubuntu LDFLAGS+=-fuse-ld=gold else ifneq (,${findstring Raspbian,${OS}}) # some warnings may appear when mixing g++-6 and g++-7 on Raspbian CXXFLAGS+=-Wno-psabi else # nothing special for now endif endif endif
#~~~~ adjust platform-specific features (Posix/Windows/Emscripten...) ~~~~ ifneq (,${findstring Windows_NT,${OS}}) LIB_PREFIX= LIB_SUFFIX=.dll EXE_SUFFIX=.exe SKIP_LINE=echo. REMOVE=del /q else LIB_PREFIX=lib ifneq (,${findstring Darwin,${OS}}) LIB_SUFFIX=.dylib else LIB_SUFFIX=.so endif EXE_SUFFIX= SKIP_LINE=echo REMOVE=rm -rf endif ifeq (${strip ${wasm}},1) LIB_PREFIX:=lib LIB_SUFFIX:=.bc EXE_SUFFIX:=.html endif
#~~~~ deduce file names ~~~~ ifneq (,${strip ${LIB_TARGET}}) LIB_TARGET:=${LIB_PREFIX}${strip ${LIB_TARGET}}${LIB_SUFFIX} MAIN_C_FILES= MAIN_CXX_FILES= else LIB_TARGET:= MAIN_C_FILES=${wildcard ${strip ${EXE_PREFIX}}*.c} MAIN_CXX_FILES=${wildcard ${strip ${EXE_PREFIX}}*.cpp} endif COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard *.c}} COMMON_CXX_FILES=${filter-out ${MAIN_CXX_FILES},${wildcard *.cpp}} # MAIN_OBJECT_FILES=${sort ${patsubst %.c,%.o,${MAIN_C_FILES}} \ ${patsubst %.cpp,%.o,${MAIN_CXX_FILES}}} COMMON_OBJECT_FILES=${sort ${patsubst %.c,%.o,${COMMON_C_FILES}} \ ${patsubst %.cpp,%.o,${COMMON_CXX_FILES}}} OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES} DEPEND_FILES=${patsubst %.o,%.d,${OBJECT_FILES}} EXE_FILES=${sort ${patsubst %.c,%${EXE_SUFFIX},${MAIN_C_FILES}} \ ${patsubst %.cpp,%${EXE_SUFFIX},${MAIN_CXX_FILES}}} # GENERATED_FILES=${DEPEND_FILES} ${OBJECT_FILES} ${LIB_TARGET} ${EXE_FILES} ifneq (,${findstring Darwin,${OS}}) GENERATED_FILES+=${wildcard *.dSYM} endif ifeq (${strip ${wasm}},1) GENERATED_FILES+=${patsubst %.html,%.js,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.html.mem,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wasm,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wast,${EXE_FILES}} endif GENERATED_FILES+=${wildcard output_* *~}
#~~~~ compiler/linker settings ~~~~ CPPFLAGS+=-MMD -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion CPPFLAGS+=-Wno-unused -Wno-unused-parameter CPPFLAGS+=-Werror -Wfatal-errors CFLAGS+=-std=c99 -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla CXXFLAGS+=-std=c++17 -Wno-missing-braces LDFLAGS+= BINFLAGS+= ifeq (${strip ${wasm}},1) CC=emcc CXX=em++ CPPFLAGS+=-Wno-dollar-in-identifier-extension LDFLAGS+=-s ALLOW_MEMORY_GROWTH=1 else ifeq (${strip ${clang}},1) CC=clang CXX=clang++ else CC=gcc CXX=g++ endif # ifneq (,${strip ${MAIN_CXX_FILES} ${COMMON_CXX_FILES}}) # force c++ link if there is at least one c++ source file LD:=${CXX} else LD:=${CC} endif
#~~~~ debug/optimisation settings ~~~~ ifneq (${strip ${opt}},0) CPPFLAGS+=-DNDEBUG BINFLAGS+=-O3 -ffast-math # BINFLAGS+=-fopt-info-vec-optimized ifneq (${strip ${wasm}},1) BINFLAGS+=-march=native endif ifeq (${strip ${opt}},2) # optimise but keep symbols for profiling BINFLAGS+=-g -fno-omit-frame-pointer else BINFLAGS+=-fomit-frame-pointer endif else CPPFLAGS+=-UNDEBUG BINFLAGS+=-g -O0 ifeq (${strip ${wasm}},1) # sanitizer is not available yet with Emscripten else ifneq (,${findstring Windows_NT,${OS}}) # sanitizer is not available yet on Windows else BINFLAGS+=-fsanitize=address,undefined ifneq (,${findstring Raspbian,${OS}}) # dynamic sanitizer libraries may not be found on Raspbian BINFLAGS+=-static-libasan -static-libubsan endif endif endif
#~~~~ main target ~~~~ all : ${EXE_FILES} ${LIB_TARGET}
rebuild : clean all
.SUFFIXES: .SECONDARY: .PHONY: all clean rebuild
#~~~~ linker command to produce the library (if any) ~~~~ ${LIB_TARGET} : ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -shared -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ linker command to produce the executable files (if any) ~~~~ %${EXE_SUFFIX} : %.o ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ compiler command for every source file ~~~~ %.o : %.c @echo ==== compiling [opt=${opt}] $< ==== ${CC} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CFLAGS} @${SKIP_LINE}
%.o : %.cpp @echo ==== compiling [opt=${opt}] $< ==== ${CXX} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CXXFLAGS} @${SKIP_LINE}
-include ${DEPEND_FILES}
#~~~~ remove generated files ~~~~ clean : @echo ==== cleaning ==== ${REMOVE} ${GENERATED_FILES} @${SKIP_LINE}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 7:23.567 18:38.043 44:27.725 7:19.942 35:54.172
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # this GNU-makefile relies on the GCC toolchain # nb: on Windows, the Mingw-w64 package provides the mingw32-make.exe command # ( see https://web.enib.fr/~harrouet/dev_tools/#windows.mingw )
#~~~~ control global settings ~~~~ # make opt=2 --> enable optimisation, then disable debug, but keep symbols # make opt=1 --> enable optimisation, then disable debug # make opt=0 --> disable optimisation, then enable debug opt=0 # make clang=1 --> use clang/clang++, not gcc/g++ # make clang=0 --> use gcc/g++, not clang/clang++ clang=0 # make wasm=1 --> target webassembly rather than the native platform # make wasm=0 --> target the native platform rather than webassembly wasm=0
#~~~~ build library or programs ~~~~ # if LIB_TARGET is provided, this library will be built (with its # platform-specific name), otherwise ${EXE_PREFIX}* programs will be built LIB_TARGET= EXE_PREFIX=prog
#~~~~ detect operating system ~~~~ ifneq (${OS},Windows_NT) ifneq (,${findstring Ubuntu,${shell lsb_release -i 2>/dev/null}}) OS:=Ubuntu else ifneq (,${findstring Raspbian,${shell lsb_release -i 2>/dev/null}}) # Standard distribution for Raspberry-Pi OS:=Raspbian else OS:=${strip ${shell uname -s}} endif ifneq (,${findstring Microsoft,${shell cat /proc/version 2>/dev/null}}) # Windows-Subsystem-for-Linux OS:=${OS}_WSL endif endif
#~~~~ adjust project-specific settings ~~~~ CPPFLAGS= # CPPFLAGS+=-I header/path LDFLAGS=-lm # LDFLAGS+=-L library/path -Wl,-rpath,library/path -l library_name CFLAGS= CXXFLAGS= BINFLAGS= ifneq (,${findstring Windows_NT,${OS}}) # nothing special for now else ifneq (,${strip ${LIB_TARGET}}) BINFLAGS+=-fPIC endif ifneq (,${findstring Darwin,${OS}}) # nothing special for now else ifneq (,${findstring Ubuntu,${OS}}) # sanitizer sometimes requires gold-linker on Ubuntu LDFLAGS+=-fuse-ld=gold else ifneq (,${findstring Raspbian,${OS}}) # some warnings may appear when mixing g++-6 and g++-7 on Raspbian CXXFLAGS+=-Wno-psabi else # nothing special for now endif endif endif
#~~~~ adjust platform-specific features (Posix/Windows/Emscripten...) ~~~~ ifneq (,${findstring Windows_NT,${OS}}) LIB_PREFIX= LIB_SUFFIX=.dll EXE_SUFFIX=.exe SKIP_LINE=echo. REMOVE=del /q else LIB_PREFIX=lib ifneq (,${findstring Darwin,${OS}}) LIB_SUFFIX=.dylib else LIB_SUFFIX=.so endif EXE_SUFFIX= SKIP_LINE=echo REMOVE=rm -rf endif ifeq (${strip ${wasm}},1) LIB_PREFIX:=lib LIB_SUFFIX:=.bc EXE_SUFFIX:=.html endif
#~~~~ deduce file names ~~~~ ifneq (,${strip ${LIB_TARGET}}) LIB_TARGET:=${LIB_PREFIX}${strip ${LIB_TARGET}}${LIB_SUFFIX} MAIN_C_FILES= MAIN_CXX_FILES= else LIB_TARGET:= MAIN_C_FILES=${wildcard ${strip ${EXE_PREFIX}}*.c} MAIN_CXX_FILES=${wildcard ${strip ${EXE_PREFIX}}*.cpp} endif COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard *.c}} COMMON_CXX_FILES=${filter-out ${MAIN_CXX_FILES},${wildcard *.cpp}} # MAIN_OBJECT_FILES=${sort ${patsubst %.c,%.o,${MAIN_C_FILES}} \ ${patsubst %.cpp,%.o,${MAIN_CXX_FILES}}} COMMON_OBJECT_FILES=${sort ${patsubst %.c,%.o,${COMMON_C_FILES}} \ ${patsubst %.cpp,%.o,${COMMON_CXX_FILES}}} OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES} DEPEND_FILES=${patsubst %.o,%.d,${OBJECT_FILES}} EXE_FILES=${sort ${patsubst %.c,%${EXE_SUFFIX},${MAIN_C_FILES}} \ ${patsubst %.cpp,%${EXE_SUFFIX},${MAIN_CXX_FILES}}} # GENERATED_FILES=${DEPEND_FILES} ${OBJECT_FILES} ${LIB_TARGET} ${EXE_FILES} ifneq (,${findstring Darwin,${OS}}) GENERATED_FILES+=${wildcard *.dSYM} endif ifeq (${strip ${wasm}},1) GENERATED_FILES+=${patsubst %.html,%.js,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.html.mem,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wasm,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wast,${EXE_FILES}} endif GENERATED_FILES+=${wildcard output_* *~}
#~~~~ compiler/linker settings ~~~~ CPPFLAGS+=-MMD -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion CPPFLAGS+=-Wno-unused -Wno-unused-parameter CPPFLAGS+=-Werror -Wfatal-errors CFLAGS+=-std=c99 -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla CXXFLAGS+=-std=c++17 -Wno-missing-braces LDFLAGS+= BINFLAGS+= ifeq (${strip ${wasm}},1) CC=emcc CXX=em++ CPPFLAGS+=-Wno-dollar-in-identifier-extension LDFLAGS+=-s ALLOW_MEMORY_GROWTH=1 else ifeq (${strip ${clang}},1) CC=clang CXX=clang++ else CC=gcc CXX=g++ endif # ifneq (,${strip ${MAIN_CXX_FILES} ${COMMON_CXX_FILES}}) # force c++ link if there is at least one c++ source file LD:=${CXX} else LD:=${CC} endif
#~~~~ debug/optimisation settings ~~~~ ifneq (${strip ${opt}},0) CPPFLAGS+=-DNDEBUG BINFLAGS+=-O3 -ffast-math # BINFLAGS+=-fopt-info-vec-optimized ifneq (${strip ${wasm}},1) BINFLAGS+=-march=native endif ifeq (${strip ${opt}},2) # optimise but keep symbols for profiling BINFLAGS+=-g -fno-omit-frame-pointer else BINFLAGS+=-fomit-frame-pointer endif else CPPFLAGS+=-UNDEBUG BINFLAGS+=-g -O0 ifeq (${strip ${wasm}},1) # sanitizer is not available yet with Emscripten else ifneq (,${findstring Windows_NT,${OS}}) # sanitizer is not available yet on Windows else BINFLAGS+=-fsanitize=address,undefined ifneq (,${findstring Raspbian,${OS}}) # dynamic sanitizer libraries may not be found on Raspbian BINFLAGS+=-static-libasan -static-libubsan endif endif endif
#~~~~ main target ~~~~ all : ${EXE_FILES} ${LIB_TARGET}
rebuild : clean all
.SUFFIXES: .SECONDARY: .PHONY: all clean rebuild
#~~~~ linker command to produce the library (if any) ~~~~ ${LIB_TARGET} : ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -shared -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ linker command to produce the executable files (if any) ~~~~ %${EXE_SUFFIX} : %.o ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ compiler command for every source file ~~~~ %.o : %.c @echo ==== compiling [opt=${opt}] $< ==== ${CC} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CFLAGS} @${SKIP_LINE}
%.o : %.cpp @echo ==== compiling [opt=${opt}] $< ==== ${CXX} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CXXFLAGS} @${SKIP_LINE}
-include ${DEPEND_FILES}
#~~~~ remove generated files ~~~~ clean : @echo ==== cleaning ==== ${REMOVE} ${GENERATED_FILES} @${SKIP_LINE}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 (63.7; 18.5) 64.8 × 28.6 (48.2; 75.9) 27.4 × 12.5 (37.1; 52.6) 76.3 × 85.1 (21.4; 86.2) 92.1 × 36.4 (56.9; 31.8) 59.7 × 94.3 (10.5; 20.7) 38.9 × 57.2
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "time_utils.h" #include "rectangle_utils.h"
#include <stdio.h>
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void test_Time(void) { printf("\n~~~~ test_Time() ~~~~\n"); Time t={5, 20.7}; printf("%d:%g ~~> %g seconds\n", t.minute, t.second, Time_total_seconds(t)); const double delta1=55.2; Time_add_seconds(&t, delta1); printf("adding %g seconds ~~> %d:%g\n", delta1, t.minute, t.second); const double delta2=-80.8; Time_add_seconds(&t, delta2); printf("adding %g seconds ~~> %d:%g\n", delta2, t.minute, t.second); }
void test_TimeCollection(void) { printf("\n~~~~ test_TimeCollection() ~~~~\n"); TimeCollection tc=TimeCollection_load("time_collection.txt"); const int earliest_pos=TimeCollection_earliest_pos(&tc); for(int i=0; i<tc.count; ++i) { printf("%d:%g (%g)%s\n", tc.times[i].minute, tc.times[i].second, Time_total_seconds(tc.times[i]), i==earliest_pos ? " <~~ earliest" : ""); } TimeCollection_destroy(&tc); }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void test_Rectangle(void) { printf("\n~~~~ test_Rectangle() ~~~~\n"); Rectangle r={10.0, 20.0, 100.0, 50.0}; printf("(%g;%g)%g×%g ~~> %g area\n", r.x, r.y, r.width, r.height, Rectangle_area(r)); const double x1=5.5, y1=15.5; Rectangle_extend(&r, x1, y1); printf("extending with %g %g ~~> (%g;%g)%g×%g\n", x1, y1, r.x, r.y, r.width, r.height); const double x2=130.5, y2=75.5; Rectangle_extend(&r, x2, y2); printf("extending with %g %g ~~> (%g;%g)%g×%g\n", x2, y2, r.x, r.y, r.width, r.height); }
void test_RectangleGroup(void) { printf("\n~~~~ test_RectangleGroup() ~~~~\n"); RectangleGroup rg=RectangleGroup_load("rectangle_group.txt"); const int largest_pos=RectangleGroup_largest_pos(&rg); for(int i=0; i<rg.count; ++i) { printf("(%g;%g)%g×%g (%g)%s\n", rg.rectangles[i].x, rg.rectangles[i].y, rg.rectangles[i].width, rg.rectangles[i].height, Rectangle_area(rg.rectangles[i]), i==largest_pos ? " <~~ largest" : ""); } RectangleGroup_destroy(&rg); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main(void) { test_Time(); test_TimeCollection();
test_Rectangle(); test_RectangleGroup();
return 0; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifndef TIME_UTILS_H #define TIME_UTILS_H
typedef struct { int minute; double second; } Time;
double Time_total_seconds(Time time);
void Time_add_seconds(Time *time, double seconds);
typedef struct { int count; Time *times; } TimeCollection;
TimeCollection TimeCollection_load(const char *filename);
void TimeCollection_destroy(TimeCollection *tc);
int TimeCollection_earliest_pos(const TimeCollection *tc);
#endif // TIME_UTILS_H
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "time_utils.h"
#include <stdio.h> #include <stdlib.h>
double Time_total_seconds(Time time) { return 60*time.minute+time.second; }
void Time_add_seconds(Time *time, double seconds) { time->second+=seconds; while(time->second>=60.0) { time->second-=60.0; time->minute+=1; } while(time->second<0.0) { time->second+=60.0; time->minute-=1; } }
TimeCollection TimeCollection_load(const char *filename) { TimeCollection tc={0, NULL}; FILE *input=fopen(filename, "r"); if(input!=NULL) { if((fscanf(input," %d ", &tc.count)==1)&& (tc.count>0)) { tc.times=(Time *)malloc(tc.count*sizeof(Time)); if(tc.times==NULL) { abort(); } for(int i=0; i<tc.count; ++i) { if(fscanf(input, " %d : %lg ", &tc.times[i].minute, &tc.times[i].second)!=2) { TimeCollection_destroy(&tc); break; } } } fclose(input); } return tc; }
void TimeCollection_destroy(TimeCollection *tc) { free(tc->times); tc->times=NULL; tc->count=0; }
int TimeCollection_earliest_pos(const TimeCollection *tc) { int earliest_pos=-1; double earliest_seconds=0.0; for(int i=0; i<tc->count; ++i) { const double seconds=Time_total_seconds(tc->times[i]); if(earliest_pos<0 || seconds<earliest_seconds) { earliest_pos=i; earliest_seconds=seconds; } } return earliest_pos; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifndef RECTANGLE_UTILS_H #define RECTANGLE_UTILS_H
typedef struct { double x, y; double width, height; } Rectangle;
double Rectangle_area(Rectangle rect);
void Rectangle_extend(Rectangle *rect, double x, double y);
typedef struct { int count; Rectangle *rectangles; } RectangleGroup;
RectangleGroup RectangleGroup_load(const char *filename);
void RectangleGroup_destroy(RectangleGroup *rg);
int RectangleGroup_largest_pos(const RectangleGroup *rg);
#endif // RECTANGLE_UTILS_H
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "rectangle_utils.h"
#include <stdio.h> #include <stdlib.h>
double Rectangle_area(Rectangle rect) { return rect.width*rect.height; }
void Rectangle_extend(Rectangle *rect, double x, double y) { if(x<rect->x) { rect->width+=rect->x-x; rect->x=x; } else if(x>rect->x+rect->width) { rect->width=x-rect->x; } if(y<rect->y) { rect->height+=rect->y-y; rect->y=y; } else if(y>rect->y+rect->height) { rect->height=y-rect->y; } }
RectangleGroup RectangleGroup_load(const char *filename) { RectangleGroup rg={0, NULL}; FILE *input=fopen(filename, "r"); if(input!=NULL) { if((fscanf(input," %d ", &rg.count)==1)&& (rg.count>0)) { rg.rectangles=(Rectangle *)malloc(rg.count*sizeof(Rectangle)); if(rg.rectangles==NULL) { abort(); } for(int i=0; i<rg.count; ++i) { if(fscanf(input, " ( %lg ; %lg ) %lg × %lg ", &rg.rectangles[i].x, &rg.rectangles[i].y, &rg.rectangles[i].width, &rg.rectangles[i].height)!=4) { RectangleGroup_destroy(&rg); break; } } } fclose(input); } return rg; }
void RectangleGroup_destroy(RectangleGroup *rg) { free(rg->rectangles); rg->rectangles=NULL; rg->count=0; }
int RectangleGroup_largest_pos(const RectangleGroup *rg) { int largest_pos=-1; double largest_area=0.0; for(int i=0; i<rg->count; ++i) { const double area=Rectangle_area(rg->rectangles[i]); if(largest_pos<0 || area>largest_area) { largest_pos=i; largest_area=area; } } return largest_pos; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~