Random Letter Distribution Limitations - c

I am writing a scrabble program that will randomly generate an array of 7 letters.
this is my code that generates the letters and puts them in the array and it works great.
char randomletters (char letters[8], int i){
srand((time(NULL)));
for(i=0; i<7; i++){
letters[i] = (rand() % 26 + 65);
}
return letters[8];
}
My only issue is figuring out how to limit the number of times a certain letter can appear, using the standard scrabble distribution. Such as 'B' only can appear twice. I was thinking a way of doing it was 26 if statements that counted how many of each letter were there and if it was to much then start over? Seem's like that isn't the best way of doing it though.
Not looking for a code answer, just ideas on how to make it happen.
Thanks in advance.

char array[] = "AAAAAAAAABBCCD";
unsigned remaining = sizeof array;
int get_a_letter(void)
{
unsigned idx;
int sample;
if (!remaining) return EOF;
idx = urnd(remaining);
sample = array[idx] ;
array [idx] = array [--remaining];
array [remaining] = sample; // #Note:1
return sample;
}
urnd(xxx) is a function that should return a random value between 0 and (xxx-1), inclusive.
Update
#Note1: this statement is not necessary for drawing a random letter, but it helps for the next round: resetting remaining = sizeof array; will suffice to start over. (the array will be scrambled, but all the initial letters are still present)

Create an array of struct to keep a letter and the number of times it can be used. Randomly choose a number between 0 and 25, if the chosen cell has a count >0 add the letter to the rack decrease the letter count, repeat until the rack counts 7 tiles, repeat the whole think until less than 7 letters are left.

Related

Making a character array rotate its cells left/right n times

