C++ nested If statement, it doesn't work as expected - c++

StackOverflow fellow developers,
I am doing some Arduino coding to working with measuring Fine Dust Monitoring Device,
However, I have a question regarding with If-statement.
In the code below, I added nested-if statement in the while loop, and some reason,
else if (9999 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 52) {
pm25i = 7;
}
else if (9999 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 102) {
pm10i = 7;
}
else if (pm10i == 7) {
status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
}
}
Those lines doesn't work as expected, as when pm10 or pm25 value reaches more than 100 ug / m^3, it doesn't sync with the ThingSpeak server anymore, but I don't know why it doesn't uploads any data. Interestingly rest of my source code parts work fine as expected.
However When I removed those nested-if statements it works fine. (It successfully uploads even pm10 or pm25 value reaches more than 100 ug / m^3.
Could somebody explain what's wrong with my code? and how should I fix this issue please?
Thanks.
void loop() {
if (ss.available() <= 0) {
Serial.println("SIGNAL STATUS : WEAK");
s_map_x = String(map_x, 6);
s_map_y = String(map_y, 6);
}
else {
while (ss.available() > 0) {
Serial.println("SIGNAL STATUS : GREAT");
if (gps.encode(ss.read())) {
Serial.println("GPS READ");
Serial.println(ss.read());
if (gps.location.isValid()) {
Serial.println("LOCATION : GREAT");
map_x = gps.location.lat();
map_y = gps.location.lng();
Serial.println(String(map_x, 6));
Serial.println(String(map_y, 6));
Serial.println(gps.satellites.value());
}
}
s_map_x = String(map_x, 6);
s_map_y = String(map_y, 6);
yield();
}
}
while (dust.available() > 0) {
do_dust(dust.read(), got_dust);
yield();
/* AQI (실시간 대기질 지수) 등급 분류를 위한 코드입니다.
실시간 대기질 기준 수치는 국제 표준인 WHO 대기질 수치 기준으로 분류합니다.
http://www.euro.who.int/__data/assets/pdf_file/0005/78638/E90038.pdf
https://airnow.gov/index.cfm?action=aqibasics.aqi */
// 초미세먼지 AQI (실시간 대기질 지수) 등급을 분류합니다.
// 0 이상 8 이하 : 1
// 9 이상 16 이하 : 2
// 17 이상 26 이하 : 3
// 27 이상 34 이하 : 4
// 35 이상 43 이하 : 5
// 44 이상 51 이하 : 6
// 52 이상 ∞ 이하 : 7
if (8 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 0) {
pm25i = 1;
}
else if (16 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 9) {
pm25i = 2;
}
else if (26 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 17) {
pm25i = 3;
}
else if (34 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 27) {
pm25i = 4;
}
else if (43 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 35) {
pm25i = 5;
}
else if (51 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 44) {
pm25i = 6;
}
else if (9999 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 52) {
pm25i = 7;
}
// 미세먼지 AQI (실시간 대기질 지수) 등급을 분류합니다.
// 0 이상 8 이하 : 1
// 9 이상 16 이하 : 2
// 17 이상 51 이하 : 3
// 52 이상 68 이하 : 4
// 69 이상 84 이하 : 5
// 85 이상 101 이하 : 6
// 102 이상 ∞ 이하 : 7
if (8 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 0) {
pm10i = 1;
}
else if (16 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 9) {
pm10i = 2;
}
else if (51 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 17) {
pm10i = 3;
}
else if (68 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 52) {
pm10i = 4;
}
else if (84 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 69) {
pm10i = 5;
}
else if (101 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 85) {
pm10i = 6;
}
else if (9999 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 102) {
pm10i = 7;
}
/* ThingSpeak 채널 내 Status Update (상태 업데이트) 영역에 표시되는 문구이므로,
종합적인 정보 표현을 위해 초미세먼지와 미세먼지 등급을 비교 한 후
두 가지 중 높은 등급 기준으로 경고 혹은 권고메시지를 표시합니다. */
// 분류된 초미세먼지 등급이 미세먼지 등급보다 같거나 높은 경우, 초미세먼지 등급을 기준으로 내용을 표시하기 위하여 아래의 문자열을 status 변수에 저장합니다.
if (pm25i >= pm10i) {
if (pm25i == 1) {
status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
}
else if (pm25i == 2) {
status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities.";
}
else if (pm25i == 3) {
status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
}
else if (pm25i == 4) {
status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
}
else if (pm25i == 5) {
status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
}
else if (pm25i == 6) {
status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
}
else if (pm25i == 7) {
status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
}
// 분류된 미세먼지 등급이 초미세먼지 등급보다 높은 경우, 미세먼지 등급을 기준으로 내용을 표시하기 위하여 아래의 문자열을 status 변수에 저장합니다.
} else if (pm25i < pm10i) {
if (pm10i == 1) {
status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
}
else if (pm10i == 2) {
status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities";
}
else if (pm10i == 3) {
status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
}
else if (pm10i == 4) {
status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
}
else if (pm10i == 5) {
status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
}
else if (pm10i == 6) {
status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
}
else if (pm10i == 7) {
status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
}
}
}
//Serial.println(map_x);
//Serial.print("pm 25 : ");
//Serial.println(int(pm25s.getMedian()));
if (millis() > mark) {//one minute(60000) interval
mark = millis() + 60000;
got_interval = true;
}
if (got_interval) {
got_interval = false;
do_interval();
}
yield();
}

You may be getting unexpected behavior due to floating point comparisons or may be due to some unhandled cases, or may be because RunningMedian::getMedian() is changing on any/every condition check. Another possible reason is maybe RunningMedia::_cnt is not more than 0.
Also I would recommend updating your library to its latest version (v0.1.15).
Try putting this code inside your while loop:
float _pm25Median = pm25s.getMedian();
float _pm10Median = pm10s.getMedian();
if (isnan(_pm25Median) || isnan(_pm10Median))
continue; // or do something else to handle this exception properly
if (_pm25Median < 9)
pm25i = 1;
else if (_pm25Median < 17)
pm25i = 2;
else if (_pm25Median < 27)
pm25i = 3;
else if (_pm25Median < 35)
pm25i = 4;
else if (_pm25Median < 44)
pm25i = 5;
else if (_pm25Median < 52)
pm25i = 6;
else
pm25i = 7;
if (_pm10Median < 9)
pm10i = 1;
else if (_pm10Median < 17)
pm10i = 2;
else if (_pm10Median < 52)
pm10i = 3;
else if (_pm10Median < 69)
pm10i = 4;
else if (_pm10Median < 85)
pm10i = 5;
else if (_pm10Median < 102)
pm10i = 6;
else
pm10i = 7;
if (pm25i >= pm10i) {
switch (pm25i) {
case 1:
status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
break;
case 2:
status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities.";
break;
case 3:
status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
break;
case 4:
status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
break;
case 5:
status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
break;
case 6:
status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
break;
case 7:
status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
default:
break;
}
} else {
switch (pm10i) {
case 1:
status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
break;
case 2:
status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities";
break;
case 3:
status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
break;
case 4:
status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
break;
case 5:
status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
break;
case 6:
status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
break;
case 7:
status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
break;
default:
break;
}
}

Related

How to allow my C++ code to update variables?

I'm new to coding and C++.
The code below is meant to monitor a magswitch and a status led on another controller. The code needs to run once the magswitch pin goes high (this works).
The additional code for pulseIn, is what I hope to use to monitor different flash rates of the led when I get the code working. For now I'm just looking for the state variable to update with the if and else if statements.
When I toggle the statusPin, the code picks up the changing state, but I cannot get it to update the "state" and "statuspinstate" variables.
The statuspinstate variable shows as 1, even though it is initialized as 0.
I inserted all the serial prints to try and see where things are going wrong.
This is the serial print when "statusPin" is LOW:
statuspinstate: 0
rate1: 2147483647
period: 0.00
rate2: 0
ontime: 0
offtime: 0
state: 0
statepinstatus: 1
This is the serial print when "statusPin" is HIGH
statuspinstate: 1
rate1: 2147483647
period: 0.00
rate2: 0
ontime: 0
offtime: 0
state: 0
statepinstatus: 1
Code:
const int statusPin = 19; //Reads status led
const int magSwitch = 22; //Magswitch to detect movement
int ontime,offtime,rate1,rate2;
float freq,period;
volatile unsigned int state =0;
volatile unsigned int statuspinstate = 0;
void setup()
{
pinMode(statusPin, INPUT); //input from controller
pinMode(magSwitch, INPUT);
Serial.begin(115200);
}
void loop()
{
while (digitalRead(magSwitch) == LOW) {
}
{
statuspinstate = digitalRead(statusPin);
ontime = pulseIn(statusPin,HIGH);
offtime = pulseIn(statusPin,LOW);
period = ontime+offtime;
rate1 = (ontime/period); //future use
rate2 = (offtime); //future use
Serial.println(String("statuspinstate ") + (digitalRead(statusPin))); //all serial print is debug info
Serial.println(String("rate1: ") + (rate1));
Serial.println(String("period: ") + (period));
Serial.println(String("rate2: ") + (rate2));
Serial.println(String("ontime: ") + (ontime));
Serial.println(String("offtime: ") + (offtime));
delay(500);
}
if ((ontime) != 0)
state = period;
else if (statuspinstate = 1)
state = 9999;
else if (statuspinstate = 0);
state = 0;
Serial.println(String("state: ") + (state));
Serial.println(String("statepinstatus: ") + (statuspinstate));
statuspinstate = 0; //return statuspinstate to zero
}
Look at your conditional, with proper indentation (do get a text editor that can indent your code for you):
if ((ontime) != 0)
state = period;
else if (statuspinstate = 1)
state = 9999;
else if (statuspinstate = 0);
state = 0;
We know that ontime is zero, so the second condition is tried next.
Now, statuspinstate = 1 is an assignment, not a comparison, and its value is "truth-y" so you take that branch.
Next, the stray semicolon in if (statuspinstate = 0); (which is also an assignment condition, but not evaluated) makes state = 0 unconditional.
So every time ontime is zero, you end up executing statuspinstate = 1 and state = 0.
What you probably want is
if (ontime != 0)
state = period;
else if (statuspinstate == 1)
state = 9999;
else if (statuspinstate == 0)
state = 0;

Refactoring switch or if/else statement? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
i'm working on a school project and got some feedback from my teacher. He said that in my code there are some bad practices, he said that the switch cases could be replaced by a polymorphic approach. Only i have no clue how i could do this.
My code is receiving messages from a CAN bus. Those messages come from different devices, I check the messages from which device they come from. If there is a new device I create a object and parse the message and store the information.
This system is pretty much the same for each message.
Here is my code.
void Application::PollWhisperConnectBus()
{
HAL_GPIO_TogglePin(PORT_LED1, PIN_LED1);
whisper_connect_id_ = hcan2.pRxMsg->StdId;
if (whisper_connect_id_ >= 0x580 && whisper_connect_id_ <= 0x58F)
{
WIBDevice();
}
if (whisper_connect_id_ >= 0x590 && whisper_connect_id_ <= 0x59F)
{
BMSSDevice();
}
if (whisper_connect_id_ >= 0x5B0 && whisper_connect_id_ <= 0x5BF)
{
DCPowerCubeDevice();
}
if (whisper_connect_id_ >= 0x5C0 && whisper_connect_id_ <= 0x5CF)
{
ACPowerCubeDevice();
}
if (whisper_connect_id_ >= 0x700 && whisper_connect_id_ <= 0x70F)
{
WIBHeartBeatDevice();
}
}
This is one of the functions which checked if there is an object of the class, if so parse the message.
void Application::DCPowerCubeDevice()
{
bool found_device = false;
int device = (hcan2.pRxMsg->StdId & 0x0F) + device_instance_offset_;
WhisperConnectDevice* whisper_connect_device;
for(unsigned int i = 0; i < whisper_connect_device_list_.size(); ++i)
{
if ((whisper_connect_device = whisper_connect_device_list_.at(i)) != NULL &&
whisper_connect_device->GetClassName() == "DCPowerCube")
{
DCPowerCube* dc_powercube = dynamic_cast<DCPowerCube*>(whisper_connect_device);
if (dc_powercube != NULL)
{
if (dc_powercube->GetDevice() == device)
{
dc_powercube->ParseCanMessage(&hcan2);
found_device = true;
break;
}
}
}
}
if (!found_device)
{
WhisperConnectDevice* dc_powercube;
if ((dc_powercube = new DCPowerCube) != NULL)
{
dc_powercube->SetDevice(device);
int n2k_address = nmea2000_.FindFirstFreeCanId(n2k_address_, device_list_);
if (n2k_address != 0xFFFF)
{
dc_powercube->SetSrcCanId(n2k_address);
dc_powercube->SetDeviceInstanceOffset(device_instance_offset_);
dc_powercube->SetDeviceInstance(0x30 + device);
dc_powercube->AddressClaim(nmea2000_);
dc_powercube->SendPGN126996(nmea2000_);
dc_powercube->SendPGN126998(nmea2000_, "DCPowerCube", "", "");
device_list_.at(n2k_address) = 0x01;
}
DCPowerCube* dc_powercube2 = dynamic_cast<DCPowerCube*>(dc_powercube);
if (dc_powercube2 != NULL)
{
dc_powercube2->SetCurrentLimit(16);
}
AddToWPCDeviceList(dc_powercube);
}
}
}
void DCPowerCube::ParseCanMessage(CAN_HandleTypeDef *can_handle)
{
if (can_handle != NULL)
{
uint16_t message_index = (can_handle->pRxMsg->Data[1] << 8) + can_handle->pRxMsg->Data[2];
switch (message_index)
{
case 0x1008:
device_name_[0] = can_handle->pRxMsg->Data[4];
device_name_[1] = can_handle->pRxMsg->Data[5];
device_name_[2] = can_handle->pRxMsg->Data[6];
device_name_[3] = can_handle->pRxMsg->Data[7];
device_name_[4] = '\0';
break;
case 0x100A:
software_version_[0] = can_handle->pRxMsg->Data[4];
software_version_[1] = can_handle->pRxMsg->Data[5];
software_version_[2] = can_handle->pRxMsg->Data[6];
software_version_[3] = can_handle->pRxMsg->Data[7];
software_version_[4] = '\0';
break;
case 0x1018:
serial_number_ = can_handle->pRxMsg->Data[4] << 24 | can_handle->pRxMsg->Data[5] << 16 |
can_handle->pRxMsg->Data[6] << 8 | can_handle->pRxMsg->Data[7];
break;
case 0x2100: // DC PowerCube status
power_cube_status_ = can_handle->pRxMsg->Data[4];
io_status_bit_ = can_handle->pRxMsg->Data[5];
dip_switch_status_bit_ = can_handle->pRxMsg->Data[6];
break;
case 0x2111: // Grid voltage, current, current limit
grid_voltage_ = (can_handle->pRxMsg->Data[4] << 8) + can_handle->pRxMsg->Data[5];
grid_current_ = can_handle->pRxMsg->Data[6];
grid_current_limit_ = can_handle->pRxMsg->Data[7];
break;
case 0x2112: // Generator frequency, RPM
generator_freq_ = (can_handle->pRxMsg->Data[4] << 8) + can_handle->pRxMsg->Data[5];
rpm_ = (can_handle->pRxMsg->Data[6] << 8) + can_handle->pRxMsg->Data[7];
break;
case 0x2113: // Generator current
gen_current_phase1_ = can_handle->pRxMsg->Data[4];
gen_current_phase2_ = can_handle->pRxMsg->Data[5];
gen_current_phase3_ = can_handle->pRxMsg->Data[6];
gen_current_limit_ = can_handle->pRxMsg->Data[7];
break;
case 0x2114: // Load percentage
grid_load_ = can_handle->pRxMsg->Data[4];
generator_load_ = can_handle->pRxMsg->Data[5];
dc_output_load_ = can_handle->pRxMsg->Data[6];
break;
case 0x2151: // Battery type & charger state
battery_type_ = can_handle->pRxMsg->Data[4];
charger_state_ = can_handle->pRxMsg->Data[5];
break;
case 0x2152: // DC output voltage & DC slave voltage
dc_output_voltage_ = (can_handle->pRxMsg->Data[4] << 8) + can_handle->pRxMsg->Data[5];
dc_slave_voltage_ = (can_handle->pRxMsg->Data[6] << 8) + can_handle->pRxMsg->Data[7];
break;
case 0x2153: // DC output current & DC output current limit
dc_output_current_ = (can_handle->pRxMsg->Data[4] << 8) + can_handle->pRxMsg->Data[5];
dc_output_current_limit_ = (can_handle->pRxMsg->Data[6] << 8) + can_handle->pRxMsg->Data[7];
break;
case 0x21A0: // Temperature sensor
temp_sens_BTS_ = can_handle->pRxMsg->Data[4];
temp_sens_intern1_ = can_handle->pRxMsg->Data[5];
temp_sens_intern2_ = can_handle->pRxMsg->Data[6];
temp_sens_intern3_ = can_handle->pRxMsg->Data[7];
break;
case 0x21A1:
break;
}
}
}
The WhisperConnectDevice is the base class of DCPowerCube.
I would love to get some feedback on how to approach this problem.
Whether or not you introduce polymorphism it appears you have to map an externally provided type number (ID) to code so you will always need some structure inbetween.
Your candidates are:
A block of if statements probably if-else-if...
A switch statement (if values are ameanable)
Some kind of look-up table (array, associative map, other...)
You've already got if but could improve with if-else-if.
That is normally considered the ugliest high-maintenance potential coding hot-spot approach. Coding hot-spot because all new IDs return to this code block.
I also notice in this case all your ranges are 0xnn0 to 0xnnF inclusive for some nn so you can at least simplify by reducing out the low 4 bits:
auto whisper_connect_type = whisper_connect_id_ >> 4;
Your switch option is then simplified to:
switch(whisper_connect_type) {
case 0x58: WIBDevice(); break;
case 0x59: BMSSDevice(); break;
case 0x5B: DCPowerCubeDevice(); break;
case 0x5C: ACPowerCubeDevice(); break;
case 0x70: WIBHeartBeatDevice(); break;
default: HandleUnknownDeviceIDError(whisper_connect_id_); break;
}
NB: I very strongly recommend some code to handle an unsupported ID. My advice is throwing an exception or something leading to termination. The break; is for completeness. I don't think you're coming back from an unknown ID.
An alternative is to define an associative map:
#include <iostream>
#include <unordered_map>
#include <memory>
class WhisperHandler {
public:
virtual void HandleWhisper() const = 0 ;
virtual ~WhisperHandler() {}
};
class WhisperHandlerWIBDevice : public WhisperHandler {
public:
void HandleWhisper() const override {
std::cout << "Handler WIBDevice...\n";
}
} ;
int main() {
std::unordered_map<unsigned,std::unique_ptr<const WhisperHandler>> handlers;
//...
std::unique_ptr<const WhisperHandler> handler(std::make_unique<const WhisperHandlerWIBDevice>());
std::pair<const unsigned , std::unique_ptr<const WhisperHandler> > pair({0x5B,std::move(handler)});
handlers.insert(std::move(pair));
//...
{
const auto &chandlers=handlers;
auto handlerit(chandlers.find(0x5B1));
if(handlerit!=chandlers.end()){
handlerit->second->HandleWhisper();
}else{
//ERROR - UNKNOWN HANDLER.
}
}
return 0;
}
I would suggest however you're only going to get return on investment for all this polymorphic machinery if you're going to allow the registration of handlers dynamically either from different modules of the application or by dynamically loading libraries that register themselves on load.
If it's a single project application (which it appears to be) then the switch table dispatch will probably work fine.
Because applications tend to communicate using IDs of some kind OO can start to look cumbersome when it in practice it needs to take an ID, map it to a polymorphic handler and then call the handler. Logically you've done the ID to logic mapping twice!
Footnote: The trick of knocking out the lowest 4-bits is somewhat separate from these methods and (of course) slightly fragile if the lower 4 bits become relevant to determining the handler down the line.

Some of these codes don't run [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
i'm a beginner at C++ and i tried to make a script for a Trinity Core World of Warcraft private server but it seems that some of the codes ran successfully and the others are escaped for unknown reason..
here's the code
#include "ScriptPCH.h"
#include "DisableMgr.h"
class LearnSpellsOnLevelUp : public PlayerScript
{
public:
LearnSpellsOnLevelUp()
: PlayerScript("LearnSpellsOnLevelUp"){};
void OnLevelChanged(Player* player, uint8 oldLevel)
{
if (player->getClass() == 3 && player->getLevel() >= 12) // ran
{
if (player->HasSpell(23356)) // ran
return; // ran
else // ran
player->LearnSpell(23356, false); // ran
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Taming Lesson]!|r"); // ran
}
if (player->getClass() == 9) // Warlock // ran
{
if (player->getLevel() >= 2) // ran
{
if (player->HasSpell(44163)) // ran
return;
else
player->LearnSpell(44163, false); // ran
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Imp]!|r"); // ran
}
else if (player->getLevel() >= 10)
{
if (player->HasSpell(25112))
return;
else
player->LearnSpell(25112, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Voidwalker]!|r");
}
else if (player->getLevel() >= 20)
{
if (player->HasSpell(712))
return;
else
player->LearnSpell(712, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Succubus]!|r");
}
else if (player->getLevel() >= 30)
{
if (player->HasSpell(691))
return;
else
player->LearnSpell(691, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Felhunter]!|r");
}
else
return;
}
}
};
void AddSC_LearnSpellsOnLevelUp()
{
new LearnSpellsOnLevelUp();
}
i wrote next to the codes that ran successfully // ran
Pay close attention to the order of your getLevel conditions.
if (player->getLevel() >= 2)
{
}
// Here, it's certain that the level is < 2, since it wasn't >= 2.
// Thus, none of these following tests will be true.
else if (player->getLevel() >= 10)
{
}
else if (player->getLevel() >= 20)
{
}
else if (player->getLevel() >= 30)
{
}
else
return;
You should test the levels starting with the greatest one and work your way donwnward.
if (player->getLevel() >= 30)
{
}
// The level is less than 30. Is it greater than 20?
else if (player->getLevel() >= 20)
{
}
// The level is less than 20. Is it greater than 10?
else if (player->getLevel() >= 10)
{
}
// The level is less than 10. Is it greater than 2?
else if (player->getLevel() >= 2)
{
}
else
return;
Looks like there is simply a logic bug. Let's look at this statement:
if (player->getLevel() >= 2) // ran - ok so far
And now a lot of this:
else if (player->getLevel() >= 10) - and others (comparing with 20, 30)
Now suppose your 'player' has 15 level - looks like the intent was to run the second if block (e.g. where you compare with >= 10)
But there is a problem: if the level is 15 then everytime only the first if-block is executed (because obviously 15 >= 2).
Solution: compare to range, like this:
if ((player->getLevel() >= 2) && (player->getLevel() < 10))
...
else if ((player->getLevel() >= 10) && (player->getLevel() < 20))
...
And so on.

