How to create a macro on a condition inside a if statement - c

I need to iterate a for loop nested inside of a while loop for several different conditions.
The only change in the code for each statement is the comparison condition to apply.
Turns out I am copy-pasting all of the code multiple times and changing the direction of the greater-less than symbol.
for example:
if (direction.horizontal == UIScrollDirectionLeft) {
int column = startColumn+1;
while (column < maxAllowed) {
for (int row = minRow; row < maxRow; row++) {
repeated code
}
column++;
} else {
int column = minColumn -1;
while (column >= 0) {
for (int row = minRow; row < maxRow; row++) {
repeated code
}
column--;
}
}
Is it possible to do a macro for the condition operator in order to facilitate code reuse?
I would really like something which could look like this:
int startColumn = (direction.horizontal == UIScrollDirectionLeft) ? (startColumn+1) : minColumn -1;
SignOfOperator theSignInTheWhile = (direction.horizontal == UIScrollDirectionLeft) ? "<" : ">=";
int conditionToTestInWhile = (direction.horizontal == UIScrollDirectionLeft) ? maxAllowed : 0;
while(startColumn,theSignInTheWhile,conditionToTestInWhile) {
// repeated code
}
I have another 4 cases like the one above...

You only need the loop code once. Just change the step value and terminating value. For example:
int start_column, end_column, column_step;
:
switch (direction.horizontal) {
case UIScrollDirectionLeft:
column = start_column + 1;
column_step = 1;
end_column = max_allowed;
break;
case UIScrollDirectionRight:
column = min_column - 1;
column_step = -1;
end_column = -1;
break;
:
}
while (column != end_column) {
for (int row = minRow; row < maxRow; row++) {
repeated_code();
}
column += column_step;
}

Related

How would I check if every element in a row within a 2D array is the same in C?

So for example if I had a 2D array of char seatingChart[5][5] =
x x . x x
. x . x x
. . . . .
x x x x .
. . . . .
How would I print out that the 3rd and 5th rows are all "."?
I was trying to do it like this
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
}
if (seatingChart[row][0-9] == "."){
printf("Row %d is empty",row+1);
}
}
}
Is there a quicker way of doing this without writing && multiple times in the if statement? because my actual seating chart has 1000 rows and 1000 columns
You can do that by
Set "all elements in this row is ." flag.
Iterate over the row.
When you find an element that is not ., clear the flag.
After the iteration, check the flag to see the result.
#include <stdio.h>
int main(void) {
char seatingChart[5][5] = {
"xx.xx",
".x.xx",
".....",
"xxxx.",
"....."
};
for (int row = 0; row < 5; row++) {
int is_all_dot = 1;
for (int col = 0; col < 5; col++) {
if (seatingChart[row][col] != '.') {
is_all_dot = 0;
break;
}
}
if (is_all_dot) {
printf("Row %d is empty\n", row + 1);
}
}
return 0;
}
You just check to see if the next element is the same as the current element, and if the whole row passes then you flag the row index as being all the same. If any of the checks fail you can move on to the next row because it invalidates the entire row.
For this I would recommend writing a separate function for checking rows. This both makes the program more readable and you can use early return as part of your algorithm:
bool row_empty(size_t row_length, const char row[row_length])
{
for (size_t n = 0; n < row_length; n++)
{
/*
As soon as we see a non-empty seat, we know that the
row is empty
*/
if (row[n] != '.')
return false;
}
/* We only reach this point if all the seats were empty */
return true;
}
Now, looping through your rows becomes dead simple:
for (int row = 0; row < num_rows; row++)
{
if (row_empty(row_length, seatingChart[row])
{
printf("Row %d is empty",row+1);
}
}
Some final notes:
I removed the hardcoded value 5 for your benefit.
You have to add #include <stdbool.h> to use bool, true and false.
If your compiler doesn't have stdbool.h you have to use int, 1 and 0

Cycle through an array in either direction based on a bool

I'm looking for a method of looping through some array in either direction based on some passed bool value, with the same functionality as:
void Transfer(bool *_payload, int _size, bool _isLSB)
{
if (_isLSB)
{
for (int i = _size - 1; i >= 0; i--)
{
digitalWrite(dataPin, _payload[i]);
}
}
else
{
for (int i = 0; i < _size; i++)
{
digitalWrite(dataPin, _payload[i]);
}
}
}
or
void Transfer(bool *_payload, int _size, bool _isLSB)
{
int _index = 0;
if (_isLSB) _index = _size - 1;
for (;;)
{
printf("%d",_payload[_index]);
if (_isLSB) _index--;
else _index++;
if (_isLSB && _index < 0) break;
if (!_isLSB && _index >= _size) break;
}
}
Other than creating a method that reverses the array, is there a nice simplification of this?
You can define the starting and ending point and the increment conditionally:
void Transfer(bool *_payload, int _size, bool _isLSB)
{
int increment = _isLSB ? -1 : 1;
int i = _isLSB ? _size : -1; // one before the area to scan
int end = _isLSB ? -1 : _size; // one past the area
while ((i += increment) != end) // incr/decr before testing
{
digitalWrite(dataPin, _payload[i]);
}
}
We do not know in advance which way the index will be changing (incrementing or decrementing), so we can't use less-than or greater-than in the loop condition. And after processing the last item the index will be modified once more, hence the stopping point is one past the area being processed.
Similarly we need the starting point one position before the scanned area, so that after incrementing (or decrementing) the index we process the valid, first item.
You can calculate the direction and the start/end position for the for loop depending on _isLSB
void Transfer(bool* _payload, int _size, bool _isLSB) {
int dir;
int start;
int end;
if(_isLSB) {
dir = -1;
start = _size-1;
end = -1;
}else {
dir = 1;
start = 0;
end = _size;
}
for(int i = start; i != end; i+=dir) {
digitalWrite(dataPin, _payload[i]);
}
}
What you could do for example, since in C true and false are expanded to integer values in reality, is to use said integer value for calculations.
In the following example I will extract the main problem from your question which is: Looping over a size in a direction depending on a boolean value
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
int main()
{
int size = 5;
bool condition = false;
// Option #1
printf("Option #1\n");
for (int i = (size - 1) * condition; (i >= 0 && condition) || (i < size && !condition); i += 1 * pow(-1, condition))
{
printf("%d", i);
}
// Option #2
printf("\nOption #2\n");
int i = (size - 1) * condition;
for (;;)
{
printf("%d", i);
i += 1 * pow(-1, condition);
if ((i < 0 && condition) || (i >= size && !condition))
break;
}
return 0;
}
With the main function giving the following output for condition = true
Option #1
01234
Option #2
01234
And the following output for condition = false
Option #1
43210
Option #2
43210

How to check for n consecutive same characters in row in c

So my assignment is to write a program for Connect-N, which is basically the game Connect-4 but where the user specifies the number of rows and columns (doesn't have to be square) and specifies the number of consecutive pieces to win (this doesn't have to fit on the board). For example, if the user specifies a 3x3 board, they can also say 4 consecutive pieces are needed to win.
I'm having trouble writing a program to check for a row win, where the player wins the game completely horizontally. Here's what I have so far:
bool horizontalWin(char **board, const int numRows,
const int numCols, const char blankSpace, const int numToWin) {
if((numCols - numToWin) < 0) {
return false;
}
else {
for (int row = 0; row < numRows; ++row) {
for (int col = 0; col <= numCols-numToWin; ++col) {
///This is where I need help
}
}
}
return false;
}
Just for reference: the variable blankSpace is a '*' and is used to denote a blank space on the board.
My idea was to have a nested for loop that started at column 0 and then checked far enough forward to see if they were all identical characters, but I can't seem to figure out how to accomplish this. Can someone point me in the right direction?
Count the number of matches, or reset the count when there is no match.
Assuming board[row][col], and that the color you check is user1
for (int row = 0; row < numRows; ++row) {
int match = 0;
for (int col = 0; col <= numCols-numToWin; ++col) {
if (board[row][col] != user1) match = 0;
else {
match++;
if (match >= numToWin) return true;
}
}
}
Note that you could do if (++match >= numToWin) return true; to save a line (if you feel this being readable).
This is not in the problem description, but if you have two players, there should be 3 colors, say blankSpace, user1, and user2. The program above checks if user1 wins.
So you could add an argument to the function to tell which color you are testing for a win (say colorCheck), the whole function becomes
bool horizontalWin(char **board, const int numRows,
const int numCols, const char blankSpace, const int numToWin, const in colorCheck) {
if((numCols - numToWin) < 0) {
return false;
}
else {
for (int row = 0; row < numRows; ++row) {
for (int col = 0; col <= numCols-numToWin; ++col) {
if (board[row][col] != colorCheck) match = 0;
else {
match++;
if (match >= numToWin) return true;
}
}
}
}
return false;
}
You can set two counters, one for the red discs and the other for the yellow ones. Then inside the body of your nested loop whenever you encounter an r increment the red discs counter by one, the same goes for yellow disks.
Then you can check after each row iteration if any of these counters equals the given N required to win the game.
You can do it this way supposing you denote a red disk with an r and a yellow disk with a y :
else
{
int red_c, yellow_c;
for (int row = 0; row < numRows; ++row)
{
red_c=0; yellow_c=0;
for (int col = 0; col < numCols; ++col)
{
if(board[r][c]=='r') red_c++;
else if (board[r][c]=='y') yellow_c++;
if(red_c == numToWin )
{
//Red wins
}
else if(yellow_c == numToWin )
{
//Yellow wins
}
}
}
}
The code will depend if you want to know if someone win in the board of if you win after an specific move.
This is a common and simple code that you can execute after each move or for every position in the board:
The idea is to move in every direction from the center (the new position of a piece) making something like a star " * " (like the star character)
consecutivesInHorizontal =0
consecutivesInVertical = 0
consecutivesDiagLeft =0
consecutiveDiagRight = 0
for i =1 ; i < height && i<width && i<= 4 ; i++
if(board[centerX][centerY+i] == myPieceColor)
consecutivesInVertical++;
if(board[centerX][centerY-i] == myPieceColor)
consecutivesInVertical++;
if(board[centerX+i][centerY] == myPieceColor)
consecutivesInHorizontal++;
if(board[centerX-i][centerY] == myPieceColor)
consecutivesInHorizontal++;
if(board[centerX+i][centerY-i] == myPieceColor)
consecutivesDiagLeft++;
if(board[centerX-i][centerY+i] == myPieceColor)
consecutivesDiagLeft++;
if(board[centerX-i][centerY+i] == myPieceColor)
consecutiveDiagRight++;
if(board[centerX+i][centerY-i] == myPieceColor)
consecutiveDiagRight
if any of the consecutive variables == 4
return true

Searching array twice

This is a hackerrank problem.
Find out the maximum movies that can be watched. Assume the list to be distinct movies.
Input:
movieStart[] = {10,12,9,14,16,14}
movieEnd[] = {11,13,15,16,18,18}
Output : 4 (10-11,12-13,14-16,16-18)
Below code is giving me correct output. Would like to know the best solution possible for this problem.
Also what algorithm is used to solve this kind of problem?
static int getMaxMovies(int[] movie_start, int[] movie_end) {
int cnt = 0;
for (int i = 0; i < movie_start.length; i++) {
for (int j = 0; j < movie_start.length; j++) {
if (movie_start[j] == movie_start[i] && movie_end[j] == movie_end[i]) {
continue;
}
if (movie_start[j] >= movie_start[i] && movie_end[j] <= movie_end[i]) {
cnt += 1;
break;
}
}
}
return movie_start.length - cnt;
}
That's "Activity selection" problem - which could be easily solved with O(n) (in case of sorted input) or O(nlogn) (when input isn't sorted) greedy algorithm. If input is already sorted by finishing (end) time you should pick movies which doesn't conflict with previously selected movie.
Pseudocode:
Sort by finish times
int previouslySelectedIndex = 0;
int watchedMoviesCount = 1;
for (int i=1; i<movie_end.Length; i++)
{
if (movie_start[i] >= movie_end[previouslySelectedIndex)
{
watchedMoviesCount++;
previouslySelectedIndex=i;
}
}

jCombobox giving incremental value error on jTable

I am having problems with my code below, the code below shows a jComboBox being populated, when i select an item from this list it is added to the jTable below it.
There is alos code to check for duplicate entries ont he table. If a duplicate entry is found it should increase the qty column by one and not create a seperate entry.
This is where the problem comes in, when I press the back button on this screen and go to a different screen and then come back via same route as the first time, I get an incrementally different qty added to the table row/cell.
I have also included the code that populates the Round Details depending on Round Drop selected from table, for reference, but Im fairly certain the problem lies in the below code. The navigation is as follows...
To get to the below screen... Round Drop panel table of round drops) >> click on table row and taken to associated round details panel >> pressing the Till button takes user to screen with code below...
Test results:
First pass through below code using navigation above gives results as expected
Second pass gives an initial value of 2 (instead of one), and duplicate row increases qty by 2 instead of one
Third pass gives an initial value of 3 (instead of one), and duplicate row increases qty by 3 instead of one
Fourth pass gives an initial value of 4 (instead of one), and duplicate row increases qty by 4 instead of one
...and so on.
Any help, guidance on solution or a better design would be hugely appreciated.
Thanks
/*************Code sample ********************************/
public void tillOperations(String sourceCall) {
final DefaultTableModel model = (DefaultTableModel)main.tillPanel.tblTillSale.getModel();
if (main.tillPanel.cmbTillProdSelect.getItemCount() < 1) {
for (int d = 0; d < roundStockObj.length ; d++) {
main.tillPanel.cmbTillProdSelect.addItem(roundStockObj[d].getDescription());
}}
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
main.tillPanel.cmbTillProdSelect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent f)
{
int qty = 1;
for (int index = 0; index < 4; index++) {
addSelectedItem[index] = "";
}
int row;
selectedItem = null;
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
selectedItem = main.tillPanel.cmbTillProdSelect.getSelectedItem();
for (int d = 0; d < roundStockObj.length; d++) {
if (selectedItem.equals(roundStockObj[d].getDescription())) {
addSelectedItem[0] = roundStockObj[d].getDescription();
addSelectedItem[1] = Integer.toString(qty);
addSelectedItem[2] = Double.toString(roundStockObj[d].getPrice()).trim();
addSelectedItem[3] = Double.toString(roundStockObj[d].getPrice()).trim();
//break;
}
}
if(model.getRowCount() == 0) { //check if model is empty
model.addRow(new String[]{addSelectedItem[0], addSelectedItem[1], addSelectedItem[2], addSelectedItem[3]});
}
else { //check if there is a duplicate row
int duplicateRow = -1;
for (row = 0 ; row < model.getRowCount(); row++) {
if(addSelectedItem[0].equals(main.tillPanel.tblTillSale.getModel().getValueAt(row,0))) {
duplicateRow = row;
break;
}
}
if(duplicateRow == -1) { //if there is no duplicate row, append
model.addRow(new String[]{addSelectedItem[0], addSelectedItem[1], addSelectedItem[2], addSelectedItem[3]});
}
else { //if there is a duplicate row, update
main.tillPanel.jLabel1.setText(addSelectedItem[1]);
DecimalFormat fmtObj = new DecimalFormat("####0.00");
int currentValue = Integer.parseInt(main.tillPanel.tblTillSale.getValueAt(row, 1).toString().trim());
int newValue = currentValue + 1;
Integer newValueInt = new Integer(newValue);
model.setValueAt(newValueInt, row, 1);
double unitPrice = Double.parseDouble(main.tillPanel.tblTillSale.getValueAt(row, 2).toString().trim());
double newPrice = newValue * unitPrice;
Double newPriceDbl = new Double(newPrice);
main.tillPanel.tblTillSale.setValueAt(fmtObj.format(newPriceDbl), row, 3);
}
}
main.tillPanel.tblTillSale.removeRowSelectionInterval(0, model.getRowCount() - 1);
for (int index = 0; index < 4; index++) {
addSelectedItem[index] = "";
}
}
});
//This code loads the specific Round Details, based on the selection form the round drops table
public void displayRoundDropDetails() {
DefaultTableModel model = (DefaultTableModel)main.selectRoundDropPanel.tblSelectRoundDrop.getModel();
if (!loaded) {
for (int d = 0; d < roundDropsData.length; d++) {
if (roundDropsData[d][0].equals(defaultRoundID)) {
model.addRow(new Object[]{roundDropsData[d][3], roundDropsData[d][2],
roundDropsData[d][4], roundDropsData[d][5]});
}
}
loaded = true;
}
main.selectRoundDropPanel.tblSelectRoundDrop.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
int row = 0;
row = main.selectRoundDropPanel.tblSelectRoundDrop.getSelectedRow();
for (int index = 0; index < roundDropsData.length; index++) {
if (roundDropsData[index][3].equals(
main.selectRoundDropPanel.tblSelectRoundDrop.getModel().getValueAt(row, 0))) {
main.roundDetailsPanel.txtRoundDetailsAddress.setText(roundDropsData[index][6] + "\n"
+ roundDropsData[index][7] + ", " + roundDropsData[index][8] + "\n" +
roundDropsData[index][9]);
main.roundDetailsPanel.lblRoundDetailsName.setText(roundDropsData[index][2]);
main.roundDetailsPanel.txtRoundDetailsInstuct.setText(roundDropsData[index][10]);
main.roundDetailsPanel.txtDropDetailsIn.setText(roundDropsData[index][4]);
main.roundDetailsPanel.txtDropDetailsOut.setText(roundDropsData[index][5]);
main.roundDetailsPanel.txtRoundDetailsInstruct.setText(roundDropsData[index][12]);
break;
}
}
Globals.CURRENT_COMPONENT = "selectRoundDropPanel";
showRoundDetailsPanel();
}
});
}
Try changing the listener for JComboBox. try using stateChangeListener.

Resources