I'm totally new here but I heard a lot about this site and now that I've been accepted for a 7 months software development 'bootcamp' I'm sharpening my C knowledge for an upcoming test.
I've been assigned a question on a test that I've passed already, but I did not finish that question and it bothers me quite a lot.
The question was a task to write a program in C that moves a character (char) array's cells by 1 to the left (it doesn't quite matter in which direction for me, but the question specified left). And I also took upon myself NOT to use a temporary array/stack or any other structure to hold the entire array data during execution.
So a 'string' or array of chars containing '0' '1' '2' 'A' 'B' 'C' will become
'1' '2' 'A' 'B' 'C' '0' after using the function once.
Writing this was no problem, I believe I ended up with something similar to:
void ArrayCharMoveLeft(char arr[], int arrsize, int times) {
int i;
for (i = 0; i <= arrsize ; i++) {
ArraySwap2CellsChar(arr, i, i+1);
}
}
As you can see the function is somewhat modular since it allows to input how many times the cells need to move or shift to the left. I did not implement it, but that was the idea.
As far as I know there are 3 ways to make this:
Loop ArrayCharMoveLeft times times. This feels instinctively inefficient.
Use recursion in ArrayCharMoveLeft. This should resemble the first solution, but I'm not 100% sure on how to implement this.
This is the way I'm trying to figure out: No loop within loop, no recursion, no temporary array, the program will know how to move the cells x times to the left/right without any issues.
The problem is that after swapping say N times of cells in the array, the remaining array size - times are sometimes not organized. For example:
Using ArrayCharMoveLeft with 3 as times with our given array mentioned above will yield
ABC021 instead of the expected value of ABC012.
I've run the following function for this:
int i;
char* lastcell;
if (!(times % arrsize))
{
printf("Nothing to move!\n");
return;
}
times = times % arrsize;
// Input checking. in case user inputs multiples of the array size, auto reduce to array size reminder
for (i = 0; i < arrsize-times; i++) {
printf("I = %d ", i);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, i+times);
}
As you can see the for runs from 0 to array size - times. If this function is used, say with an array containing 14 chars. Then using times = 5 will make the for run from 0 to 9, so cells 10 - 14 are NOT in order (but the rest are).
The worst thing about this is that the remaining cells always maintain the sequence, but at different position. Meaning instead of 0123 they could be 3012 or 2301... etc.
I've run different arrays on different times values and didn't find a particular pattern such as "if remaining cells = 3 then use ArrayCharMoveLeft on remaining cells with times = 1).
It always seem to be 1 out of 2 options: the remaining cells are in order, or shifted with different values. It seems to be something similar to this:
times shift+direction to allign
1 0
2 0
3 0
4 1R
5 3R
6 5R
7 3R
8 1R
the numbers change with different times and arrays. Anyone got an idea for this?
even if you use recursion or loops within loops, I'd like to hear a possible solution. Only firm rule for this is not to use a temporary array.
Thanks in advance!
If irrespective of efficiency or simplicity for the purpose of studying you want to use only exchanges of two array elements with ArraySwap2CellsChar, you can keep your loop with some adjustment. As you noted, the given for (i = 0; i < arrsize-times; i++) loop leaves the last times elements out of place. In order to correctly place all elements, the loop condition has to be i < arrsize-1 (one less suffices because if every element but the last is correct, the last one must be right, too). Of course when i runs nearly up to arrsize, i+times can't be kept as the other swap index; instead, the correct index j of the element which is to be put at index i has to be computed. This computation turns out somewhat tricky, due to the element having been swapped already from its original place. Here's a modified variant of your loop:
for (i = 0; i < arrsize-1; i++)
{
printf("i = %d ", i);
int j = i+times;
while (arrsize <= j) j %= arrsize, j += (i-j+times-1)/times*times;
printf("j = %d ", j);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, j);
}
Use standard library functions memcpy, memmove, etc as they are very optimized for your platform.
Use the correct type for sizes - size_t not int
char *ArrayCharMoveLeft(char *arr, const size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
if(ntimes)
{
char temp[ntimes];
memcpy(temp, arr, ntimes);
memmove(arr, arr + ntimes, arrsize - ntimes);
memcpy(arr + arrsize - ntimes, temp, ntimes);
}
return arr;
}
But you want it without the temporary array (more memory efficient, very bad performance-wise):
char *ArrayCharMoveLeft(char *arr, size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
while(ntimes--)
{
char temp = arr[0];
memmove(arr, arr + 1, arrsize - 1);
arr[arrsize -1] = temp;
}
return arr;
}
https://godbolt.org/z/od68dKTWq
https://godbolt.org/z/noah9zdYY
Disclaimer: I'm not sure if it's common to share a full working code here or not, since this is literally my first question asked here, so I'll refrain from doing so assuming the idea is answering specific questions, and not providing an example solution for grabs (which might defeat the purpose of studying and exploring C). This argument is backed by the fact that this specific task is derived from a programing test used by a programing course and it's purpose is to filter out applicants who aren't fit for intense 7 months training in software development. If you still wish to see my code, message me privately.
So, with a great amount of help from #Armali I'm happy to announce the question is answered! Together we came up with a function that takes an array of characters in C (string), and without using any previously written libraries (such as strings.h), or even a temporary array, it rotates all the cells in the array N times to the left.
Example: using ArrayCharMoveLeft() on the following array with N = 5:
Original array: 0123456789ABCDEF
Updated array: 56789ABCDEF01234
As you can see the first cell (0) is now the sixth cell (5), the 2nd cell is the 7th cell and so on. So each cell was moved to the left 5 times. The first 5 cells 'overflow' to the end of the array and now appear as the Last 5 cells, while maintaining their order.
The function works with various array lengths and N values.
This is not any sort of achievement, but rather an attempt to execute the task with as little variables as possible (only 4 ints, besides the char array, also counting the sub function used to swap the cells).
It was achieved using a nested loop so by no means its efficient runtime-wise, just memory wise, while still being self-coded functions, with no external libraries used (except stdio.h).
Refer to Armali's posted solution, it should get you the answer for this question.

Iterate a long integer and then append number to an array in C

