theme | class | size | paginate | marp | ||
---|---|---|---|---|---|---|
default |
|
14580 |
true |
true |
Lec 4
- Recursive programs
- factorial | fibonacci | n choose k | permutations
- Caching (Memoization/Dynamic Programing)
- Typedef
- Representation/Memory management for Perm
- Creation/Destruction
- GDB
- breakpoints | watch expressions | call stack | step over/in/out
- Recursive Drawing
- recursive circles
- Input: an array of integers
- Ouptut: array sorted in increasing order
- Base Case: If array of size 1 then return.
- Otherwise
- Divide the array into two halfs
- Copy the halfs into arrays L, R
- Recursively sort L and R seperately
- Merge L, R such that the result is sorted
- Input: two arrays L, R that are sorted (seperately)
- Output: an array with size = size(L) + size(R) containing their elements and is sorted
- Example: Merge({1,3,5}, {2,4,6}) should return {1,2,3,4,5,6}
t = size(L) + size(R)
A = array of size t
c = 0, l = 0, r = 0;
while(c < t):
if l reached size(L):
copy remaining elements from R to A
if r reached size(R):
copy remaining elements from L to A
if L[l] < R[r]:
A[c++] = L[l++]
else:
A[c++] = R[r++]
void merge(int *L, int sL, int* R,
int sR, int *A) {
int l = 0, r = 0, c = 0;
while(c <= sL + sR -1) {
if (r == sR - 1 ) {
A[c++] = L[l++];
continue;
}
if (l == sL - 1) {
A[c++] = R[r++];
continue;
}
if (L[l] < R[r]) {
A[c++] = L[l++];
} else if (L[l] >= R[r]) {
A[c++] = R[r++];
}
}
}
void copy_array(int *A, int start,
int end, int *B) {
for(int i = start; i <= end; i++) {
B[i-start] = A[i];
}
}
void sort(int *A, int len) {
if (len == 1) {
return;
} else {
int mid = len/2;
int L [ mid], R [len - mid];
copy_array(A, 0, mid, L);
copy_array(A, mid, len, R);
sort(L, mid);
sort(R,len - mid);
merge(L, mid, R, len-mid, A);
}
}
Debug and fix!
For sorting an array A from start
to end
- Base case:
start == end
then nothing to be done. - Find the index
i
of the smallest element in A fromstart
toend
- swap the values of
A[start]
andA[i]
- Sort
A
fromstart + 1
toend
- C passes arguments by value.
- Every time an array is passed, entire element is copied.
- Also modifications done to the Array will not be saved.
- Passing pointers, only results in copying of the pointer(ie address of the first element of the array).
- Also modifications will remain, as we are changing the actual memory location.
#include <allegro5/allegro5.h>
#include <allegro5/allegro_primitives.h>
ALLEGRO_EVENT_QUEUE* queue = NULL;
ALLEGRO_DISPLAY* disp = NULL;
// Checks a condition `test`.
// If false, prints out a `description` and exits
void must_init(bool test, const char *description)
// Initialization logic of allegro library
// creates queue or disp
void allegro_init()
// frees all the memory allocated by allegro
void allegro_close()
int main() {
allegro_init();
ALLEGRO_EVENT event;
draw();
// wait for some event to enter the queue.
// In this case, it is only the event
// for closing the window
al_wait_for_event(queue, &event);
allegro_close();
return 0;
}
- We want to write many program that use Allegro (1_learn_draw.c, 2_rec_drawing.c).
- Then the functions defined in slide 3 has to be repeated in both the files.
Seperate the common code into allegro.h
and allegro.c
Write a allegro.h
that
- includes the allegro, stdio, math header files
- declares variables
disp
,queue
(as extern; but do not initialize). - declares the functions (also called prototypes)
#include <allegro5/allegro5.h>
#include <allegro5/allegro_primitives.h>
#include <math.h>
#include <stdio.h>
// These are initialized in allegro.c
extern ALLEGRO_EVENT_QUEUE* queue;
extern ALLEGRO_DISPLAY* disp;
// Functions bellow are defined in allegro.c
void must_init(bool test, const char *description);
void allegro_init();
void allegro_close();
#include "allegro.h"
ALLEGRO_EVENT_QUEUE* queue = NULL;
ALLEGRO_DISPLAY* disp = NULL;
void must_init(bool test, const char *description) {
...
}
void allegro_init() {
...
}
void allegro_close() {
...
}
- Include
allegro.h
in both1_learn_draw.c
and2_rec_drawing.c
.
#include "allegro.h"
void draw() {
...
}
int main() {
...
}
gcc 1_learn_draw.c allegro.c -o 1.out \\
-lm -lallegro_primitives -lallegro
gcc 2_rec_drawing.c allegro.c -o 2.out \\
-lm -lallegro_primitives -lallegro
3_tree_drawing.c
#include "allegro.h"
// draws a line starting at (x, y), at an angle, with length len
// recursion goes to 11 level
// at the last two levels, line is drawn in green.
void drawTree(int x, int y, float angle, float len, int level) {
// the other end point of the line, is obtained
// by moving len distance at an angle
int x2 = x + len*cos(2*3.14*angle/360.0);
int y2 = y - len*sin(2*3.14*angle/360.0);
// if level < 10 give brown color otherwise green
ALLEGRO_COLOR c = al_map_rgb_f(1,1,1) ;
// set line width to 5 if level <= 2
al_draw_line(x,y,x2 , y2, c, 1);
if (level <= 10) {
drawTree(x2,y2, angle - 20, len, level+1);
drawTree(x2,y2, angle + 20, len, level +1);
}
}
struct Point {
int x;
int y;
}
int main() {
Point p = {.x = 320, .y = 100};
printf("X coordinate of p is %d", p.x);
printf("Y coordinate of p is %d", p.y);
}
struct Point {
int x;
int y;
};
void drawTree(struct Point p, float angle, float len, int level) {
struct Point p2 = {
.x = p.x + len*cos(2*3.14*angle/360.0),
.y = p.y - len*sin(2*3.14*angle/360.0)
};
...
if (level <= 10) {
drawTree(p2, angle - 20, len, level+1);
drawTree(p2, angle + 20, len, level +1);
}
}
typedef struct Point {
int x;
int y;
} Point;
void drawTree(Point p, float angle, float len, int level) {
Point p2 = {
.x = p.x + len*cos(2*3.14*angle/360.0),
.y = p.y - len*sin(2*3.14*angle/360.0)
};
...
if (level <= 10) {
drawTree(p2, angle - 20, len, level+1);
drawTree(p2, angle + 20, len, level +1);
}
}
typedef struct Point {
int x;
int y;
} Point;
void drawTree(Point p, float angle, float len, int level) {
...
if (level <= 10) {
drawTree((Point){
.x = p.x + len*cos(2*3.14*angle/360.0),
.y = p.y - len*sin(2*3.14*angle/360.0)
}, angle - 20, len, level+1);
drawTree((Point){
.x = p.x + len*cos(2*3.14*angle/360.0),
.y = p.y - len*sin(2*3.14*angle/360.0)
}, angle + 20, len, level +1);
}
}
typedef struct Circle {
Point center;
int radius;
} Circle;
void drawCircle(Circle c) {
al_draw_circle(c.center.x, c.center.y, c.radius);
if(c.radius > 32) {
Circle
c1 = {.center = {c.center.x + c.radius/2, c.center.y},
.radius = c.radius/2},
c2 = {.center = {c.center.x - c.radius/2, c.center.y},
.radius = c.radius/2},
c3 ={.center = {c.center.x, c.center.y + c.radius/2},
.radius = c.radius/2},
c4 ={.center = {c.center.x, c.center.y - c.radius/2},
.radius = c.radius/2};
drawCircle(c1);
drawCircle(c2);
drawCircle(c3);
drawCircle(c4);
}
}
typedef struct Circle {
Point center;
int radius;
} Circle;
void drawCircle(Circle c) {
al_draw_circle(c.center.x, c.center.y, c.radius);
if(c.radius > 32) {
Circle
c1 = {.center = {c.center.x + c.radius/2, c.center.y}, .radius = c.radius/2},
c2 = {.center = {c.center.x - c.radius/2, c.center.y}, .radius = c.radius/2},
c3 ={.center = {c.center.x, c.center.y + c.radius/2}, .radius = c.radius/2},
c4 ={.center = {c.center.x, c.center.y - c.radius/2}, .radius = c.radius/2};
drawCircle((Circle){.center = (Point){c.center.x + c.radius/2, c.center.y}, .radius = c.radius/2});
drawCircle(c2);
drawCircle(c3);
drawCircle(c4);
}
}
typedef struct Circle {
Point center;
int radius;
} Circle;
void drawCircle(Circle c) {
al_draw_circle(c.center.x, c.center.y, c.radius,);
if(c.radius > 32) {
circle circles[4] = {
{.center = {c.center.x + c.radius/2, c.center.y}, .radius = c.radius/2},
{.center = {c.center.x - c.radius/2, c.center.y}, .radius = c.radius/2},
{.center = {c.center.x, c.center.y + c.radius/2}, .radius = c.radius/2},
{.center = {c.center.x, c.center.y - c.radius/2}, .radius = c.radius/2}
};
for(int i = 0; i < 4; i++) {
drawCircle(circles[i]);
}
}
}
typedef struct Circle {
Point center;
int radius;
} Circle;
void drawCircle(Circle c*) {
al_draw_circle(c->center.x, c->center.y, c->radius,);
if(c->radius > 32) {
circle circles[4] = {
{.center = {c->center.x + c->radius/2, c->center.y}, .radius = c->radius/2},
{.center = {c->center.x - c->radius/2, c->center.y}, .radius = c->radius/2},
{.center = {c->center.x, c->center.y + c->radius/2}, .radius = c->radius/2},
{.center = {c->center.x, c->center.y - c->radius/2}, .radius = c->radius/2}
};
for(int i = 0; i < 4; i++) {
drawCircle(&(circles[i]));
}
}
}
gcc 1_learn_draw.c allegro.c -o 1.out \
-lm -lallegro_primitives -lallegro
- Even if small number of files are changed, will compile everything!
Recompile only files that are needed.
Make files specify dependencies between files and recompiles only what is needed.
LDLIBS = -lm -lallegro_primitives -lallegro
1.out : 1_learn_draw.o allegro.o
cc -o 1.out 1_learn_draw.o allegro.o $(LDLIBS)
2.out : 2_rec_drawing.o allegro.o
cc -o 2.out 2_rec_drawing.o allegro.o $(LDLIBS)
1_learn_draw.o : 1_learn_draw.c allegro.h
cc -o 1_learn_draw.o 1_learn_draw.c $(LDLIBS)
2_rec_drawing.o : 2_rec_drawing.c allegro.h
cc -o 2_rec_drawing.o 2_rec_drawing.c $(LDLIBS)
allegro.o : allegro.c allegro.h
cc -o allegro.o allegro.c $(LDLIBS)
clean:
rm -f *.out *.o
LDLIBS = -lm -lallegro_primitives -lallegro
1.out : 1_learn_draw.o allegro.o
cc -o 1.out 1_learn_draw.o allegro.o $(LDLIBS)
2.out : 2_rec_drawing.o allegro.o
cc -o 2.out 2_rec_drawing.o allegro.o $(LDLIBS)
prog_objs = 1_learn_draw.o 2_rec_drawing.o allegro.o
$(prog_objs) : allegro.h
clean:
rm -f *.out *.o