Recommended improved match-finding algorithm for Bejeweled game? - c++

I'm trying to determine a sensible method of finding matches of 3, 4, or 5, for each rows and column. The player looks for areas (rows or columns) in the game board where the same "gem" will, after swapping two adjacent pieces (one swap each turn), repeat for 3-5 consecutive spots.
Here's an example scenario of a match-making move:
Board before player move (bolded is necessary swap):
A C B B C
D D B A D
D A A C C
A D B B A
D C D A A
Board after player move (bolded is resulting match):
A C B B C
D D B A D
D A A C C
D A B B A
D C D A A
In this example, there is a 4-match of "D" in the first column, after the first row. I'm trying to figure out how to find such matches after 1.) the board is created at the start of the game and the board randomizes a number of times to eliminate immediate matches, and 2.) after the player makes a move. If working correctly, the program will be able to detect a match after the correct swap is made by the program itself or the player.
Every algorithm I've attempted have caused the looping to go out of bounds and/or improperly find all resulting matches after a swap. By this, I mean that the program would sometimes try to search outside the array because I'm unsuccessfully telling the program how to "adjust" its array-searching based on where the current spot is. Even when it does not cause runtime errors, it still shows improper results. For instance, the player will see that the board has at least one complete match shown, which isn't good.
Here are explanations for two procedures I've attempted:
Following spaces. From the current spot, check ahead four spaces across in same row (or less if there's less than four spaces remaining in the row). First check for a match of five, including the current spot; if none, check for four (minus a spot); if none, check for three (minus a spot); if none, no match found. Repeat the same check for the below column.
Preceding spaces. From the current spot, check back four spaces across in same row (or less if there's less than four spaces in between the first spot in the row and the current spot). First check for a match of five, including the current spot; if none, check for four (minus a spot); if none, check for three (minus a spot); if none, no match found. Repeat the same check for the above column.
Here's the primary function where such working algorithm is needed. The use of my Gem class here (which is currectly broken) may not be important to the request, so I won't add it unless it's helpful.
bool Board::findMatches(bool scoringMove) // false if board is being setup before game
{
bool matchesFound = false;
// loops through entire board, where "size" is the width, not the number of spots
for (int i = 0; i < size.getSize()*size.getSize(); i++)
{
// loops for each type of Gem, six total (_not identical to given example_)
for (int k = 0; k < gems.getNumGems(); k++)
{
Gem traverseGems(k); // next Gem (in sequence)
char nextGem = traverseGems.getGem(); // next Gem set to a char
// ROWS check
// default match search for 3-match
if ((i < (size.getSize()*size.getSize())-4)
&& (board[i]->getGem() == nextGem)
&& (board[i+1]->getGem() == nextGem)
&& (board[i+2]->getGem() == nextGem))
{
// if the player is making a move
if (!scoringMove)
return true;
matchesFound = true;
// just adds points to score; irrelevant to algorithm
scoreMatches(3, 'R', i, 3);
// no 4-match, but a 3-match
if (board[i+3]->getGem() != nextGem)
scoreMatches(3, 'R', i, 3);
else
scoreMatches(4, 'R', i, 4);
// 5-match found
if (board[i+3]->getGem() == nextGem && board[i+4]->getGem() == nextGem)
scoreMatches(5, 'R', i, 5);
}
// COLUMNS check (comments for rows check apply here as well)
if ((i <= (size.getSize()-1))
&& (board[i]->getGem() == nextGem)
&& (board[i+size.getSize()]->getGem() == nextGem)
&& (board[i+(size.getSize()*2)]->getGem() == nextGem))
{
if (!scoringMove)
return true;
matchesFound = true;
scoreMatches(3, 'C', i, 3);
if (board[i+(size*3)]->getGem() != nextGem)
scoreMatches(3, 'C', i, 3);
else
scoreMatches(4, 'C', i, 4);
if (board[i+(size*3)]->getGem() == nextGem && board[i+(size*4)]->getGem() == nextGem)
scoreMatches(5, 'C', i, 5);
}
}
}
return matchesFound;
}
Board.h
#ifndef BOARD_H
#define BOARD_H
#include "Size.h"
#include "Score.h"
#include "Move.h"
#include "Gem.h"
#include <iostream>
#include <iomanip>
#include <ctime>
class Board
{
private:
Size size;
Score score;
Gem **board;
bool moreSwaps;
void swapGems(Move);
void swapGems(int, int);
void setNewRandGem(int);
void findMoreSwaps();
void scoreMatches(int, char, int, int);
bool findMatches(bool);
public:
Board();
Board(Size, Score&);
~Board();
void displayBoard() const;
bool isMatch(Move);
bool moreMovesFound() const;
};
#endif
Board Constructor
Board::Board(Size size, Score &score)
{
srand((unsigned int)time(NULL)); // I can always move this to main()
this->size = size;
this->score = score;
board = new Gem *[size.getSize()*size.getSize()];
for (int i = 0; i < size.getSize()*size.getSize(); i++)
board[i] = new Gem;
//This is the "pre-game" block.
//As long as the program finds a new match after performing its
//own swaps, it'll randomize the entire board and start over again.
//This is incredibly unefficient, but I will try to fix it later.
do
{
for (int i = 0; i < size.getSize()*size.getSize(); i++)
setNewRandGem(i);
} while (findMatches(false));
}

Having reread the updated question, I think your goal is to test whether, for a given 5x5 board, there is any possible swap of two adjacent symbols that will produce a board with 3 or more identical symbols in a row or column.
If the previous attempts produced out-of-bounds errors, that would imply a bug in the implementation, not a bug in the algorithm. So using a different algorithm would do nothing to solve that problem, you still need to implement proper array boundary checks. There is no way around that, but on the plus side it is not particularly hard. Simply check each index on whether it is smaller than zero or larger than the array dimension size, before accessing the array. If it is, trace back the steps your program used to get to that value, and find the bug that must be there.
Of course, if the program produces the wrong results in addition to out-of-bounds errors, then your algorithm might also be wrong.
Having said that, I am still not sure I understand the algorithms you describe, but they seem too complex for this problem. Unless you need to evaluate thousands of boards per second, a simple brute force algorithm will suffice. Just try out all possible swaps, and for each swap check if the board contains 3 or more identical symbols in a row or column.
Here is a description in pseudocode:
function is_there_a_valid_move(board)
// returns true if there is a valid bejewelled move
// test all horizontal swaps
for (x = 0; x++; x< board-width - 1):
for (y = 0; y++; y < board-height):
make a copy of the board: board2
swap board2[x,y] and board2[x+1,y]
check_matches(board2, 3)
if match found: return true
// test all vertical swaps
for (x = 0; x++; x< board-width):
for (y = 0; y++; y < board-height - 1):
make a copy of the board: board2
swap board2[x,y] and board2[x,y+1]
check_matches(board2, 3)
if match found: return true
return false
function check_matches(board, num_matches)
// returns true if there are num_matches or more of the same symbol in a row or column
// check rows
for (y = 0; y++; y < board-height):
consecutive_symbols = 0
for (x = 0; x++; x< board-width - 1):
if board[x,y] == board[x+1,y]: consecutive_symbols++
else: consecutive_symbols = 0
if consecutive_symbols >=num_matches: return true
// check columns
for (x = 0; x++; x< board-width):
consecutive_symbols = 0
for (y = 0; y++; y < board-height - 1):
if board[x,y] == board[x,y+1]: consecutive_symbols++
else: consecutive_symbols = 0
if consecutive_symbols >=num_matches: return true
return false
This is certainly not the fastest method, but for a 5x5 board everything else is overkill.

Related

C++ moving characters from one vector to another

I'm new to C++. I am trying to create a program that reads a file named symbols.txt, fill a vector with the symbols, then take chars that are in the range [d;p] and move them to the second vector while erasing them from the first vector.
int main(){
vector<char> sym1;
vector<char> sym2;
int p = 100, d = 80;
char x;
ifstream symbols("symbols.txt");
while (symbols >> x )
{
sym1.push_back(x);
}
for(int i = 0; i < sym1.size(); i++){
if (sym1[i] < p && sym1[i] > d){
sym2.push_back(sym1[i]);
sym1.erase(sym1.begin()+i);
}
}
}
When I do this, the program works if there are no characters the same, otherwise it only moves half of the characters and leaves the other half untouched.
In your implementation, the first thing you need to notice is that in your for loop, sym1.size() changes if you call sym1.erase(). Second, since your variable i increments every time, you skip some elements in the vector.
For example, the element at index 5 is erased, then the element at index 6 will move down to replace it. In the mean time, your loops does i++, so you skip the element that moved to index 5.
I think you should use iterators with C++ containers, below is an example:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<char> sym1;
vector<char> sym2;
int p = 100, d = 80;
char x;
// ifstream symbols("symbols.txt");
// while (symbols >> x)
// {
// sym1.push_back(x);
// }
for(int i = 0; i < 200; i++) {
sym1.push_back(i);
}
int size = sym1.size();
for(vector<char>::iterator it = sym1.begin(); it != sym1.end(); ){
if (*it < p && *it > d){
sym2.push_back(*it);
it = sym1.erase(it);
}
else
it++;
}
for(vector<char>::iterator it = sym2.begin(); it != sym2.end(); it++) {
cout << (int)*it << " ";
}
}
std::vector is good for a lot of things. However, it's terribly inefficient when it comes to insertion or erasing at any other position than the end.
When an element is inserted somewhere (not at end), then the following happens:
The internally managed size is increased by 1. (This may cause a re-allocation of the internal buffer.)
The last element is moved to next position, the second last element is moved to the now "free" position, and so on until the element at insertion index is moved.
Similar happens when an element is erased:
The successor of the element to erase is moved to its previous position, the next is moved to its previous position, and so on until the last element is moved.
Finally, the internally managed size is decreased by 1. (No re-allocation. – The buffer is kept as reserved.)
In OPs case, it's the repeated erasing which makes me concerns. And, when I had this problem in production I used a way to reduce all the moves to the absolutely minimal required.
For this, I use two indices:
one to read and check the characters
one to write the characters which have to be kept in the vector (sym1 in OPs sample).
While the read index is simply incremented for each loop iteration (as usual) the write index is incremented only after an element has been moved (because it should be kept).
As long as nothing is erased, both indices will have identical values. In this case, it's a bit annoying that elements are moved to the position where they already are. However, I consider this as the lesser evil. (Checking whether indices are still identical will probably buy nothing if the move is simple enough.) As soon as something is erased the write index starts to lag behind the read index.
So finally, for a vector of length N there are exactly N write operations to perform (and this for granted). This sounds reliable and not too terrible.
(Erasing elements individually one by one could be in worst case result in
N - 1 + N - 2 + … + 1 moves of elements which are roughly N * (N - 1) / 2 or (N² - N) / 2.)
For the demonstration, the modified sample of OP:
#include <fstream>
#include <iostream>
#include <vector>
int main()
{
std::vector<char> sym1, sym2;
const char p = 'z', d = 'a';
// read sample data
std::ifstream symbols("symbols.txt");
for (char x; symbols >> x;) sym1.push_back(x);
// move all characters in [d, p] to sym2
size_t iWrite = 0;
for (size_t iRead = 0, n = sym1.size(); iRead < n; ++iRead) {
const char c = sym1[iRead];
if (c >= d && c <= p) sym2.push_back(c);
else sym1[iWrite++] = sym1[iRead];
}
// The difference between iWrite - iRead is the number of obsolete elements.
// (It must be equal to sym2.size().)
sym1.resize(iWrite);
// could've been altermatively: sym1.erase(sym1.begin() + iWrite, sym1.end());
// show results:
std::cout << "sym1: '";
for (const char c : sym1) std::cout << c;
std::cout << "'\nsym2: '";
for (const char c : sym2) std::cout << c;
std::cout << "'\n";
}
Input:
I used the above source code as input (as the OP didn't expose the symbols.txt file).
Output:
sym1: '#<>#<>#<>(){::<>1,2;='',='';//::(".");(;>>;)1._();//[,]2_W=0;(_R=0,=1.();R<;++R){=1[R];(>=&&<=)2._();1[W++]=1[R];}//TW-R.//(I2.().)1.(1.()+W,1.());//:::<<"1:'";(:1)::<<;::<<"'\2:'";(:2)::<<;::<<"'\";}'
sym2: 'includefstreamincludeiostreamincludevectorintmainstdvectorcharsymsymconstcharpadzreadsampledatastdifstreamsymbolssymbolstxtforcharxsymbolsxsympushbackxmoveallcharactersindptosymsizetiriteforsizetieadnsymsizeieadnieadconstcharcsymieadifcpcdsympushbackcelsesymiritesymieadhedifferencebetweeniriteieadisthenumberofobsoleteelementstmustbeequaltosymsizesymerasesymbeginiritesymendshowresultsstdcoutsymforconstcharcsymstdcoutcstdcoutnsymforconstcharcsymstdcoutcstdcoutn'
Live Demo on coliru
So, for the range ['a', 'z'], (I used in my demo for better illustration) sym2 ends up containing all lower case characters while sym1 keeps everything else (except the white spaces).
Concerning the missing white spaces I wondered a bit until I realized that the white spaces are filtered out by the read loop:
for (char x; symbols >> x;) sym1.push_back(x);
which used formatted input.
This could be changed using symbols.get(x) instead of symbols >> x but the filtering of white space might be even intended.
Nitpicking:
OP described the range [d;p] (for the characters to move) as requirement.
AFAIK, it's usual that square brackets (or angle brackets) describe ranges with closed ends (i.e. with inclusive border values) while for open ends (exclusive border values) round brackets are used.
Thus, either the requirement has to be (d;p)
or the implementation of the range check
if (sym1[i] < p && sym1[i] > d){ // check for range (d;p)
is not according to the requirement but should be
if (sym1[i] <= p && sym1[i] >= d){ // check for range [d;p]

Why is my output freezing when it gets to this section of the code?

I'm trying to compare two decks of cards, yet every time I try another method of doing it, I get the same result... Everything before the code outputs, and it just freezes as soon as it hits the comparison code, as if it's stuck in an infinite loop.
I've tried for loops, static variables, do-while loops, etc. This is my first time leaving the loop at the client code.
The code that supposedly throws the program into an infinite loop.
while (repeatLoop == false)
{
deck1.shuffleDeck();
counter++;
repeatLoop = deck1.compareDecks();
}
compareDecks function.
bool deck::compareDecks()
{
int deckCount = 0;
suitType tempOriginalSuit;
suitType tempShuffleSuit;
rankType tempOriginalRank;
rankType tempShuffleRank;
while (index < 52)
{
tempOriginalSuit = originalCardDeck[index].getSuit();
tempShuffleSuit = shuffledCardDeck[index].getSuit();
if (int(tempOriginalSuit) == int(tempShuffleSuit))
{
tempOriginalRank = originalCardDeck[index].getRank();
tempShuffleRank = shuffledCardDeck[index].getRank();
if (int(tempOriginalRank) == int(tempShuffleRank))
{
deckCount++;
if (deckCount == 52)
return true;
}
}
else
{
return false;
index++;
}
}
}
The shuffleDeck function
(This function pushes back the first card from the first half of the deck and the first card from the second half of the deck towards the end until all 52 cards have been pushed in this pattern. This makes the deck have 52 x 2 cards (with the second half of the deck being the perfect shuffle), so I delete the first half of the cards using .erase as it is not needed)
void deck::shuffleDeck()
{
for (int a = 0, b = 2; a < 2 && b < 4; a++, b++)
{
for (int i = 2; i < 15; i++)
{
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(a),
static_cast<cardSpace::rankType>(i) });
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(b),
static_cast<cardSpace::rankType>(i) });
}
}
shuffledCardDeck.erase(shuffledCardDeck.begin(),
shuffledCardDeck.begin() + (shuffledCardDeck.size() / 2));
}
The two decks initialized by this constructor.
deck::deck()
{
for (int i = 0; i < 4; i++)
{
for (int j = 2; j < 15; j++)
{
originalCardDeck.push_back(card{ static_cast<cardSpace::suitType>(i),
static_cast<cardSpace::rankType>(j) });
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(i),
static_cast<cardSpace::rankType>(j) });
}
}
}
Also note that I've done a perfect shuffle on the shuffledCardDeck vector in another function. I'm trying to repeat the perfectShuffle function until it reaches it's original state and output how many times it took to do this.
I get an infinite loop.
EDIT: I've decided to add the return false; statement in the compareDecks function into the if-else. Also, I think what's causing the problem is that my index i is reset to zero everytime it is called again. Are there any solutions you guys could propose to this? I've tried using static variables, but they just would not increment in the for loop.
EDIT 2: I enclosed my if statements within the curly braces, per users' request, as it's a flaw in my code.
EDIT 3: After commenting out
deck1.shuffleDeck()
The compareDecks function returned true, stating that the decks are equal, which isn't supposed to happen... This caused the loop to end after only one loop.
I was expecting you to actually shuffle the deck.
Your code was pushing a specific, newly synthesized card onto the end of the deck:
shuffledCardDeck.push_back(card{ static_cast<cardSpace::suitType>(a),
static_cast<cardSpace::rankType>(i) });
For example, the first card it will push is always the 2 of 0's (Whatever the 0th suit is). That's not what you want. You actually want to push a copy of the card that is at a specific position index in the deck. For example, loop index from 0 to 25 and then push shuffledCardDeck[index] and shuffledCardDeck[26 + index].
Then you can still wrap up by using your technique of erasing the first half of the deck.
void deck::shuffleDeck()
{
for (int index = 0; index < 26; ++index) {
shuffledCardDeck.push_back(shuffledCardDeck[index]);
shuffledCardDeck.push_back(shuffledCardDeck[26 + index]);
}
shuffledCardDeck.erase(shuffledCardDeck.begin(),
shuffledCardDeck.begin() + 52);
}
You are not modifying the value in the loop, you're using a double equals sign:
repeatLoop == deck1.compareDecks();
That would explain your observed behavior.