So I'm prompting the user for a number, stored as a long int, then I want to do a for loop and iterate that long int, getting all the odd position numbers in a odd array and all the even position numbers in a even array. I'm trying to resolve the credit problem set from CS50
#include <stdio.h>
#include <cs50.h>
int main(void)
{
long even[] = {}, odd[] = {};
long cc = get_long("Number: ");
}
Basically I'm trying to get this:
If long cc = 12345678912345, then even should be even[7] = {1, 3, 5, 7, 9, 2, 4} and odd should be odd[7] = {2, 4, 6, 8, 1, 3, 5}
I don't really know how I would be able to iterate over long cc to then add the specific number I need into the array
The main problem you have is that arrays in C have a fixed size, set when they are created, and that size cannot be changed. So there's no way to "append" to an array.
The usual way to deal with that is to create an array with a maximum size (or capacity) and track the "in use" part of the array with a separate variable (often called 'size'). At any given time, the array elements from 0 to size-1 are "in use" and valid, while those from size to capacity-1 are "free" and might contain garbage values that will be ignored.
Since the array and the size variable are so intimately connected, it is common to combine them into a struct to make things easier to manage:
#define MAX_ARRAY_SIZE 100
struct long_array {
size_t size;
long data[MAX_ARRAY_SIZE];
};
Now you can initialize an empty array with struct long_array odd = { 0 }; and you could then append to this array with
if (odd.size == MAX_ARRAY_SIZE) {
/* always check for errors or unexpected situations! */
fprintf(stderr, "array overflow\n");
exit(1); }
odd.data[odd.size++] = new_value;
of course, this will end up allocating the maximum amount for every array, so the limit needs to be fairly small. You can make this more flexible by allocating the array on the heap and storing the capacity in the array as well as the size:
struct long_array {
size_t size, capacity;
long *data;
};
but this requires more management to track when the array needs to be resized or freed.
that's fairly easy, just allocate two array with how many numbers are in cc using something like
int temp = cc, i = 0;
while (temp > 0) {i++; cc /= 10;}
Then calculate ur stuff like this:
while (cc > 0)
{
newNumber = cc/10;
newDigit = CC % 10
if (newNumber % 2 == 0) /*newDigit is even*/
else /*newDigit is odd*/
cc = newNumber;
}
You can use the modulo operator % to get each digit. The modulo operator basically gives you the remainder so if you do % 10 then it will give you the last digit. So 123 % 10 = 3. Then you divide the credit card number by 10 and repeat the process to get the next digit. Ex 123/10 = 12, then 12 % 10 is 2. If you make a counter variable to count how many times you've done the loop, that will give you the position. If you do position % 2, that will tell you if it is odd or even.
while (CC > 0)
digit = CC % 10
if (position % 2 == 1) //it's odd
else //its even
CC = CC/10 //to prepare for next iteration of the loop
position = position + 1 //position starts at right side of CC number
One of the other proposed answers here determines if the digit's value is odd or even, but you're trying to determine if the digit is in an even or odd position. The other proposed answer uses an array, which is something you learn about later in the course and isn't what the class is trying to teach you now.
The solution I've suggested is in line with what has been covered by your class so far. Later you will learn about arrays and you can approach this problem differently. Later in the course, you need to do this same problem in Python and that time I took in the value as a string because you can treat the full credit card number as an array and then each digit is just an element in that array. creditcardnumberarray[0] would be the first digit for example. You would need to change each digit from a Char to a Int before doing your checksum. You can do this conversion by subtracting the digit char from the char '0'. So int digitAsInt = digitAsChar - '0'

developing a function that returns number of distinct values that exist in array

