double CParseTreeNode::EvaluateTernaryExpression(bool log) { // This function covers both OH-style ternary expressions // and OpenPPL-style (open-ended) when-conditions. // In case of (OE)WCs the parse-tree-generation assures // that _third_sibbling points to the next (OE)WC. // Again we use short circuiting. assert(_first_sibbling != NULL); // Both second and thirs sibbling can be zero in case of an OEWC. // So no assertion here. // We handle this case gracefully in EvaluateSibbling(). assert(_terminal_name == ""); assert((_node_type == kTokenOperatorConditionalIf) || (_node_type == kTokenOperatorConditionalWhen)); double value_of_first_sibbling = EvaluateSibbling(_first_sibbling, log); if (value_of_first_sibbling) { double value_of_second_sibbling = EvaluateSibbling(_second_sibbling, log); // Special behaviour for user-variables: // we have to set them, but then continue with the next when-condition // (third sibbling) if (!SecondSibblingIsUserVariableToBeSet()) { // Normal behaviour: return the evaluated result return value_of_second_sibbling; } // Uvervariables: will fall through to the evaluation // of the third sibbling... } double value_of_third_sibbling = EvaluateSibbling(_third_sibbling, log); return value_of_third_sibbling; }
double CParseTreeOperatorNode::Evaluate(bool log /* = false */) { write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] Evaluating node type %i %s\n", _node_type, TokenString(_node_type)); p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); // Actions first, which are "unary". // We have to encode all possible outcomes in a single floating-point, // therefore: // * positive values mean: raise size (by big-blinds, raise-to-semantics) // * negative values mean: elementary actions if (_node_type == kTokenActionRaiseToBigBlinds) { // RaiseTo N Force return EvaluateSibbling(_first_sibbling, log); } else if (_node_type == kTokenActionRaiseByBigBlinds) { // RaiseBy N Force double raise_by_amount_in_bblinds = EvaluateSibbling(_first_sibbling, log); double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] raiseby = %.2f ncallbets = %.2f final = %.2f\n", raise_by_amount_in_bblinds, p_symbol_engine_chip_amounts->ncallbets(), final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionRaiseByPercentagedPotsize) { // RaiseBy X% Force double raise_by_percentage = EvaluateSibbling(_first_sibbling, log); assert(p_symbol_engine_tablelimits->bet() > 0); double pot_size_after_call_in_big_blinds = (p_symbol_engine_chip_amounts->pot() / p_symbol_engine_tablelimits->bet()) + p_symbol_engine_chip_amounts->nbetstocall(); assert(pot_size_after_call_in_big_blinds >= 0); double raise_by_amount_in_bblinds = 0.01 * raise_by_percentage * pot_size_after_call_in_big_blinds; double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] raiseby percentage = %.2f pot after call = %.2f raiseby = %.2f final = %.2f\n", raise_by_percentage, pot_size_after_call_in_big_blinds, raise_by_amount_in_bblinds, final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (TokenIsElementaryAction(_node_type)) { return (0 - _node_type); } // Finally operators else if (TokenIsUnary(_node_type)) { return EvaluateUnaryExpression(log); } else if (TokenIsBinary(_node_type)) { return EvaluateBinaryExpression(log); } else if (TokenIsTernary(_node_type)) { return EvaluateTernaryExpression(log); } assert(false); return kUndefined; }
double CParseTreeOperatorNode::EvaluateUnaryExpression(bool log_symbol) { // Paramater named "log_symbol" instead of "log" // due to naming conflict with mathematical function assert(_first_sibbling != NULL); assert(_second_sibbling == NULL); assert(_third_sibbling == NULL); double value_of_first_sibbling = EvaluateSibbling(_first_sibbling, log_symbol); switch (_node_type) { case kTokenOperatorUnaryMinus: return (0 - value_of_first_sibbling); case kTokenOperatorLog: return log(value_of_first_sibbling); case kTokenOperatorLogicalNot: return !value_of_first_sibbling; case kTokenOperatorBinaryNot: return ~ ((unsigned long)value_of_first_sibbling); case kTokenOperatorBitCount: return bitcount((unsigned long)value_of_first_sibbling); case kTokenBracketOpen_1: case kTokenBracketOpen_2: case kTokenBracketOpen_3: return value_of_first_sibbling; default: assert(false); return kUndefined; } }
double CParseTreeNode::EvaluateBinaryExpression(bool log) { assert(_first_sibbling != NULL); assert(_second_sibbling != NULL); assert(_third_sibbling == NULL); assert(_terminal_name == ""); double value_of_first_sibbling = EvaluateSibbling(_first_sibbling, log); double value_of_second_sibbling = 0.0; // Short circuiting // Don't evaluate unnecessary parts of expressions if (_node_type == kTokenOperatorLogicalAnd) { if (value_of_first_sibbling == false) { return false; } value_of_second_sibbling = EvaluateSibbling(_second_sibbling, log); return (value_of_second_sibbling ? true : false); } else if (_node_type == kTokenOperatorLogicalOr) { // Attention! // We can not look here for "value_of_first_sibbling == true" // because this way we would only accept true (==1) // but we want to accept any non-zero value. // http://www.maxinmontreal.com/forums/viewtopic.php?f=111&t=17899 if (value_of_first_sibbling) { return true; } value_of_second_sibbling = EvaluateSibbling(_second_sibbling, log); return (value_of_second_sibbling ? true : false); } // Short circuiting done // Now normal evaluation of operators that need both operands value_of_second_sibbling = EvaluateSibbling(_second_sibbling, log); switch (_node_type) { case kTokenOperatorPlus: return value_of_first_sibbling + value_of_second_sibbling; case kTokenOperatorMinus: return value_of_first_sibbling - value_of_second_sibbling; case kTokenOperatorMultiplication: return value_of_first_sibbling * value_of_second_sibbling; case kTokenOperatorDivision: if (value_of_second_sibbling == 0) { OH_MessageBox_Error_Warning("Division by zero."); return kUndefined; } else { return value_of_first_sibbling / value_of_second_sibbling; } case kTokenOperatorModulo: if (value_of_second_sibbling == 0) { OH_MessageBox_Error_Warning("Division by zero."); return kUndefined; } else { return (unsigned long)value_of_first_sibbling % (unsigned long)value_of_second_sibbling; } case kTokenOperatorExponentiation: return pow(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorEquality: return IsEqual(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorApproximatellyEqual: return IsApproximatellyEqual(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorSmaller: return IsSmaller(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorSmallerOrEqual: return IsSmallerOrEqual(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorGreater: return IsGreater(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorGreaterOrEqual: return IsGreaterOrEqual(value_of_first_sibbling, value_of_second_sibbling); case kTokenOperatorNotEqual: case kTokenOperatorLogicalXOr: return value_of_first_sibbling != value_of_second_sibbling; case kTokenOperatorBinaryAnd: return (unsigned long)value_of_first_sibbling & (unsigned long)value_of_second_sibbling; case kTokenOperatorBinaryOr: return (unsigned long)value_of_first_sibbling | (unsigned long)value_of_second_sibbling; case kTokenOperatorBinaryXOr: return (unsigned long)value_of_first_sibbling ^ (unsigned long)value_of_second_sibbling; case kTokenOperatorBitShiftLeft: return (unsigned long)value_of_first_sibbling << (unsigned long)value_of_second_sibbling; case kTokenOperatorBitShiftRight: return (unsigned long)value_of_first_sibbling >> (unsigned long)value_of_second_sibbling; case kTokenOperatorPercentage: return value_of_first_sibbling * value_of_second_sibbling * 0.01; default: assert(false); } return kUndefined; }
double CParseTreeNode::Evaluate(bool log /* = false */){ write_log(preferences.debug_formula(), "[CParseTreeNode] Evaluating node type %i %s\n", _node_type, TokenString(_node_type)); p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); // Most common types first: numbers and identifiers if (_node_type == kTokenNumber) { write_log(preferences.debug_formula(), "[CParseTreeNode] Number evaluates to %6.3f\n", _constant_value); return _constant_value; } else if (_node_type == kTokenIdentifier) { assert(_first_sibbling == NULL); assert(_second_sibbling == NULL); assert(_third_sibbling == NULL); assert(_terminal_name != ""); double value = EvaluateIdentifier(_terminal_name, log); write_log(preferences.debug_formula(), "[CParseTreeNode] Identifier evaluates to %6.3f\n", value); // In case of f$-functions the line changed inbetween, // so we have to set it to the current location (again) // for the next log. p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); return value; } // Actions second, which are also "unary". // We have to encode all possible outcomes in a single floating-point, // therefore: // * positive values mean: raise size (by big-blinds, raise-to-semantics) // * negative values mean: elementary actions else if (_node_type == kTokenActionRaiseToBigBlinds) { // RaiseTo N Force return EvaluateSibbling(_first_sibbling, log); } else if (_node_type == kTokenActionRaiseByBigBlinds) { // RaiseBy N Force double raise_by_amount_in_bblinds = EvaluateSibbling(_first_sibbling, log); double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeNode] raiseby = %.2f ncallbets = %.2f final = %.2f\n", raise_by_amount_in_bblinds, p_symbol_engine_chip_amounts->ncallbets(), final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionRaiseByPercentagedPotsize) { // RaiseBy X% Force double raise_by_percentage = EvaluateSibbling(_first_sibbling, log); assert(p_symbol_engine_tablelimits->bet() > 0); double pot_size_after_call_in_big_blinds = (p_symbol_engine_chip_amounts->pot() / p_symbol_engine_tablelimits->bet()) + p_symbol_engine_chip_amounts->nbetstocall(); assert(pot_size_after_call_in_big_blinds >= 0); double raise_by_amount_in_bblinds = 0.01 * raise_by_percentage * pot_size_after_call_in_big_blinds; double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeNode] raiseby percentage = %.2f pot after call = %.2f raiseby = %.2f final = %.2f\n", raise_by_percentage, pot_size_after_call_in_big_blinds, raise_by_amount_in_bblinds, final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionUserVariableToBeSet) { // User-variables are a special case of elementary actions // Therefore need to be handled first. SetUserVariable(_terminal_name); return kUndefinedZero; } else if (TokenIsElementaryAction(_node_type)) { return (0 - _node_type); } // Finally operators else if (TokenIsUnary(_node_type)) { return EvaluateUnaryExpression(log); } else if (TokenIsBinary(_node_type)) { return EvaluateBinaryExpression(log); } else if (TokenIsTernary(_node_type)) { return EvaluateTernaryExpression(log); } assert(false); return kUndefined; }