How to write nested if or case to make a prompted input menu?

I'm working on an experience design project for one of my classes using a rotary phone and arduino kit to create a game based on automated phone menus. Serial input from the rotary dial is running through arduino and now I am using processing to write the menu.
I have an outline of actions and have started to code some if then statements to get going but now I have stumbled upon case and switch.
I am completely new to this but have learned a lot in class.
My question is how do I make a continuous set of nested if/then statments OR use case and switch to move through a series of prompts and inputs?
Here is my sketch so far:
import processing.serial.*;
Serial port; // Create object from Serial class
float val; // Data received from the serial port
boolean task1prompted;
boolean task1;
boolean task2;
boolean dialed;
PFont font;
void setup() {
size(800, 400);
background(0, 0, 0);
smooth();
// IMPORTANT NOTE:
// The first serial port retrieved by Serial.list()
// should be your Arduino. If not, uncomment the next
// line by deleting the // before it. Run the sketch
// again to see a list of serial ports. Then, change
// the 0 in between [ and ] to the number of the port
// that your Arduino is connected to.
//println(Serial.list());
String arduinoPort = Serial.list()[0];
port = new Serial(this, arduinoPort, 9600);
task1 = false;
task2 = false;
task1prompted = false;
font = createFont("Arial", 32);
textFont(font, 32);
textAlign(CENTER);
}
void draw() {
if (port.available() > 0) { // If data is available,
val = port.read(); // read it and store it in val
if (val >= 48 && val <= 57) {
val = map(val, 48, 57, 0, 9); // Convert the value
}
println(val);
}
if (val == 97) {
println("dialing");
}
if (val == 98){
println("dialed");
dialed = true;
}
/// switch will activate the task1 variable.
// Play sound file for the prompt.
if (task1prompted == false){
delay(1000);
println("for spanish, press one. for french, press 2...");
task1prompted = true;
}
task1 = true;
if (task1 == true && dialed == true) {
///play sound file
if (val == 5) {
println("Thank you for playing... Blah blah next prompt.");
dialed = true;
task1=false;
task2=true;
} else
if (val != 5) {
println("We're sorry, all of our international operators are busy");
task1 = true;
task2 = false;
dialed = false;
}
}
else
if (task2 == true){
delay(1000);
println("task2 start");
}
}
My instructor helped me to get this far and I have been scouring for answers on how to keep going on to the next task/prompt. Would it be easier to use case and switch? And am I even doing nested if statements the right way?
Well I just tried this out with sketch and case commands as follows:
/// Switch will activate the task1 variable.
// Play sound file for the prompt.
if (task1prompted == false){
delay(1000);
println("for spanish, press one. for french, press 2...");
task1prompted = true;
}
task1 = true;
if (task1 == true && dialed == true) {
///Play sound file
int lang = (int)(val+0);
switch(lang) {
case 1:
case 2:
case 3:
case 4:
println("sorry no international operators"); // If 1-4 go back to choices
task1 = true;
task2 = false;
dialed = false;
break;
case 5:
println("thank you, move to next prompt"); // If 5 go to next prompt
task1=false;
task2=true;
dialed = true;
break;
case 6:
case 7:
case 8:
case 9:
case 0:
println("not a valid option, you lose"); // If not 1-5 go back to beginning
task1=false;
task2=false;
dialed = true;
break;
}
if (task2prompted == false){
delay(1000);
println("please listen while we test the line");
task2prompted = true;
}
task2 = true;
if (task2 == true && dialed == true) {
} ///Play sound file
int tone = (int)(val+0);
switch(tone) {
case 1:
case 2:
case 3:
case 5:
case 6:
case 7:
case 8:
case 9:
case 0:
println("not a valid connection, you lose"); // If not 4 go back to beginning
task2 = false;
task3 = false;
dialed = false;
break;
case 4:
println("thank you, move to next prompt"); // If 4 move to next prompt
task2=false;
task3=true;
dialed = true;
break;
}
}
}
I'm still confused on how to make this have levels and not all happen simultaneously.
You might want to look up finite state machines. It's a pretty common approach to dealing with event driven user interfaces.
I'm not entirely sure what your question is but maybe something here will answer it, if not just clarify what you're looking for
With case statements you don't need to make a case for every single output that can happen. the way you can avoid doing that is by using a default statement
Example:
switch(tone) {
case 4:
println("thank you, move to next prompt"); // If 4 move to next prompt
task2=false;
task3=true;
dialed = true;
break;
default:
println("not a valid connection, you lose"); // If not 4 go back to beginning
task2 = false;
task3 = false;
dialed = false;
}
The default case doesn't need a break because it is at the end. But essentially it is the catch all case if nothing else is hit.
Also in some of your code above
if (val == 97) {
println("dialing");
}
if (val == 98){
println("dialed");
dialed = true;
}
it is better to use an "else if" to make it not have to check through both if one is correct
if (val == 97) {
println("dialing");
}
else if (val == 98){
println("dialed");
dialed = true;
}