check if one string is interleaved by two other strings

I am debugging the following problem. Post detailed problem statement and the coding. My question is whether the last else if (else if (A[i-1]==C[i+j-1] && B[j-1]==C[i+j-1])) is necessary? I think it is not necessary since it is always covered either by else if(A[i-1]==C[i+j-1] && B[j-1]!=C[i+j-1]), or covered by else if (A[i-1]!=C[i+j-1] && B[j-1]==C[i+j-1]), i.e. previous two if-else check conditions. Thanks.
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc",
s2 = "dbbca",
When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
// The main function that returns true if C is
// an interleaving of A and B, otherwise false.
bool isInterleaved(char* A, char* B, char* C)
{
// Find lengths of the two strings
int M = strlen(A), N = strlen(B);
// Let us create a 2D table to store solutions of
// subproblems. C[i][j] will be true if C[0..i+j-1]
// is an interleaving of A[0..i-1] and B[0..j-1].
bool IL[M+1][N+1];
memset(IL, 0, sizeof(IL)); // Initialize all values as false.
// C can be an interleaving of A and B only of sum
// of lengths of A & B is equal to length of C.
if ((M+N) != strlen(C))
return false;
// Process all characters of A and B
for (int i=0; i<=M; ++i)
{
for (int j=0; j<=N; ++j)
{
// two empty strings have an empty string
// as interleaving
if (i==0 && j==0)
IL[i][j] = true;
// A is empty
else if (i==0 && B[j-1]==C[j-1])
IL[i][j] = IL[i][j-1];
// B is empty
else if (j==0 && A[i-1]==C[i-1])
IL[i][j] = IL[i-1][j];
// Current character of C matches with current character of A,
// but doesn't match with current character of B
else if(A[i-1]==C[i+j-1] && B[j-1]!=C[i+j-1])
IL[i][j] = IL[i-1][j];
// Current character of C matches with current character of B,
// but doesn't match with current character of A
else if (A[i-1]!=C[i+j-1] && B[j-1]==C[i+j-1])
IL[i][j] = IL[i][j-1];
// Current character of C matches with that of both A and B
else if (A[i-1]==C[i+j-1] && B[j-1]==C[i+j-1])
IL[i][j]=(IL[i-1][j] || IL[i][j-1]) ;
}
}
return IL[M][N];
}
thanks in advance,
Lin
You do need the final else if to catch the cases when the next character in C matches the next character in both A and B. For example, run your program with A="aaaa", B="aaaa", and C="aaaaaaaa" and see if you enter that last else if block.
Additionally, you also need a final else block to handle cases when none of the previous conditions match. In this case, you need to set IL[i][j] to false. Otherwise, the function will incorrectly return true.
Edit: Even though the code uses memset to initialize all elements of IL to 0, it may not work because ISO C++ does not support variable length arrays (VLAs). In fact, this is what happened when I tried the code at cpp.sh. It uses g++-4.9.2 with flags that causes it to report sizeof(IL) to be 1 even though g++ is supposed to support VLAs. Maybe this is a compiler bug or maybe it does not support multidimensional VLAs. In any case, it might be safer to not use them at all.

