C 100 Prisoners riddle, something wrong with my code - arrays

(If you already know what the riddle is about just read the last 2 lines)
I saw a video about a riddle which is called "The 100 prisoners riddle" it essentially tells you that a bunch of prisoners (only one person at a time) get into a room, this room has boxes that are ordered correctly from 1 to a 100 but the numbers inside the boxes are random and each prisoner getting into the room is numbered from 1 to a 100 too, so each prisoner has to pick the box that has his number, each prisoner has a set of tries (50 tries) if he opened 50 boxes and he didn't find his number he loses! for example prisoner number 1 gets in the room and he has to find the box that has his number .. it might be box number 7 or 19 or 27 who knows! so it's just a game of luck .. or is it? the game has strategies and ways to mathematically solve the puzzle but that's not my problem here, I just wanna program the game in C and solve the puzzle for myself, the code has a lot of holes in it so look closely into it and find what's the problem, THANK YOU ALL :)!
#include <stdio.h>
#include <stdlib.h>
int main() {
int i, j = 0, k = 0, counter = 0;
int boxes[10];
int boxEntered;
for (i = 0; i <= 10; i++) \\ numbering the array
boxes[i] = i;
for (i = 0; i <= 10; i++) {
int temp = boxes[i];
int randomIndex = (rand() % 10); \\ shuffling the boxes to put random numbers
boxes[i] = boxes[randomIndex];
boxes[randomIndex] = temp;
}
for (i = 0; i <= 10; i++) {
printf("%d : (%d)\n", boxes[i], i); \\ print the boxes randomized and their index ordered
}
printf("You only have 5 tries!\n");
while (k != 5) {
while (j < 10) {
printf("Pick a box number between 0 and 10 (You are number %d)\n",counter);
scanf("%d",&boxEntered);
if (boxes[boxEntered] == boxes[counter]) {
printf("\nYou succeded, PROCEED TO NEXT PRISONER\n");
j++; \\ go to the next iteration
k = 0; \\ set tries back to 0
counter++;
} else
printf("Try again\nThe box you entered had number %d\n",boxes[boxEntered]);
k++;
if (k == 5) { \\ if player prisoner fails 5 times you break the loop
break;
}
}
}
if (counter == 10) { \\ if last prisoner was reached successfully then game is won
printf("You are freed!");
} else {
printf("You are going back heheheheheh!\n")
}
return 0;
}
As you can see in this picture the output doesn't make any sense at all and i have no idea what is wrong here..

From your code's logic, you should replace
boxes[boxEntered] == boxes[counter]
with
boxes[boxEntered] == counter
This is because counter here seems to represent a prisoner. Taking boxes[counter] will give you a box, which isn't what you want; you're trying to see if the box matches the current prisoner.
Another important note is the following code will go out of bounds for your array, causing undefined behaviour:
for (i = 0; i <= 10; i++) boxes[i] = i;
boxes is declared as having size 10, and therefore taking boxes[10] goes out of bounds; the maximum is boxes[9].
To fix this, you can index your arrays starting from 1. To do this in C, instead of declaring boxes[10], use boxes[11]. This will ensure you can access boxes[10].
You can then change your loops to start from 1, so something like:
for (i = 1; i <= 10; i++) boxes[i] = i;
Be sure to make this change for every array and for loop in your code.

Related

How do I record the frequency of numbers inputted by a user using functions in C