I want to create a function that can return the number distinct values present in a given array. If for eg the array is
array[5] = { 1 3 4 1 3}, the return value should be 3(3 unique numbers in array).
I've so far only got this:
int NewFucntion(int values[], int numValues){
for (i=0; i<numValues; i++){
Im a new coder/New to C language and im stuck on how to proceed. Any guidance would be much appreciated. Thanks
Add elements from the array to the std::set<T> and since the set is not allowing duplicate elements, you can then only get the number of elements from the set which gives you the number of distinct elements.
For example:
#include<set>
int NewFucntion(int values[], int numValues){
std::set<int> set;
for(int i=0; i<numValues; i++){
set.insert(values[i]);
}
return set.size();
}
int distinct(int arr[], int arr_size){
int count = arr_size;
int current;
int i, j;
for (i = 0; i < arr_size; i++){
current = arr[i];
for (j = i+1; j < arr_size; j++) // checks values after [i]th element.
if (current == arr[j])
--count; // decrease count by 1;
}
if (count >= 0)
return count;
else return 0;
}
Here's the explanation.
The array with its size is passed as an argument.
current stores the element to compare others with.
count is the number that we need finally.
count is assigned the value of size of the array (i.e we assume that all elements are unique).
(It can also be the other way round)
A for loop starts, and the first (0th) element is compared with the elements after it.
If the element reoccurs, i.e. if (current==arr[j]), then the value of count is decremented by 1 (since we expected all elements to be unique, and because it is not unique, the number of unique values is now one less than what it was initially. Hence --count).
The loops go on, and the value is decremented to whatever the number of unique elements is.
In case our array is {1,1,1,1}, then the code will print 0 instead of a negative value.
Hope that helps.
Happy coding. :)
I like wdc's answer, but I am going to give an alternative using only arrays and ints as you seam to be coding in c and wdc's answer is a c++ answer:
To do this thing, what you need to do is to go through your array as you did, and store the new numbers you go over in a different array lets call it repArray where there wont be any repetition; So every time you add something to this array you should check if the number isn't already there.
You need to create it and give it a size so why not numValues as it cannot get any longer than that. And an integers specifying how many of it's indexes are valid, in other words how many you have written to let's say validIndexes. So every time you add a NEW element to repArray you need to increment validIndexes.
In the end validIndexes will be your result.

C programming: function that keeps track of word lengths & counts?

I'm having trouble articulating what the function is supposed to do, so I think I will just show you guys an example. Say my program opens and scans a text file, which contains the following:
"The cat chased after the rooster to no avail."
Basically the function I'm trying to write is supposed to print out how many 1 letter words there are (if any), how many 2 letter words there are, how many 3 letter words, etc.
"
Length Count
2 2
3 3
5 2
6 1
7 1
"
Here's my attempt:
int word_length(FILE *fp, char file[80], int count)//count is how many total words there are; I already found this in main()
{
printf("Length\n");
int i = 0, j = 0;
while(j < count)
{
for(i = 0; i < count; i++)
{
if(strlen(file[i] = i)
printf("%d\n", i);
}//I intended for the for loop to print the lengths
++i;
printf("Count\n");
while()//How do you print the counts in this case?
}
}
I think the way I set up the loops causes words of the same length to be printed twice...so it'd look something like this, which is wrong. So how should I set up the loops?
"Length Count
2 1
2 2
"
This sounds like homework, so I will not write code for you, but will give you some clues.
To hold several values you will need array. Element with index i will contain counter for words with length i.
Find a way to identify boundaries of words (space, period, beginning of line etc.). Then count number of characters between boundaries.
Increase relevant counter (see tip 1). Repeat.
Some details. You actually want to map one thing to another: length of word to number of such words. For mapping there is special data type, called usually hash(table) or dictionary. But in your case array can perfectly work as a map because you keys are uniform and continues (1,2 ... to some maximum word length).
You can't use a single int to count all of that. You need an array and then in it at position 0 you keep track of how many 1 letter words, at position 1 you accumulate 2 letter words and so on.

Starting with a 10x10 array how do I choose 10 random sites

I am trying to write C code to randomly select 10 random sites from a grid of 10x10. The way I am considering going about this is to assign every cell a random number between zero and RAND_MAX and then picking out the 10 smallest/largest values. But I have very little idea about how to actually code something like that :/
I have used pseudo-random number generators before so I can do that part.
Just generate 2 random numbers between 0 and 9 and the select the random element from the array like:
arr[rand1][rand2];
Do that 10 times in a loop. No need to make it more complicated than that.
To simplify slightly, treat the 10x10 array as an equivalent linear array of 100 elements. Now the problem becomes that of picking 10 distinct numbers from a set of 100. To get the first index, just pick a random number in the range 0 to 99.
int hits[10]; /* stow randomly selected indexes here */
hits[0] = random1(100); /* random1(n) returns a random int in range 0..n-1 */
The second number is almost as easy. Choose another number from the 99 remaining possibilities. Random1 returns a number in the continuous range 0..99; you must then map that into the broken range 0..hits[0]-1, hits[0]+1..99.
hits[1] = random1(99);
if (hits[1] == hits[0]) hits[1]++;
Now for the second number the mapping starts to get interesting because it takes a little extra work to ensure the new number is distinct from both existing choices.
hits[2] = random1(98);
if (hits[2] == hits[0]) hits[2]++;
if (hits[2] == hits[1]) hits[2]++;
if (hits[2] == hits[0]) hits[2]++; /* re-check, in case hits[1] == hits[0]+1 */
If you sort the array of hits as you go, you can avoid the need to re-check elements for uniqueness. Putting everything together:
int hits[10];
int i, n;
for (n = 0; n < 10; n++) {
int choice = random1( 100 - n ); /* pick a remaining index at random */
for (i = 0; i < n; i++) {
if (choice < hits[i]) /* find where it belongs in sorted hits */
break;
choice++; /* and make sure it is distinct *
/* need ++ to preserve uniform random distribution! */
}
insert1( hits, n, choice, i );
/* insert1(...) inserts choice at i in growing array hits */
}
You can use hits to fetch elements from your 10x10 array like this:
array[hits[0]/10][hits[0]%10]
for (int i = 0; i < 10; i++) {
// ith random entry in the matrix
arr[rand() % 10][rand() % 10];
}
Modified this from Peter Raynham's answer - I think the idea in it is right, but his execution is too complex and isn't mapping the ranges correctly:
To simplify slightly, treat the 10x10 array as an equivalent linear array of 100 elements. Now the problem becomes that of picking 10 distinct numbers from a set of 100.
To get the first index, just pick a random number in the range 0 to 99.
int hits[10]; /* stow randomly selected indexes here */
hits[0] = random1(100); /* random1(n) returns a random int in range 0..n-1 */
The second number is almost as easy. Choose another number from the 99 remaining possibilities. Random1 returns a number in the continuous range 0..99; you must then map that into the broken range 0..hits[0]-1, hits[0]+1..99.
hits[1] = random1(99);
if (hits[1] >= hits[0]) hits[1]++;
Note that you must map the complete range of hits[0]..98 to hits[0]+1..99
For another number you must compare to all previous numbers, so for the third number you must do
hits[2] = random1(98);
if (hits[2] >= hits[0]) hits[2]++;
if (hits[2] >= hits[1]) hits[2]++;
You don't need to sort the numbers! Putting everything together:
int hits[10];
int i, n;
for (n = 0; n < 10; n++) {
int choice = random1( 100 - n ); /* pick a remaining index at random */
for (i = 0; i < n; i++)
if (choice >= hits[i])
choice++;
hits[i] = choice;
}
You can use hits to fetch elements from your 10x10 array like this:
array[hits[0]/10][hits[0]%10]
If you want your chosen random cells from grid to be unique - it seems that you really want to construct random permutations. In that case:
Put cell number 0..99 into 1D array
Take some shuffle algorithm and toss that array with it
Read first 10 elements out of shuffled array.
Drawback: Running time of this algorithm increases linearly with increasing number of cells. So it may be better for practical reasons to do as #PaulP.R.O. says ...
There is a subtle bug in hjhill's solution. If you don't sort the elements in your list, then when you scan the list (inner for loop), you need to re-scan whenever you bump the choice index (choice++). This is because you may bump it into a previous entry in the list - for example with random numbers: 90, 89, 89.
The complete code:
int hits[10];
int i, j, n;
for (n = 0; n < 10; n++) {
int choice = random1( 100 - n ); /* pick a remaining index at random */
for (i = 0; i < n; i++) {
if (choice >= hits[i]) { /* find its place in partitioned range */
choice++;
for (j = 0; j < i; j++) { /* adjusted the index, must ... */
if (choice == hits[j]) { /* ... ensure no collateral damage */
choice++;
j = 0;
}
}
}
}
hits[n] = choice;
}
I know it's getting a little ugly with five levels of nesting. When selecting just a few elements (e.g., 10 of 100) it will have better performance than the sorting solution; when selecting a lot of elements (e.g., 90 of 100), performance will likely be worse than the sorting solution.

Resources