Determine the current output to the speaker C++ Beginner

Recently, I've began learning C++ in college and was asked to make a looping sequence of "*" with the sequence going like this:
*
***
*****
*******
*********
*********
*******
*****
***
*
[continues indefinitely until it goes x lines, where x is specified at the start]
How I did it if you need a visualisation:
#include<iostream>
#include<windows.h>
using namespace std;
int main() {
int hFar=0; //Variable that will be used to find out how many parts into the sequence the user would like to travel.
unsigned long int fibSequenceA = 0; //Unsigned doesn't overflow as easilly. This is the first value of the fibunacci sequence, it's defined as 0 to start.
unsigned long int fibSequenceB = 1; // Second Value of fibbunacci sequence. Defined at 1 to start.
int sPart = 1;//Used for the * sequence, it is the part of the sequence that the loop is on. It changes dynamically by either +2 or -2 every loop.
int cValue = 0;// also for the * sequence, it is the current number of * typed.
int sDirection = 0; // used to change from subtracting 2, and adding 2.
int redo = 1; // used to ensure that every 9 and every 1 the sequence repeats that number a second time. Starts at one because the sequence starts with only 1 single * rather then 2 *.
cout << "How far into the second sequence would you like to travel?" << endl; //Requests how far into the * sequence you'd like to go.
cin >> hFar; //inputs answer into variable.
for(int i = 0; i < hFar; i++ ) {//begins for statement. Notice there's no hfar/2. There will only be 1 output per line now.
while(cValue < sPart) { //Basic while loop to input the ammount of * on the current line. Works by adding a * depending on what part of the sequence it is.
cout << "*"; //self explainitory.
cValue++; //raises the cValue in order to keep track of the current number of *. Also prevents infinite loop.
}
if(sPart == 9 && redo == 0) { //Checks if the sequence part is 9, meaning that the value begins to reduce to 1 again. But first, it must repeat 9 to keep with the sequence.
sDirection = 3; //sets the direction to 3 to make sure that the value of sPart stays at 9, instead of reducing by 2.
redo = 1; //resets the redo.
cValue = 8; //changes the value of the current number of 8. Not sure if this is important, It gets done again later to make sure anyway.
sPart = 9; //Changes the sPart to 9, the needed number of *. Also redone later, but to make sure, I kept this here.
}
else if(sPart == 9 && redo == 1) { // if the sequence has already redone the 9th *
sDirection = 1; //sets the direction to 1; The sequence will reverse.
redo = 0; //returns redo to 0 to ensure that next time it reaches 1, it repeats the 1 * again.
}
else if(sPart == 1 && redo == 0) { //when the value reaches one for the second time, it needs to repeat that value.
sDirection = 3; //sets the direction to 3 again to stop the change.
redo = 1; //resets the redo.
cValue = 0;//also might be redundant.
}
else if(sPart == 1 && redo == 1) { // stops the duplicate number of *
sDirection = 0; //sets the direction to +2 again.
redo = 0;//resets the redo.
}
Sleep(50);
cout << endl; //adds a new line. This ensures that we get a new line after every part rather then 900 * on one line.
if(sDirection == 0) { //if the direction is positive.
sPart += 2; //adds 2 to the spart to keep with the sequence.
cValue = 0; //resets the cValue to 0 so the while statement works again.
}
else if(sDirection == 1) { //if the direction is negative
sPart -=2; //subtracts 2 from the spart to keep with the sequence.
cValue = 0; //resets the cValue to keep the while statement working.
}
else if(sDirection = 3) { //if the change is
//Could have been done differently. Could have just set the values to themselves, but it wasn't working. not sure why.
if(sPart == 9){ //if the spart is currently 9.
sPart = 9; //keeps it at 9.
cValue = 0; //resets the cValue.
}
else if(sPart == 1){ //if the spart is currently 1
sPart = 1; //keeps it at one.
cValue = 0; //resets the cValue.
}
}
}
return 1;//ends the code.
}
[Sorry about all the comments, I'm trying to make sure I understand what I'm doing, like I said, I'm learning :)]
While fooling around with the loops, I ended up putting the Sleep() function in, so that it produced a wave effect when generating the sequence. This got me thinking, and I wanted to know if it would be possible to make the command prompt act like a makeshift volume visualizer. (The more "*" the higher the volume at that point in time).
So, when playing a song on my computer, the program would find the total output to the speaker, and put a number of "*" that correlate to that volume, and would continue this until the program ends, producing (hopefully) an interesting effect. (if you're confused, play a song on your computer, right click on the speaker icon on the task bar, and click open volume mixer, and look at the volume levels change, this is the type of effect that I'm looking for)
Would this be possible? I've been googling the issue, (found things like This and I've found a number of ways to find out the current MASTER volume, and change that, But I'm looking for more of the actual volume that one hears, not the maximum volume that my speakers can output.
Here's somewhat of what I'm looking to do.
int sPart = x; //x = the current output of the speaker
int cValue = 0 //the current number of "*" output
while([somecondition I'm not sure when i want the sequence to stop yet]) {
while(cValue < sPart) {
cout << "*";
cValue++;
}
cout << endl; //ends the current line, making room for the next value of the volume.
Sleep(50); //waits 50ms before finding the next volume value.
sPart = [current speaker value]; //finds the value of the speaker again.
cValue = 0; //resetting the number of "*" back to zero.
}
//I just reused the variables from my original code.
Would this be possible? If so, would a beginner be capable of this? Again, If so, how would it be done?

C++ Can someone explain what these for loops are saying?

So this code is the base outline for a boggle game from online that I copied over.
SOURCE: http://www.codingfriends.com/index.php/2010/06/10/boggle/
bool findUsersWord(string findThis, Grid<char> &theBoard, Vector<cell> &theRoute, string alreadyFound, int placeY, int placeX)
{
// need to find the findThis base case
if (findThis == alreadyFound)
return true;
// need to find the first letter within the board and then progress around that.
if (alreadyFound.empty())
{
for (int rows = 0; rows < theBoard.numRows(); rows++)
for (int cols = 0; cols < theBoard.numCols(); cols++)
// find the each character within the
if (theBoard[rows][cols] == findThis[0])
{
alreadyFound = findThis[0];
cell newR;
newR.row = rows;
newR.col = cols;
theRoute.add(newR);
if (findUsersWord(findThis, theBoard, theRoute, alreadyFound, rows, cols))
return true;
else
// clear out the found Board
theRoute.clear();
}
}
else
{
// try and find the next letters within the area around the base letter
// spin around the letter 3 * 3 grid
for (int y= (placeY > 0 ? placeY-1: placeY); y <=(placeY == (theBoard.numRows()-1) ? placeY : placeY+1);y++)
for (int x=(placeX > 0 ? placeX-1: placeX); x<=(placeX == (theBoard.numCols()-1) ? placeX : placeX+1); x++)
if ((theBoard[y][x] == findThis[alreadyFound.length()]) && (!(y==placeY && x ==placeX)))
// already used letter
if (!placeAlreadyUsed(y,x,theRoute))
{
alreadyFound += findThis[alreadyFound.length()];
cell newR;
newR.row = y;
newR.col = x;
theRoute.add(newR);
if (findUsersWord(findThis, theBoard,theRoute, alreadyFound, y, x))
return true;
else
{
if (alreadyFound.length() > 1)
alreadyFound = alreadyFound.substr(0, alreadyFound.length()-1);
theRoute.removeAt(theRoute.size()-1);
}
}
return false;
}
return false;
}
The code below is the code in question which is part of the code above.
for (int y= (placeY > 0 ? placeY-1: placeY); y <=(placeY == (theBoard.numRows()-1) ? placeY : placeY+1);y++)
for (int x=(placeX > 0 ? placeX-1: placeX); x<=(placeX == (theBoard.numCols()-1) ? placeX : placeX+1)
I am wondering if someone could turn this code into more simple code that doesn't involve the using of ? and that. I do know the simple parts of it such as the "?" means return and ":" means next line, but I am lost in the fact that it is being used in a for loop and the fact that it would just look like
if(placeY > 0)
return playceY-1
placeY;
Where have I gone wrong?
The ? : block is just a strange looking if statement. It's an inline if, if you will.
Here's the format
argument ? result evaluated to if true : result evaluated to if false
Here's an example
1<2 ? "Hurray" : "boo"
Will evaluate to "Hurray" because 1<2 is true. However, if we switch it to 1>2 it will evaluate to "boo".
I do know the simple parts of it such as the "?" means return and ":" means next line
Um, no. That's not what it means at all. ?: is one operator with three operand expressions, one of which appears between the ? and the :.
placeY > 0 ? placeY-1 : placeY
is an expression that means: "If placeY > 0 then evaluate placeY-1; otherwise evaluate placeY".
The idea of the code is that we want, for some reason, to iterate over all positions of the board that are next to (placeX,placeY). Those positions form a rectangle, and the ?: operators are used to compute the left, right, top and bottom limits of that rectangle. For example the expression quoted above is for the top coordinate. It is usually placeY-1, except that if placeY is already 0, there is no row on the board above it, and in that case placeY itself is the top row.