Is there efficient way to deal cards other then this if statement? - c

I want to deal 52 cards numbered from 1 to 52. To share it into 4 groups of 13 cards and to separate them, I put "-" in the code below to make them appear nice. The other group starts with card numbers 14,27 and 40. I could not find a better way then 2 OR's in if statement.
What I want to ask is if there is an easier way than this.(if (cardNo==14 || cardNo==27 || cardNo==40)
while (cardNo<53)
{
...
if (cardNo==14 || cardNo==27 || cardNo==40)
{
printf("------------\n");
}
printf("%-6s of %-6s\n ", face[column], suit[row]);
cardNo++;
}

Use the modulo operator:
if ((cardNo - 1) % 13 == 0)

Related

Ruby Array Elements

I am trying to create password Generate in ruby. At the moment all is working just got stuck at the final piece of generating the password.
I asked user if he/she would like the password to include numbers, lowercase or uppercase.
If YES, user will enter 1 and 0 for NO.
I used the code below to generate password if everything is 1. Meaning user want to include numbers, lowercase and uppercase.
if numbers == 1 && lowercase == 1 && uppercase == 1
passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10)
end
p passGen
This works 90% of the time. 10% of the time the generated password will not include say any numbers. But everything else present. I am not sure if this is because of the size or length of Array from which the password is sampled.
Anyway lets go to the main problem below
Here is the problem, I am struggling to write the code to generate password if one or more of input is 0. That's if user don't want to include numbers. Or no numbers and uppercase etc . As I can't predict what user may want or not want. I need help on this please.
Thank you.
You will need to make your input array more dynamic:
passGen = []
passGen += (0..9).to_a if numbers == 1
passGen += ('A'..'Z').to_a if uppercase == 1
passGen += ('a'..'z').to_a if lowercase == 1
passGen.sample(10).join
Now, to tackle your other issue with missing characters - this is caused as you are simply taking 10 random characters from an array. So it can just take, for example, all digits.
To tackle this you need to get one character from each generator first and then generate the remaining characters randomly and shuffle the result:
def generators(numbers:, lowercase:, uppercase:)
[
(0..9 if numbers),
('A'..'Z' if uppercase),
('a'..'z' if lowercase)
].compact.map(&:to_a)
end
def generate_password(generators:, length:, min_per_generator: 1)
chars = generators.flat_map {|g| Array.new(min_per_generator) { g.sample }}
chars += Array.new(length - chars.length) { generators.sample.sample }
chars.shuffle.join
end
gens = generators(numbers: numbers == 1, uppercase == 1, lowercase: lowercase == 1)
Array.new(10) { generate_password(generators: gens, length: 10) }
The code doesn't know it needs to include a digit/letter from every group. The sample takes random signs and since you a basically sampling 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz there is a possibility that all the signs will not be digits.
The easiest way to fix it is to check if a sign from every group is in the "password" and then replace a random sign with a sign from group that is not present.
If I were to program this I would do it like that
def random_from_range(range)
range.to_a.sample.to_s
end
def passGen(numbers, lowercase, uppercase)
result = ''
possibleSigns = []
if numbers == 1
range = (0..9)
result += random_from_range(range)
possibleSigns += range.to_a
end
if lowercase == 1
range = ('A'..'Z')
result += random_from_range(range)
possibleSigns += range.to_a
end
if uppercase == 1
range = ('a'..'z')
result += random_from_range(range)
possibleSigns += range.to_a
end
desired_lenth = 10
while result.length < desired_lenth
result += possibleSigns.sample.to_s
end
result
end
puts passGen(1,1,1)
By saying (0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a, you're creating an Array of 10 + 26 + 26 = 62 elements, and then you pick only 10 elements out of it.
At your place I'd wrap password generation around an until block:
def generate_password_with_digits_and_caps
[(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10).join
end
passGen = ''
until passGen.match(/[A-Z]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
passGen = generate_password_with_digits_and_caps
end
This could also work (closer to your snipppet):
if numbers == 1 && lowercase == 1 && uppercase == 1
passGen = ''
until passGen.match(/[A-Z]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10).join
end
end
Start with something simple and stupid:
passGen = (('0'..'9').to_a.sample(1)+ ('A'..'Z').to_a.sample(1)+('a'..'z').to_a.sample(8).shuffle).join
Technically speaking, this already fulfills your requirement. From the viewpoint of aesthetics and security, the disadvantage here is that the number of upper case characters is always 8. A more elegant solution would be to find three non-zero integers which add up to 10, and can be used as the arguments for the sample call. Also, if no numbers are requested, you simply pass 0 as argument to sample.
Since this exceeds the scope of your question, and I don't even know whether you want to go so far, I don't elaborate on this here further.

Why is my code returning all records when I am trying to subset inside for loop - R?

for (i in 1:length(data$name)){
if (!is.na(data$years[i]) >= 34 & !is.na(data$gender[i]) == "male" & !is.na(data$classification[i]) == "mid"){
print(data$name)
}
}
There's a few problems in your code. I am assuming this is a class exercise or similar, so I'll add a bit extra detail to illustrate where you've missed a step.
First of all you loop works fine, but your if condition is not completely correct.
!is.na(data$years[i]) >= 34
All of your conditions look (somewhat) like this. The idea is obvious, you want to "check that data$years[i] is not null, and above 34". But in R (and most languages) you have to check these seperately.
!is.na(data$years[i]) && data$years[i] >= 34
Similar for the rest of your conditions.
Next your print statement is printing out everything, because this is what you're asking it to:
print(data$name)
is "ignorant" of anything else you've done up till now. It seems you want to print the specific record, eg:
print(data$name[i])
And this is the way to go about it.
Now R has a thing called "vectorization", so we could wrap this entire loop up in one go:
data$name[!is.na(data$years) & !is.na(data$gender) & !is.na(data$classification) & data$year > 34 & data$gender == "male" & data$classification == "mid"]
But I am assuming that is not part of your current exercise. Note the slight (but important) difference that for vectorized (eg. more than 1) condition I use single & but for single conditions I use 2 &&. The latter is optimized to be "lazy" for single inputs (thus faster).
Perhaps you can try subset + complete.cases like below
subset(
data,
years >= 34 & gender == "male" & classification == "mid" & complete.cases(data[c("years", "gender", "classification")])
)$name

How to keep a value from resetting in a loop?

I have been trying to set up a health system for my school project but the value keeps resetting regardless of the fact that monster_health is outside of the loop, my friends and I can't seem to fix this.
Code:
monster_health = 100
while monster_health > 0:
playeraction = input('Placeholder beast wants to fight you!!\n1) Basic Attack')
print(monster_health)
if playeraction == 1:
monster_health = monster_health-7
continue
if monster_health <= 0:
print('You killed the monster!! Gain nothing, this is a test you barbarian')
break
Output:
Placeholder beast wants to fight you!!
1) Basic Attack
100 #should print 97 but fails to
replace
if playeraction == 1:
with
if playeraction == "1":
or:
if int(playeraction) == 1:
Because your input is string format and not an integer and 1 != "1".
From your code, you are printing the monster health before updating it, so it will be "100" (the initial value) the first time.
while monster_health > 0:
playeraction = input('Placeholder beast wants to fight you!!\n1) Basic Attack')
print(monster_health) # at this time, it is still 100

Threads synchronization in C

I'm trying to make a project as follows:
I'll have 10 threads, each controlling a column of 10 rectangular box.(10 columns of 10 boxes each) And at every 3s or so, I need 2 of them to change colour(i.e. red), such that at any point of time, there should be 2 red columns of 10 red boxes out of 10.
The current code I have for the column of boxes:
void* thread_func_1() {
while (1) {
if (randomNo1 == 1 || randomNo2 == 1) {
sema_wait(&sem) ;
drawRedBoxes();
sleep(3000);
drawBlueBoxes();
sema_post(&sem);
randomize(); // random 2 more numbers
}else{
drawBlueBoxes();
}
}
void randomize(){
do{
randomNo1 = 1 + rand()/ (RAND_MAX/(10) + 1);
randomNo2 = 1 + rand()/ (RAND_MAX/(10) + 1);
} while (randomNo1 == randomNo2);
}
Edit: All the 10 threads are of similar code. The drawBoxes function draws the 10 rectangular boxes in the column.
Not the exact code but it is something like this. Ideally I would want the 2 new red columns to appear together(or at least a very very short time delay between them), but I realised after awhile, it is really obvious that 1 red colum appear some time after another. How can I solve this problem?

Limit list length in redis

I'm using redis lists and pushing to new items to a list. The problem is I really only need the most recent 10 items in a list.
I'm using lpush to add items to a list and lrange to get the most recent 10.
Is there anyway to drop items after a certain number? I'll end up with lists that may have 1,000's of items and can cause performance issues with latency.
Thank you!
After every lpush, call ltrim to trim the list to 10 elements
See http://redis.io/commands/ltrim
You can use LTRIM intermittently after any LPUSH, no need to call LTRIM after every LPUSH as that would add to overall latency in your app ( though redis is really fast, but you can save lots of LPUSH operations )
Here is a pseudo code to achieve an LTRIM on approximately every 5th LPUSH:
LPUSH mylist 1
random_int = some random number between 1-5
if random_int == 1: # trim my list with 1/5 chance
LTRIM mylist 0 10
Though your list may grow to be a few elements more than 10 elements at times, but it will surely get truncated at regular intervals.
This approach is good for most practical purposes and saves a lot of LTRIM operations, keeping your pushes fast.
The following code,
pushes the item to the list,
keep the size fixed to 10,
and returns the most recent 10 elements
in a transaction.
MULTI
LPUSH list "item1"
LTRIM list 0 9
LRANGE list 0 9
EXEC
No one has ever mentioned the real solution about storing only most 10 recent items.
Let's create a sample list with 15 items (here just numbers):
RPUSH list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Now indicate offset from the end of the list:
LTRIM list -10 -1
Show list
LRANGE list 0 -1
1) "6"
2) "7"
3) "8"
4) "9"
5) "10"
6) "11"
7) "12"
8) "13"
9) "14"
10) "15"
Now you can add new items and run trim:
RPUSH list 16
LTRIM list -10 -1
1) "7"
2) "8"
3) "9"
4) "10"
5) "11"
6) "12"
7) "13"
8) "14"
9) "15"
10) "16"
Just an alternative. According to official doc of LPUSH, it returns the length of the list after the push operations. You can set a threshold length like k (in your case k > 10) and call LTRIM when returned length is bigger than k. Sample pseudo code as follows:
len = LPUSH mylist xxx
if len > k:
LTRIM mylist 0 9
LRANGE mylist 0 9
It's more controllable than random method. Greater k triggers less LTRIM but with more memory cost. You can adjust k according to how often you want to call LTRIM since calling extra command is more expensive.
Calling LTRIM <list-name> -1 -10 after LPUSH <list-name> <item>
is the simplest answer. Many had covered it.
You must do this two operations in a transaction or must use Lua script to ensure the operation is atomic.

Resources