Hey there i'm currently developing a lotto type game and one of my requirements is to record the frequency of the numbers inputted by the user and then display them if the users wishes to see them. The program also must be modular hence the functions.
My problem is that i can't seem to figure out how to keep track of the numbers I tried numerous things and this is the closest I've gotten...
void num_free(int *picked_nums)
{
static int elements[MAX] = { 0 };
int i;
for (i = 0; i < MAX; i++)
if (*(picked_nums + i) == i)
{
elements[i]++;
}
for (i = 0; i < MAX; i++)
{
if (elements[i] != 0)
{
printf("\nThe amount of times you chose %d is %d", i, elements[i]);
}
}
printf("\nEnter any key to return to main menu");
getchar();
}
The output of this every time i run it no matter the input is
"The amount of times you chose 11 is 1"
I'm really clueless as to what to do next so any and all help would be appreciated. Thanks in advance!
EDIT: The user can play multiple rounds and thats how the frequency of the numbers can add up.
I think the main problem in your code is here:
if (*(picked_nums + i) == i)
{
elements[i]++;
}
you actually check if the i-th number the user chose equals to i. That means that increment is done only in that case - which is not what you want (if I got you right).
I think you should give up the if statement, and, assuming that the user chooses only non-negative numbers (and that the elements array is properly zeroed at the beginning), do this:
elements[picked_nums[i]]++;
Namely, you increment the array cell matching the chosen number (and the i is only the index you use to iterate the picked_num array).
The problem is how you count and store the numbers:
if (*(picked_nums + i) == i)
{
elements[i]++;
}
Your i is moving and at the same time the element chosen from picked_nums is moving. This loop will not count or store properly.
The provided solution assumes that picked numbers are stored in the numbers array. I assumed that numbers are in 1 to 64 range. You can adjust program to your needs. Test provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void num_free(int picked_nums[], int size )
{
static int elements[65] = { 0 }; // numbers can be from 1 to 64 range
int i;
for (int j = 0; j < size; j++)
{
int n = picked_nums[j];
for (i = 1; i < 65; i++) // numbers can be from 1 to 64 range
{
if ( n == i)
{
elements[i] = elements[i]+1;
}
}
}
for (i = 0; i < 65; i++)
{
if (elements[i] != 0)
{
printf("\nThe amount of times you chose %d is %d", i, elements[i]);
}
}
// printf("\nEnter any key to return to main menu");
// getchar();
}
// array of entered numbers:
int numbers[] = { 2, 2, 2, 40, 7, 7, 8, 9, 40 };
int main(void) {
num_free(numbers, 9); // call with sizeof numbers
return 0;
}
Test:
The amount of times you chose 2 is 3
The amount of times you chose 7 is 2
The amount of times you chose 8 is 1
The amount of times you chose 9 is 1
The amount of times you chose 40 is 2

I need to input 20 numbers and to output only double location