Writing Java equivalent of the Fortran program

I have something like this in fortran.
20: call TESTBEGIN(a,b,c)
if(c<1) goto 40
30: call TESTMIDDLE(e,f,g)
if(g==1) goto 20
40: return
But my code is like this
Subroutine testCase()
20: CALL beginTest(a,b)
IF (b.EQ.-1) GOTO 999
30: CALL middleTest(c,b)
IF (b.EQ.-1) GOTO 20
40: CALL endTest(d,b)
IF (b.EQ.-1) GOTO 30
CALL LastTest(e,b)
IF (.b.EQ.-1) GOTO 40
DO I =1,j
DTEMP(j)=1.0
END DO
some code
999:return
Something like that?
do
{
c = TESTBEGIN(a,b);
if (c < 1) break;
g = TESTMIDDLE(e,f);
} while ( g == 1 );
For the second code snippet try a state machine:
for(int state = 1; state != 0; )
{
switch(state)
{
case 1:
state = (beginTest(a) == -1) ? 0 : 2;
break;
case 2:
state = (middleTest(c) == -1) ? 1 : 3;
break;
case 3:
state = (endTest(d) == -1) ? 2 : 4;
break;
case 4:
state = (lastTest(e) == -1) ? 3 : 5;
break;
}
case 5:
state = 0;
// DO I =1,j // Honestly I don't know what does it do.
// DTEMP(j)=1.0
break;
}
Or better try to reconsider the algorithm, I think you could do it more easy to read and understand using Java.