@HarmOUR Thanks. My goal is also to have easy and fast interaction with a GUI, but I prefer doing the "engine" first pretending to have any UI I want. And I don't think I'll get to the interactive part of the program during the jam. Also thanks for sharing your notes.
Day 2
I started by fixing the issue seen in the output from yesterday. It was an issue with removing nodes from the tree. After fixing the issue, I started to make the node removal function more robust
with things like handling what happens when you remove the root of the tree or the last node on a side of the =
. And quickly found that it wasn't the remove node function that needed to handle that.
So I tried to fix the calling code and realize that I was trying to automate the process of "adding similar elements" of the equation, which might be usefull, but the first goal of the program is to let the user choose what should happen. For example instead of having "Try to add all the x
in this equation", I want the user to select two x
and tell the application "Add those x
".
I could do a simple version of that, but it didn't seem to help me much going toward my goal, so I tried to think a bit about "things you can add in an equation".
I chose to only allow multiply and add at the moment. After a bit I decided to try to name things with names I found on the internet. It seems obvious but to this point I used terms without certainty about what they meant. If those aren't correct, please let me know, as it would really help.
A variable
is something we don't know or are searching (this definition isn't clear yet). e.g. x = a + 5 (x is a variable).
A constant
is a things on its own (letter or number). e.g. y = x + 4 (4 is a constant) or y = x + a (a is a constant).
A term
is a group of things (1 or more) without addition or subtraction. e.g. y = 2x (2x is a term) or y = ax (ax is a term).
A coefficient
is something that multiplies a variable. e.g. y = ax (a is a coefficient) or y = 2x (2 is a coefficient).
An expression
is an addition/subtraction of terms.
With those definition it became clear that I needed to be able to detect terms
and work with them. For example y - b = ax + b - b
, b
on the right side are terms and I need to find their coefficient after adding them. It made it clear to me how to add more "complex" term like abc
or 2cd4
.
A thing I keep in mind is that at the moment I consider 4ac
a term but not (2+2)*ac
. I don't have parenthesis in the program at the moment, so I'll handle that later.
So today was about "adding term together", which is close to completion (I need to finish adding the result of the add back in the tree). Here is some code.
/* TODO simon: handle parenthesis. */
b32 math_is_term( node_t* node ) {
b32 result = ( node->type == node_type_identifier || node->type == node_type_mul || node->type == node_type_div || node->type == node_type_constant );
if ( result && node->left ) {
result = math_is_term( node->left );
}
if ( result && node->right ) {
result = math_is_term( node->right );
}
return result;
}
/* TODO simon: Handle division, paranthesis. */
/* NOTE simon: The returned node is a new tree for the term without coefficient and needs to be added to the main tree. */
node_t* math_separate_term_and_coefficient( node_t* term, s64* coefficient ) {
node_t* result = 0;
if ( term->type == node_type_constant ) {
( *coefficient ) *= term->constant;
} else if ( term->type == node_type_identifier ) {
result = math_identifier( term->identifier );
} else if ( term->type == node_type_mul || term->type == node_type_div ) {
node_t* left = math_separate_term_and_coefficient( term->left, coefficient );
node_t* right = math_separate_term_and_coefficient( term->right, coefficient );
if ( left && right ) {
result = math_mul( );
node_set_left( result, left );
node_set_right( result, right );
} else if ( left ) {
result = left;
} else if ( right ) {
result = right;
}
}
return result;
}
/* TODO simon: This function consider 2 * 2 * x != 4 * x. Also a * b != b * a.
The first issue can be solved by using math_separate_term_and_coefficient.
I don't know for the second issue at the moment.
*/
b32 math_are_terms_equal( node_t* term_1, node_t* term_2 ) {
b32 result = ( term_1->type == term_2->type );
b32 term_1_left = ( term_1->left != 0 );
b32 term_1_right = ( term_1->right != 0 );
b32 term_2_left = ( term_2->left != 0 );
b32 term_2_right = ( term_2->right != 0 );
result = result && ( term_1_left == term_2_left ) && ( term_1_right == term_2_right );
if ( result ) {
switch ( term_1->type ) {
case node_type_identifier: {
result = ( term_1->identifier == term_2->identifier );
} break;
/* TODO simon: No add and sub at the moment (needs parenthesis for that). */
case node_type_mul:
case node_type_div: {
result = math_are_terms_equal( term_1->left, term_2->left );
result = result && math_are_terms_equal( term_1->right, term_2->right );
} break;
case node_type_constant: {
result = ( term_1->constant == term_2->constant );
} break;
}
}
return result;
}
void math_add_terms( node_t* term_1, node_t* term_2 ) {
_assert( term_1 && term_2 );
b32 term_1_is_valid = math_is_term( term_1 );
b32 term_2_is_valid = math_is_term( term_2 );
if ( term_1_is_valid && term_2_is_valid ) {
s64 term_1_coefficient = 1;
s64 term_2_coefficient = 1;
node_t* term_1_no_coefficient = math_separate_term_and_coefficient( term_1, &term_1_coefficient );
node_t* term_2_no_coefficient = math_separate_term_and_coefficient( term_2, &term_2_coefficient );
b32 equal = math_are_terms_equal( term_1_no_coefficient, term_2_no_coefficient );
if ( equal ) {
path_t path = { 0 };
b32 path_exists = math_path_between( term_1, 0, term_2, &path );
if ( path.first_path_node_is_on_the_left_of_last_node ) {
swap_type( term_1, term_2, node_t* );
swap_type( term_1_coefficient, term_2_coefficient, s64 );
}
_assert( term_2->parent );
node_t* parent = term_2->parent;
_assert( parent->parent );
node_t* operator_node = parent->parent;
_assert( operator_node->type == node_type_add || operator_node->type == node_type_sub );
s64 coefficient = term_1_coefficient;
if ( operator_node->type == node_type_add ) {
coefficient += term_2_coefficient;
} else {
coefficient -= term_2_coefficient;
}
math_remove_node( term_1 );
math_remove_node( term_2 );
if ( coefficient != 0 ) {
node_t* mul = math_mul( );
node_t* coefficient_node = math_constant( );
coefficient_node->constant = coefficient;
node_set_left( mul, coefficient_node );
node_set_right( mul, term_1_no_coefficient );
node_t* add = math_add( );
node_set_right( add, mul );
/* TODO simon: Add in the equation tree. */
}
}
}
}