try to input 20 numbers with array and to output
the numbers in the double location only but somehow it's print
also the 0 location... please help.
#include<stdio.h>
#define n 20
int main()
{
int num[n]={0},i=0,order=1,double_locaion=0;
for(i=0;i<n;i++)
{
printf("please enter %d number\n",order);
scanf("%d",&num[i]);
order++;
}
for(i=0;i<n;i++)
{
if (i%2==0 && i!=1 && i!=0)
{
printf("%d\n",num[i]);
}
}
}
Try this, start with 2 and increase by 2 every time, the you don't have to deal with 0th element and odd element.
for (i = 2; i < n; i += 2)
{
printf("%d\n",num[i]);
}
First of all there is no way that your code is printing the 0-th location of the array. That's impossible given the condition of the if statement.
Secondly n- you don;t need to use macro expansion for that name.
/* This program takes 20 integer number from input.
* Prints the numbers entered in odd positions.(First,Third,..etc).
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM 20
int main(void)
{
int numArr[NUM];
for(size_t i = 0; i < NUM; i++) {
printf("please enter %zu number\n",i+1);
if( scanf("%d",&numArr[i]) != 1){
fprintf(stderr, "%s\n","Error in input" );
exit(1);
}
}
for(size_t i = 0; i < n; i++)
{
if( i%2 == 0 )// if you want to omit the first number put the
// the condition (i%2 == 0 && i)
{
printf("%d\n",numArr[i]);
}
}
return 0;
}
What you did wrong that your code skipped 0th element?
if (i%2==0 && i!=1 && i!=0)
^^^^
i when 0 makes this condition false - and you never get to print it.
i!=1 ?
If i=1 then i%2 will be 1, so you will not even check the second conditions, the whole conditional expression will become false. So you can safely omit this logic.
Is there a better way?
Sure,
for(size_t i = 0; i < n; i += 2){
printf("%d\n",num[i]);
}
Explanation
If you consider that every time you check the modular arithmetic of 2 the elements which results to 0 remained are
0,2,4,6,8,10,...18
See the pattern? Starts with 0 and increments by 2 each time and when does it stop? Yes before reaching 20 coding it we get
for(size_t i = 0; i < n; i += 2){
/* Initialize with i=0 as first number is 0 (i=0)
* Increments by 2 (i+=2)
* Runs when less than 20 (i<n)
*/
printf("%d\n",num[i]);
}
If you want to omit the 0-th index do initialize properly
for(size_t i = 2; i < n; i += 2){
If you mean you want the numbers from array that are present at even position than you can do like this:
for (i = 2; i < n; i=i + 2) //Initialize i = 0 if 0 is consider as even
{
printf("%d\n",arr[i]);
}
I above code i is initialized to 2 and the increment in each iteration is 2 so it will access elements only at even position (2,4,6...).

How to find if there is a common difference between integers in an array?

Lets say that the users input is 7 10 12 14 16 20 25. I want the output to be a set of numbers in ascending order whose difference is all the same. So for this case it would be: 12,25,7,20 OR 10,14,16,20. Notice how in both cases their difference is the same and theres at least 4 numbers in the output. How do i do this?
I'm trying to find if there is a common difference between the integers in the array. I first thought that it would be better to sort them in ascending order and then if sorted_array[1] - sorted_array[0] = sorted_array[2] - sorted_array[1] then theres a common difference. But then it doesnt work if the numbers are for example 4 5 12 13 16 20 27 28 where theres a common difference between [12,5], [20,13], [27,20]
int r = 0;
int l = 0;
while (r < n) {
if (arr_days4[r] - arr_days4[l] == arr_days4[r+1] - arr_days4[l+1]) {
sequence_difference++;
r++;
i++;
}
else if(arr_days4[i] - arr_days4[r] > arr_days4[r + 1] - arr_days4[l+1]){
l++;
}
else{
r++;
}
printf("\n%d", sequence_difference);
}
When I try to print sequence_difference it gives me 32767...Can anyone help?
first of all you should clear the requirement or specify the provided input and the output you want.
but seeing your code there's many mistakes i can figure out
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (array[i] > array[j]) {
a = array[i];
array[i] = array[j];
array[j] = a;
}
}
}
the inner loop must iterate n-1 times because of at last pass i will exceed n if you don't do this.
next error is in your while loop you have used i which is having value n becuase of upper for loop.
so try to look at these mistakes.
for more info you can check

C product of three consecutive numbers

I was trying to solve this tricky question, but for some reason my code is doing something wrong... I don't exactly know why, but I'll try to explain as much as I can.
Consecutive products:
Write a program that reads a positive integer
from standard input and verifies if it's equal to the product of three
natural and consecutive numbers. For example, the number 120 is equal
to 4x5x6, as for number 90 there aren't any three consecutive natural
numbers whose product is 90. Your program should generate as output
'S' if there are 3 consecutive natural numbers whose product is the
value read, or 'N' if none.
Input
120
Expected Output
"S"
Input
60
Expected Output
"S"
Input
80
Expected Output
"N"
Input
120
Expected Output
"S"
And this is my code:
#include <stdio.h>
int main(){
int int1,i,count=10,j,k,w=0;
scanf("%i",&int1);
for (i = 1; i <= count; ++i)
{
for (j = 1; j <= count+1; ++j)
{
for ( k = 1; k <= count+2; ++k)
{
if ((i==j+1 && i==k+2) && (i*j*k==int1)){
w=1;
}
}
}
}
if (w==0)
{
printf("N");
}
else{
printf("S");
}
}
So basically what this does is I have 3 loops that will generate random numbers in a k*i*j form... and it checks if we are getting what we want(the product of three natural and consecutive numbers) . This is for an assignment.
I modified your code. Please let me know if the problem still exists. The change made is exactly as WDS said.
#include <stdio.h>
int main(){
int int1,i,count=10,j,k,w=0,comp;
scanf("%i",&int1);
for (i = 1; i <= count; ++i)
{
comp = i*(i+1)*(i+2);
if(comp==int1)
{
w = 1;
}
}
if (w==0)
{
printf("N");
}
else
{
printf("S");
}
return 0;
}
You don't need 3 loops. One trival approach would be:
int test(int num)
{
for (int i = 1; i < num; i++)
{
int product = i * (i + 1) * (i + 2);
if ( product == num )
return true;
else if (product > num)
break;
}
return false;
}
You might want to add the algorithm tag on this question. That said, my approach would be to consider what the product of 3 consecutive numbers is. You could write it as x * (x+1) * (x+2). But there is a better way.
Write it as (x-1) * x * (x+1). Then multiply and simplify. The result is x^3-x.
Now for any given number, start a single loop on x from x = 2 (because if x=1 then x-1=0 and this will never be a solution) and incrementing by 1 each loop. Check on each loop for a match with the input number. If it is a match, return true. If it is not a match and exceeds the input number return false. If it is not a match and is less than the input number, loop again.

Most effective way to find combinations in C

#include <stdio.h>
#include <stdlib.h>
int chessboard[8][8];
int indicator, x, i, j, b, checksum, testerint, temp, row, column;
int rescounter, resstarter;
void togglecolumn(int columnumber) {
//
for (j = 0; j < 8; j++) {
//
chessboard[j][columnumber] = toggleint(chessboard[j][columnumber]);
}
}
void togglerow(int rownumber) {
//
for (j = 0; j < 8; j++) {
//
chessboard[rownumber][j] = toggleint(chessboard[rownumber][j]);
}
}
void fulltoggle(int i, int j) {
//
togglerow(i);
togglecolumn(j);
chessboard[i][j] = toggleint(chessboard[i][j]);
}
int toggleint(int a) {
//
if (a == 0) {
b = 1;
}
if (a == 1) {
b = 0;
}
return b;
}
void fillchessboard() {
x = 1;
//
for (i = 0; i < 8; i++) {
x = toggleint(x);
for (j = 0; j < 8; j++) {
//
chessboard[i][j] = x;
x = toggleint(x);
}
}
}
void showchessboard() {
//
printf("------------------- \n \n");
for (i = 0; i < 8; i++) {
//
for (j = 0; j < 8; j++) {
//
if (j == 7) {
//if end of the row
printf("%d \n", chessboard[i][j]);
} else {
//
printf("%d ", chessboard[i][j]);
}
}
}
printf("\n \n");
printf("------------------- \n \n");
}
int checkboard() {
checksum = 0;
for (i = 0; i < 8; i++) {
//
for (j = 0; j < 8; j++) {
//
if (chessboard[i][j] == 1) {
//
return 1;
}
}
}
return 0;
}
void rowcolindicator(int i) {
//
if (i % 8 == 0) {
column = 7;
row = i / 8 - 1;
} else {
row = i / 8;
column = i % 8 - 1;
}
}
// for proper operation i should be chosen 0
int recurfuntion(int i, int stepcounter) {
if (stepcounter != 0) {
stepcounter--;
temp = i;
for (i = temp + 1; i < 65; i++) {
//do row and column for
rowcolindicator(i);
fulltoggle(row, column);
recurfuntion(i, stepcounter);
}
if (i == 65) {
i = temp++;
rowcolindicator(temp);
fulltoggle(row, column);
stepcounter++;
}
} else {
//
temp = i;
for (i = temp + 1; i < 65; i++) {
//do row and column for i code and return iteration number if board turns all right
rowcolindicator(i);
fulltoggle(row, column);
if (checkboard() == 0) {
//
showchessboard();
return 1;
} else {
//
fulltoggle(row, column);
}
}
if (i == 65) {
i = temp++;
rowcolindicator(temp);
fulltoggle(row, column);
stepcounter++;
//showchessboard();
}
}
}
int main(int argc, char *argv[]) {
fillchessboard();
showchessboard();
indicator = checkboard();
printf("indicator is %d \n", indicator);
for (rescounter = 0; rescounter < 1000; rescounter++) {
fillchessboard();
printf("iiteration number: %d \n", rescounter);
if (recurfuntion(0, rescounter) == 1) {
printf("iteration number is %d so is the answer :) \n", rescounter);
}
}
system("PAUSE");
return 0;
}
I am trying solve this problem: "You have an 8x8 table on a computer screen with all squares colored to white. In each step you will select any square and as a result all the squares on the same row and column -including the selected square itself- will switch their colors (white becomes black, and black becomes white).
What is the minimum number of steps required for obtaining a standard colored chessboard?"
To do that, I percieved the chessboard into 64 pieces(8x8) and calculating all the combinations of this 64s cluster from 1 to 64. (I know the answer is between 1 and 64).
My method is to begin from the end(chessboard) through to all white. So I fill the board with ones(black) and zeros(white) and construct the chessboard in function fillchessboard() successfully. And I can perfectly toggle row and the column the initial square I choose is on.
Checking method if all board is white is checkboard(). This function returns indicator as 0 if all board is white, 1 if not. I start from little combinations to bigger combinations and check the board in each step. So when the indicator returns as 0 for the first time, it will be the smallest iteration number to make the board all white and be the answer of the question.
So far, my code works and in 10 hours it is able to step up to 10th iteration. However it will take more and more time so 11th iteration will take about 10 hours and 12th iteration will take 20 hours and so on... My question is, is there any method to these instructions more fast and effective? I can not wait for a week to solve this. I d appreciate any help. Thanks!
First let's do some naming:
c_{i,j} is the cell at intersection of row i and column j.
cross_{i,j} is the set: { c_{r,c} / r=i or c=j }. It is the cross of all cells from row i union column j. It contains an odd number of cells.
odd(cross_{i,j}) is a function which returns 0 if there is an even number of black cells in cross_{i,j} and 1 if there is an odd number of black cells.
Let's consider the effect of selecting cell c_{i,j}:
It will switch an odd number of cells in cross_{i,j} and so it will switch the value of odd(cross_{i,j}).
For all other "crosses" the number of cells impacted will be even and so the value of odd(cross_{k,l}) for any (k,l) \neq (i,j) will not change.
The reason for point 2 is that there are only 3 cases for the intersection of cross_{k,l} with cross_{i,j}:
It is a whole row, with an even number of cells.
It is a whole column with an even number of cells.
It is one cell for row k and one cell for column l.
So for every possibility an even number of cells change colors, and so the value of odd(cross_{k,l}) doesn't change.
So the only way to switch the value of odd(cross_{i,j}) is to select c_{i,j}.
At the end of the game there are 32 crosses which have switched value. So the minimal number of steps for any solution is 32.
Now, the previous reasoning also show that selecting the 32 cells of interest will produce the final checkerboard state.
So this is a minimal solution.
I'm sorry but there is no programming here :)
This isn't a solution, but some pointers that should help reduce the complexity (but not the difficulty) of the problem.
The chess board has 2^64 different states.
There are some properties of a chess board that will help you reduce the number of interesting states.
Each move flips 15 tiles (an odd number). Since you start and end with an even number of white tiles you know that the total number of moves is even.
Also, the order you perform the moves in is irrelevant. And selecting the same square twice reverses the previous flip. So we only need to figure out which of the 64 tiles to select.
So we can use 64 bits to represent the solution and each bit represents either a selected tile or an unselected tile. We could use a 64-bit long to store a possible solution.
Also, if you use a 64-bit long to store the state of the board, each step is an XOR with a number that flips the right 15 tiles (a number that has those 15 bits set).
A chessboard is symmetrical. It doesn't matter if you turn it or mirror it. The state would be the same. This further reduces the complexity, because it proves that if X is a solution then the complement of X is also a solution. So if no solution has been found with 32 pieces selected, then no solution exists.
My intuition (or rather the symmetry) suggests that the solution, if one exists) should be a multiple of 8 and be either 8, 16, or 32 with 16 being the most probable. I have no proof for this, however. I should be fairly easy to prove that no solution exists in 8 moves (and you have proved this by using brute force - provided your program is correct).

Resources