I am having trouble editing the values of a 2d char array.
char[,] chrRaster = new char[4, 5];
After adding values to the array and printing it to the console, I get:
// Input example:
*****
**.**
*****
****.
I am trying to make an algorithm that replaces every '*' that is beside, under or above a '.' by a '.' and then printing this to the console.
// Output after algorithm example:
**.**
*...*
**.*.
***..
I have tried converting the 2d char array to a 2d string array and then using IndexOf('*') to replace every '*' that is beside, under or above a '.', and I also tried calculating this using a number of if and for loops without any luck.
static void Main(string[] args)
{
// Variablen
int intTestgeval = 0; // Number of times you want program to repeat
int intN = 0; // Number of rows
int intM = 0; // Number of coloms
char chrGrond; // Used to store '*' or '.'
char[,] chrRaster; // 2d char array used to store all values
// Code
try
{
intTestgeval = Int32.Parse(Console.ReadLine()); // Number of times program will repeat
if(intTestgeval > 150) // Program can not repeat more then 150 times
{
throw new Exception();
}
}
catch (Exception)
{
Environment.Exit(0);
}
intN = Controle(intN); // Number of rows ophalen
intM = Controle(intM); // Number of Coloms ophalen
chrRaster = new char[intN, intM]; // Initializing array with user input
for (int intR = 0; intR < intTestgeval; intR++) // Print 2d array to console
{
for(int intY = 0; intY < intN; intY++)
{
for(int intZ = 0; intZ < intM; intZ++)
{
chrGrond = Convert.ToChar(Console.ReadKey().KeyChar);
chrRaster[intY, intZ] = chrGrond;
}
Console.WriteLine();
}
instorten[intR] = Instorten(chrRaster, intN, intM); // Ignore this part, that's another part of my assignment not related to my question.
}
}
static int Controle( int intX )
{
try
{
intX = Int32.Parse(Console.ReadLine());
if (intX > 150 || intX < 1) // Length of row and colom can not exceed 20 and can not go lower then 1
{
throw new Exception();
}
return intX;
}
catch // Program will off if value does not meet requirements
{
Environment.Exit(0);
return intX;
}
}
// It is this part of the program I need help with. This is what I tried but can't get any further
static int Instorten(char[,] chrRaster, int intN, int intM)
{
for (int intY = 0; intY < intN; intY++)
{
for (int intZ = 0; intZ < intM; intZ++)
{
if(chrRaster[intY, intZ] == '.' && chrRaster[intY, intZ + 1] == '*' || chrRaster[intY, intZ] == '*' && chrRaster[intY, intZ + 1] == '.')
{
}
}
Console.WriteLine();
}
int intm = 0;
return intm;
}
}
One way to do this would be to make a copy of the array and then iterate over it, examining each item. If the item is a '.', then update the neighbors of this item in the original array.
To determine the neighbors, we simply add one to the row to get the neighbor below, subtract one from the row to get the neighbor above, and similarly we can get the right and left neighbors by adding/subtracting from the column value. Of course we need to ensure that we're inside the bounds of the array before doing anything.
We could write a method with this logic that might look like:
private static void ExposeDotNeighbors(char[,] input)
{
if (input == null) return;
// Make a copy of the input array that we can iterate over
// so that we don't analyze items that we've already changed
var copy = (char[,]) input.Clone();
for (var row = 0; row <= copy.GetUpperBound(0); row++)
{
for (var col = 0; col <= copy.GetUpperBound(1); col++)
{
if (copy[row, col] == '.')
{
// Update neighbors in original array
// Above = [row - 1, col], Below = [row + 1, col],
// Left = [row, col - 1], Right = [row, col + 1]
// Before updating, make sure we're inside the array bounds
if (row > 0) input[row - 1, col] = '.';
if (row < input.GetUpperBound(0)) input[row + 1, col] = '.';
if (col > 0) input[row, col - 1] = '.';
if (col < input.GetUpperBound(1)) input[row, col + 1] = '.';
}
}
}
}
We can also write some helper methods that will give us the initial array and to print an array to the console (also one that will write a header to the console):
private static char[,] GetInitialArray()
{
var initialArray = new char[4, 5];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
if ((row == 1 && col == 2) || (row == 3 && col == 4))
{
initialArray[row, col] = '.';
}
else
{
initialArray[row, col] = '*';
}
}
}
return initialArray;
}
private static void PrintArrayToConsole(char[,] input)
{
if (input == null) return;
for (var row = 0; row <= input.GetUpperBound(0); row++)
{
for (var col = 0; col <= input.GetUpperBound(1); col++)
{
Console.Write(input[row, col]);
}
Console.WriteLine();
}
}
private static void WriteHeader(string headerText)
{
if (string.IsNullOrEmpty(headerText))
{
Console.Write(new string('═', Console.WindowWidth));
return;
}
Console.WriteLine('╔' + new string('═', headerText.Length + 2) + '╗');
Console.WriteLine($"║ {headerText} ║");
Console.WriteLine('╚' + new string('═', headerText.Length + 2) + '╝');
}
With these helper methods, we can then write code like:
private static void Main()
{
var chrRaster = GetInitialArray();
WriteHeader("Before");
PrintArrayToConsole(chrRaster);
ExposeDotNeighbors(chrRaster);
WriteHeader("After");
PrintArrayToConsole(chrRaster);
GetKeyFromUser("\nDone! Press any key to exit...");
}
And out output would look like:
I noticed that you also appear to be getting the values from the user, and using try/catch blocks to validate the input. A better approach might be to write a helper method that takes in a string that represents the "prompt" to the user, and a validation method that can be used to validate the input. With this, we can keep asking the user for input until they enter something valid.
Below are methods that get an integer and a character from the user, and allow the caller to pass in a function that can be used for validation. These methods will not return until the user enters valid input:
private static char GetCharFromUser(string prompt, Func<char, bool> validator = null)
{
char result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
result = Console.ReadKey().KeyChar;
} while (!(validator?.Invoke(result) ?? true));
Console.WriteLine();
return result;
}
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
!(validator?.Invoke(result) ?? true));
return result;
}
private static void ClearSpecificLineAndWrite(int cursorTop, string message)
{
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(message);
}
We can then re-write our GetInitialArray method to use these methods to get the dimensions and values from the user:
private static char[,] GetInitialArray()
{
const int maxCols = 20;
const int maxRows = 20;
var numCols = GetIntFromUser(
$"How many columns do you want (1 - {maxCols}): ",
i => i > 0 && i <= maxCols);
var numRows = GetIntFromUser(
$"How many rows do you want (1 - {maxRows}): ",
i => i > 0 && i <= maxRows);
var initialArray = new char[numRows, numCols];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
initialArray[row, col] = GetCharFromUser(
$"Enter value for [{row}, {col}] ('.' or '*'): ",
c => c == '.' || c == '*');
}
}
return initialArray;
}
And now our output might look like this:
If you try it, notice that you cannot enter an illegal value. The program just waits for you to read the instructions and enter a valid number or character. :)
Here is the algorithm that does what you want. I have tried to explain my code in the comments. The output will match what you're looking for.
static void Main(string[] args)
{
char STAR = '*';
char DOT = '.';
var input = new char[,]
{
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,DOT,STAR,STAR},
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,STAR,STAR,DOT}
};
var output = new char[4, 5];
// Copy each from input to output, checking if it touches a '.'
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 5; y ++)
{
if (input[x, y] == STAR)
{
var isDot = false;
// Check left
if (x > 0)
isDot = input[x - 1, y] == DOT;
// Check right
if (x < 3)
isDot = isDot || (input[x + 1, y] == DOT);
// Check above
if (y > 0)
isDot = isDot || (input[x, y - 1] == DOT);
// Check below
if (y < 4)
isDot = isDot || (input[x, y + 1]) == DOT;
output[x, y] = isDot ? DOT : STAR;
}
else
{
output[x, y] = input[x, y];
}
}
}
// Print output
for (int x = 0; x < 4; x ++)
{
for (int y = 0; y < 5; y ++)
{
Console.Write(output[x, y]);
}
Console.WriteLine();
}
Console.Read();
}
You can go like this :
using System;
public class chars
{
public static void Main(string[] args)
{
char[,] charArray = new char[,] {{'*','*','*','*','*'},
{'*','*','.','*','*'},
{'*','*','*','*','*'},
{'*','*','*','*','.'}};
int[,] holdIndex = new int[4, 5];
for(int i = 0; i<4; i++) // get allindexes containing '.'
{
for(int j = 0; j<5; j++)
{
if(charArray[i,j] == '.')
holdIndex[i,j] = 1;
else
holdIndex[i,j] = 0;
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
if(holdIndex[i,j] == 1)
{
if(i!=0)
charArray[i-1,j] = '.'; //up
if(j!=0)
charArray[i,j-1] = '.'; // left
if(j!=4)
charArray[i,j+1] = '.'; //right
if(i!=3)
charArray[i+1,j] = '.'; //down
}
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
Console.Write(charArray[i,j]);
}
Console.WriteLine();
}
Console.Read();
}
}
Related
I have to implement a simple spell checker. Basically I have to user input an incorrect sentence or a word, then a number N, and then N correct words each on new line. The program has to output "incorrect word: suggestion". If there is no suggestions available it should output "incorrect word: no suggestions" and if all the words from sentence are correct it should display "Correct text!". The typos can be:
Misspeled word.
Swapped letters.
Extra letter.
Missing letter.
To do this I implemented Levensthein minumim distance algorithm, which calculates the minimum number of modifications that a string has to take to be transformed into another string. All the test cases are fine but I want to reduce the cyclomatic complexity of the main method from 27 to below 26. Any suggestion would be helpful. For the example:
Thsi is an texzt fr tet
5
This
an
text
for
test
It displays:
Thsi: This
an: no suggestions
texzt: text
fr: for
tet: text test
using System;
using System.Collections.Generic;
namespace MisspelledWords
{
class Program
{
static void Main(string[] args)
{
string sentence = Console.ReadLine();
sentence = sentence.ToLower();
int numWords = int.Parse(Console.ReadLine());
const int doi = 2;
const int doi2 = 3;
int index = 0;
int index1 = 0;
string[] correctWords = new string[numWords];
for (int i = 0; i < numWords; i++)
{
correctWords[i] = Console.ReadLine();
}
foreach (string word in sentence.Split(' '))
{
index++;
int minDistance = int.MaxValue;
string closestWord = "";
foreach (string correctWord in correctWords)
{
int distance = GetLevenshteinDistance(word, correctWord);
if (distance < minDistance)
{
minDistance = distance;
closestWord = correctWord;
}
}
Message(minDistance, closestWord, word, index, ref index1, correctWords);
if (index1 != 0)
{
return;
}
}
static void Message(int minDistance, string closestWord, string word, int index, ref int index1, string[] correctWords)
{
if (minDistance >= doi)
{
// Print the misspelled word followed by "no suggestions"
Console.WriteLine(word + ": (no suggestion)");
}
else if (minDistance < doi && closestWord != word || minDistance >= doi2)
{
// Find all correct words that have the same minimum distance
List<string> suggestions = new List<string>();
foreach (string correctWord in correctWords)
{
int distance = GetLevenshteinDistance(word, correctWord);
if (distance == minDistance)
{
suggestions.Add(correctWord);
}
}
// Print the misspelled word followed by the suggestions
Console.Write(word + ": ");
Console.WriteLine(string.Join(" ", suggestions));
}
else if (minDistance == 0 && index > 1)
{
Console.WriteLine("Text corect!");
index1++;
}
}
static int Min(int value1, int value2, int value3)
{
return Math.Min(Math.Min(value1, value2), value3);
}
static int GetLevenshteinDistance(string word1, string word2)
{
int[,] distance = new int[word1.Length + 1, word2.Length + 1];
InitializeDistanceMatrix(distance, word1, word2);
CalculateLevenshteinDistance(distance, word1, word2);
return distance[word1.Length, word2.Length];
}
static void InitializeDistanceMatrix(int[,] distance, string word1, string word2)
{
for (int i = 0; i <= word1.Length; i++)
{
for (int j = 0; j <= word2.Length; j++)
{
if (i == 0)
{
distance[i, j] = j;
}
else if (j == 0)
{
distance[i, j] = i;
}
}
}
}
static void CalculateLevenshteinDistance(int[,] distance, string word1, string word2)
{
for (int i = 0; i <= word1.Length; i++)
{
for (int j = 0; j <= word2.Length; j++)
{
CLD(i, j, distance, word1, word2);
}
}
}
static void CLD(int i, int j, int[,] distance, string word1, string word2)
{
const int v = 2;
if (i <= 0 || j <= 0)
{
return;
}
distance[i, j] = Min(
distance[i - 1, j] + 1,
distance[i, j - 1] + 1,
distance[i - 1, j - 1] + (word1[i - 1] == word2[j - 1] ? 0 : 1));
// Check if swapping the characters at positions i and j results in a new minimum distance
if (i <= 1 || j <= 1 || word1[i - 1] != word2[j - v] || word1[i - v] != word2[j - 1])
{
return;
}
distance[i, j] = Math.Min(distance[i, j], distance[i - v, j - v] + 1);
}
Console.ReadLine();
}
}
}
I'm trying to create a function which will return string in Triangle Sine-Wave format:
but currently, my format is only in Wave format:
Code below:
public static void printWave(string str)
{
int height = 3;
// Get length of the string
int len = str.Length;
// Create a 2d character array
char[,] matrixArray = new char[height, len];
char[] charArray = str.ToCharArray();
// for counting the
// rows of the ZigZag
int row = 0;
bool down = true;
for (int i = 0; i < len; i++)
{
// put characters
// in the matrix
matrixArray[row, i] = charArray[i];
// You have reached the bottom
if (row == height - 1)
down = false;
else if (row == 0)
down = true;
if (down)
row++;
else
row--;
}
// Print the Zig-Zag String
for (int i = 0; i < height; i++)
{
for (int j = 0; j < len; j++)
{
Console.Write(matrixArray[i, j] + " ");
}
Console.Write("\n");
}
}
Can you please help me modify my code to it will return triangle sin wave format?
We can use 3 separate StringBuilders to append to depending on our boolean top and a simple even value comparison. A quick TL;DR is that anything at an even index goes in the middle row, and then we flip between appending to the top or bottom row:
public static void printWave(string str)
{
//for use to determine top or bottom StringBuilder
bool top = true;
//will be used to generate each row of the output
StringBuilder topString = new StringBuilder();
StringBuilder middleString = new StringBuilder();
StringBuilder bottomString = new StringBuilder();
//iterate through paramter string
for (int i = 0; i < str.Length; i++)
{
//if char is at an even index, it goes in the middle StringBuilder, blank spaces in top and bottom builders
if (i%2 == 0)
{
topString.Append(" ");
middleString.Append(str[i]);
bottomString.Append(" ");
}
//if not even index, determine top or bottom row
else
{
//simply check our boolean and then flip it after use
if (top)
{
topString.Append(str[i]);
middleString.Append(" ");
bottomString.Append(" ");
top = false;
}
else
{
topString.Append(" ");
middleString.Append(" ");
bottomString.Append(str[i]);
top = true;
}
}
}
//write each row of strings on new lines
Console.WriteLine(topString.ToString());
Console.WriteLine(middleString.ToString());
Console.WriteLine(bottomString.ToString());
}
For a variable height:
public static void printWave(string str)
{
//height we want the wave to reach
int height = 5;
//determine "middle" row
int startingRow = height / 2;
int currentRow = startingRow; //this one is for modifying inside loop
bool up = true;
//2D array to hold the rows
char[,] arr = new char[height, str.Length];
for (int i = 0; i < str.Length; i++)
{
for (int j = 0; j < height; j++)
{
if (j == currentRow)
{
arr[j, i] = str[i];
}
else
arr[j, i] = ' ';
}
//could probably break this into more digestible pieces if time to think about it
if (up)
{
if (currentRow == 0)
{
up = false;
currentRow++;
}
else
{
currentRow--;
}
}
else
{
if (currentRow == height - 1)
{
up = true;
currentRow--;
}
else
{
currentRow++;
}
}
}
for (int k = 0; k < height; k++)
{
for (int l = 0; l < str.Length; l++)
{
Console.Write(arr[k, l]);
}
Console.WriteLine();
}
}
Examples of height = 5 and height = 6 output:
And finally, height = 7
This version works, but it's hard-coded to just the 3 rows like the question shows. If larger waves are needed, or especially if the size of the wave depends on the input string, then this may be hard to adjust to the requirements.
public static void PrintWave(string str)
{
printWithRowLogic(str, (i) => (i - 1) % 4 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => i % 2 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => (i - 3) % 4 == 0);
}
private static void printWithRowLogic(string str, Func<int, bool> checkLogic)
{
for (int i = 0; i < str.Length; i++)
Console.Write(checkLogic(i) ? str[i] : ' ');
}
I'm a bit out of practice and currently having a hard time with this one question.
If a character appears only once in the given string, I need to replace it with 'x' If a character appears several times in the string I need to replace it with 'y' (Case sensitive) e.g. "Passable" would return as "xyyyyxxx".
So far I've tried converting the string to a char array and comparing it to a copy of itself using nested loops, but I cant figure out a way to save the index of all occurrences to change them into x or y.
Unfortunately it didn't work out too great, and I'm sure there is a much simpler way of doing this that I'm missing, any ideas?
This is what I have so far:
for (int i = 0; i < OccuredArray.Length; i++)
{
for (int x = 0; x < CharArray.Length; x++)
{
if (CharArray[x] == OccuredArray[i])
{
TimesOccured++;
}
}
if (TimesOccured > 1)
{
for (int y = 0; y < OccuredArray.Length; y++)
{
if (OccuredArray[i] == OccuredArray[y])
{
OccuredArray[i] = 'y';
}
}
}
if (TimesOccured == 1)
{
for (int y = 0; y < OccuredArray.Length; y++)
{
if (OccuredArray[i] == OccuredArray[y])
{
OccuredArray[i] = 'x';
}
}
}
TimesOccured = 0;
}
What about simplifying it a bit? Use a Dictionary<char, int> to count the occurences:
string input = "Passable";
var charCounter = new Dictionary<char, int>();
foreach (char c in input)
{
charCounter.TryGetValue(c, out int count);
charCounter[c] = ++count;
}
string output = string.Concat(input.Select(c => charCounter[c] == 1 ? "x" : "y"));
If you wanted to use a loop then you could do it like this:
var text = "Passable";
var countsByChar = new Dictionary<char, int>();
foreach (var c in text)
{
if (!countsByChar.TryAdd(c,1))
{
countsByChar[c]++;
}
}
foreach (var c in countsByChar.Keys)
{
text = text.Replace(c,
countsByChar[c] == 1
? 'x'
: 'y');
}
Console.WriteLine(text);
You could use a LINQ query instead though:
var text = "Passable";
var countsByChar = text.GroupBy(c => c)
.ToDictionary(g => g.Key,
g => g.Count());
foreach (var c in countsByChar.Keys)
{
text = text.Replace(c,
countsByChar[c] == 1
? 'x'
: 'y');
}
Console.WriteLine(text);
Based on your code I modified and commented on some cases which you should check out:
// So, I suggest this is the input string.
var OccuredArray = "abbcdd";
// It is always better for the length to be in a variable and to be used in for loops.
var OccuredArrayLenght = OccuredArray.Length;
// Here we will fill the placeholders depending on their appearance.
var OccuredArrayResult = new char[OccuredArrayLenght];
// Here we will trace the occurrences in which each index corresponds to a char from the ASCII table.
var OccuredArrayCharMap = new bool[byte.MaxValue];
for (int CurrentCharIndex = 0; CurrentCharIndex < OccuredArrayLenght; CurrentCharIndex++)
{
var CurrentChar = OccuredArray[CurrentCharIndex];
// If we have processed this char, we continue with the next one
if (OccuredArrayCharMap[CurrentChar] == true)
{
continue;
}
var Placeholder = 'x';
// Then we will check all the characters, starting from the next index
for (int NextCharIndex = CurrentCharIndex + 1; NextCharIndex < OccuredArrayLenght; NextCharIndex++)
{
//if (CharArray[FollowingCharIndex] == OccuredArray[OccuredArrayCharIndex])
//{
// TimesOccured++;
//}
// If char occured twice then the placeholder is y and we can break here
if (OccuredArray[NextCharIndex] == CurrentChar)
{
Placeholder = 'y';
break;
}
}
//if (TimesOccured > 1)
//{
// for (int y = 0; y < OccuredArray.Length; y++)
// {
// if (OccuredArray[OccuredArrayCharIndex] == OccuredArray[y])
// {
// OccuredArray[OccuredArrayCharIndex] = 'y';
// }
// }
//}
//if (TimesOccured == 1)
//{
// for (int y = 0; y < OccuredArray.Length; y++)
// {
// if (OccuredArray[OccuredArrayCharIndex] == OccuredArray[y])
// {
// OccuredArray[OccuredArrayCharIndex] = 'x';
// }
// }
//}
//TimesOccured = 0;
// Here we fill ouer result array with coresponding placeholder at matched index.
for (int CharIndex = CurrentCharIndex; CharIndex < OccuredArrayLenght; CharIndex++)
{
if (OccuredArray[CharIndex] == CurrentChar)
{
OccuredArrayResult[CharIndex] = Placeholder;
}
}
// And at the end we say that this char was already replaced.
OccuredArrayCharMap[CurrentChar] = true;
}
var ResultString = new string(OccuredArrayResult);
Console.WriteLine(OccuredArray);
Console.WriteLine(ResultString);
I am a total newbie to programming and i have been following some tutorials on array related to housie ticket generator.The point where I am stuck is that, I have to check each rows and each rows of the 3x9 matrix should not have more the two empty cells or it cannot have more then two cells filled next to each other.I am putting random numbers on the arrays and trying to validate the rules but,the program crashes. Can someone please give me an idea.?
This is what i've tried.
for(int columnIndex=0;columnIndex<=6;columnIndex++)
{
if(game[i,columnIndex+2]!=0)
{
return -1;
}
}
And this is the whole code
using System;
namespace HelloWorld
{
class Program
{
public static void Main (String[] args)
{
for(int times=0;times<2;times++)
{
startGame();
Console.WriteLine("******************************************************************");
}
}
private static void startGame()
{
int[,] game = new int[3, 9];
int occupancyLimit = 15;
while (occupancyLimit > 0)
{
int i = getRandomNumber(3);
int j = getRandomNumber(9);
//Console.Write(i);
//Console.Write(j);
// Console.Write(game[i,j]+" ");
int data = validateAndReturnNumber(i, j, game);
if (data>0)
{
game[i, j] = data;
occupancyLimit--;
//Console.WriteLine(game[i,j]);
}
}
for (int i = 0; i < game.GetLength(0); i++)
{
for (int j = 0; j < game.GetLength(1); j++)
{
Console.Write(game[i,j] + "\t");
}
Console.WriteLine();
}
}
private static int validateAndReturnNumber(int i, int j, int[,] game)
{
//do not override existing elements in array
if (game[i,j] != 0)
{
return -1;
}
//column cannot have more then two elements
int columncounter = 0;
for(int c=0;c<3;c++)
{
if(game[c,j]!=0)
{
columncounter++;
}
}
if(columncounter>=2)
{
return -1;
}
/*
//rows cannot have more then two cells filled in and
//rows cannot have more then two empty cells
for(int columnIndex=0;columnIndex<=6;columnIndex++)
{
if(game[i,columnIndex+2]!=0)
{
return -1;
}
}
*/
// rows cannot have more then 5 elements
int rowcounter = 0;
for(int r=0;r<9;r++)
{
if(game[i,r]!=0)
{
rowcounter++;
}
}
//Applying, rows cannot have more then 5 elements
if(rowcounter>=5)
{
return -1;
}
//return getRandomNumberForColumn(j);
int data = 0;
Boolean isValueSet = false;
do
{
data = getRandomNumberForColumn(j);
isValueSet = isValueExistsInCol(game, i, j, data);
} while (isValueSet);
return data;
}
private static bool isValueExistsInCol(int[,] game, int i, int j, int data)
{
Boolean status = false;
for(int k=0;k<3;k++)
{
if(game[k,j]==data)
{
status = true;
break;
}
}
return status;
}
private static int getRandomNumberForColumn(int high)
{
if(high==0)
{
high = 10;
}
else
{
high=(high + 1) * 10;
}
int low = high - 9;
Random random = new Random();
return random.Next(high-low)+low;
}
private static int getRandomNumber(int max)
{
Random random = new Random();
int num=random.Next(max);
return (num);
}
}
}
Why your for loop does not work:
for (int columnIndex = 0; columnIndex <= 6; columnIndex++)
{
if (game[i, columnIndex + 2] != 0)
{
return -1;
}
}
This loop does not take j into account. It is testing for previous numbers added, as soon as one previous number fails this test, it will fail indefinitely. This creates an infinite loop. This loop also fails if a number is placed in any position past 1, while it needs to fill 5 positions to succeed. This is mathematically impossible.
This:
'should not have more the two empty cells or it cannot have more then two cells' is also mathematically impossible. a row of 9 cannot have less than 2 full and less than 2 empty at the same time.
I think you are after 2 empty or full consecutively in a row. For that testing for two empty in a row cannot be achieved as it starts empty, and you are testing it before you fill it. Fortunately this is a redundant test that will always be true based on all of the other test cases.
No more than 2 full in a row is possible, but can also lead to impossible scenarios. I have added a check that resets the scenario if it has not found the solution after 1000 guesses.
using System;
namespace HelloWorld
{
class Program
{
public static void Main(String[] args)
{
for (int times = 0; times < 2; times++)
{
startGame();
// Console.WriteLine("******************************************************************");
}
}
private static void startGame()
{
int iCount = 0;
int[,] game = new int[3, 9];
int occupancyLimit = 15;
while (occupancyLimit > 0)
{
int i = getRandomNumber(3);
int j = getRandomNumber(9);
//Console.Write(i);
//Console.Write(j);
// Console.Write(game[i,j]+" ");
int data = validateAndReturnNumber(i, j, game);
if (data > 0)
{
game[i, j] = data;
occupancyLimit--;
//Console.WriteLine(game[i,j]);
}
else
{
iCount++;
//Console.WriteLine(iCount);
//printGame(game);
// If X many fails, retry
if(iCount > 1000)
{
iCount = 0;
game = new int[3, 9];
occupancyLimit = 15;
}
}
// If you want to check for zeros you would need to do it here. And use while(true) above
/*
if( //Check for zeros)
{
break; // Ends While loop
}
else
{
// Reset and try again
iCount = 0;
game = new int[3, 9];
occupancyLimit = 15;
}
*/
}
printGame(game);
}
private static void printGame(int[,] game)
{
for (int i = 0; i < game.GetLength(0); i++)
{
for (int j = 0; j < game.GetLength(1); j++)
{
Console.Write(game[i, j] + "\t");
}
Console.WriteLine();
}
Console.WriteLine("******************************************************************");
}
private static int validateAndReturnNumber(int i, int j, int[,] game)
{
//do not override existing elements in array
if (game[i, j] != 0)
{
return -1;
}
//column cannot have more then two elements
int columncounter = 0;
for (int c = 0; c < 3; c++)
{
if (game[c, j] != 0)
{
columncounter++;
}
}
if (columncounter >= 2)
{
return -1;
}
if(
(j != 0 && j != 1 && game[i, j - 2] != 0 && game[i, j - 1] != 0) || // 12X
(j != 0 && j != 8 && game[i, j - 1] != 0 && game[i, j + 1] != 0) || // 1X3
(j != 7 && j != 8 && game[i, j + 1] != 0 && game[i, j + 2] != 0) // X23
)
{
return -1;
}
//for (int columnIndex = 0; columnIndex <= 6; columnIndex++)
//{
// if (game[i, columnIndex + 2] != 0)
// {
// return -1;
// }
//}
// rows cannot have more then 5 elements
int rowcounter = 0;
for (int r = 0; r < 9; r++)
{
if (game[i, r] != 0)
{
rowcounter++;
}
}
//Applying, rows cannot have more then 5 elements
if (rowcounter >= 5)
{
return -1;
}
//return getRandomNumberForColumn(j);
int data = 0;
Boolean isValueSet = false;
do
{
data = getRandomNumberForColumn(j);
isValueSet = isValueExistsInCol(game, i, j, data);
} while (isValueSet);
return data;
}
private static bool isValueExistsInCol(int[,] game, int i, int j, int data)
{
Boolean status = false;
for (int k = 0; k < 3; k++)
{
if (game[k, j] == data)
{
status = true;
break;
}
}
return status;
}
private static int getRandomNumberForColumn(int high)
{
if (high == 0)
{
high = 10;
}
else
{
high = (high + 1) * 10;
}
int low = high - 9;
Random random = new Random();
return random.Next(high - low) + low;
}
private static int getRandomNumber(int max)
{
Random random = new Random();
int num = random.Next(max);
return (num);
}
}
}
Cheers!
I've got two algorithms converting random 2d arrays (m х n or m х m) to 1d array. I'm wondering if there is a way to make them work als in the opposite direction and convert the result to 1d array saving the order of numbers. Here is the full code of my program and a picture to see how both of my algorithms work.enter image description here
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using static System.Math;
namespace MyProgram
{
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter number of rows:");
int n = int.Parse(Console.ReadLine());
Console.Write("Enter number of columns:");
int m = int.Parse(Console.ReadLine());
int[] arr1 = new int[n * m];
int[,] arr2 = new int[n, m];
int choice;
do
{
Console.WriteLine("Select option:");
Console.WriteLine("\t1: Diagonal");
Console.WriteLine("\t2: Spiral");
Console.WriteLine("\t3: Exit");
Console.Write("Your selection: ");
choice = int.Parse(Console.ReadLine());
switch (choice)
{
case 1:
{
SetArray(arr2);
PrintArray(arr2);
Diagonal(arr2, arr1);
PrintArray(arr1);
break;
}
case 2:
{
SetArray(arr2);
PrintArray(arr2);
Spiral(arr2, arr1);
PrintArray(arr1);
break;
}
}
Console.WriteLine();
Console.WriteLine();
} while (choice != 5);
}
static void Diagonal(int[,] array2, int[] array1)
{
int k = 0;
int row = 0;
int col = 0;
while (k < array1.Length)
{
array1[k] = array2[row, col];
if ((row + col) % 2 == 0)
{
if ((row == 0) && (col != array2.GetLength(1) - 1)) { col++; }
else
{
if (col == array2.GetLength(1) - 1) { row++; }
else { row--; col++; }
}
}
else
{
if ((col == 0) && (row != array2.GetLength(0) - 1)) { row++; }
else
{
if (row == array2.GetLength(0) - 1) { col++; }
else { row++; col--; }
}
}
k += 1;
}
}
private static void Spiral(int[,] array2, int[] array1)
{
int lengthX = array2.GetLength(0);
int lengthY = array2.GetLength(1);
int Product = lengthX * lengthY;
int CorrectY = 0;
int CorrectX = 0;
int Count = 0;
while (lengthX > 0 && lengthY > 0)
{
for (int j = CorrectY; j < lengthY && Count < Product; j++)
{
array1[Count] = array2[CorrectX, j];
Count++ ;
}
CorrectX++;
for (int i = CorrectX; i < lengthX && Count < Product; i++)
{
array1[Count] = array2[i, lengthY - 1];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthY-- ;
else break;
for (int j = lengthY - 1; j >= CorrectY && Count < Product; j--)
{
array1[Count] = array2[lengthX - 1, j];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthX-- ;
else break;
for (int i = lengthX - 1; i >= CorrectX && Count < Product; i--)
{
array1[Count] = array2[i, CorrectY];
Count++ ;
}
CorrectY++;
}
}
public static void SetArray(int[,] arr)
{
Random r = new Random();
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = r.Next(11, 99);
}
}
}
public static void SetArray(int[] arr)
{
Random r = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = r.Next(11, 99);
}
}
public static void PrintArray(int[] arr)
{
Console.Write("print 1d array:");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + " ");
}
Console.WriteLine();
}
public static void PrintArray(int[,] arr)
{
Console.WriteLine("print 2d array:");
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write(arr[i, j] + " ");
}
Console.WriteLine();
}
}
}
}
Actually what you are asking is quite easy. Just change your algorithm methods to receive int rows, int cols and delegate like this
delegate void Apply(int row, int col, int index);
Then replace arr2.GetLength(0) with rows, arr2.GetLength(1) with cols, and array element assignments with delegate call.
Here is the updated Diagonal method (you can do the same with the other):
static void Diagonal(int rows, int cols, Apply action)
{
int k = 0;
int row = 0;
int col = 0;
int length = rows * cols;
while (k < length)
{
action(row, col, k);
if ((row + col) % 2 == 0)
{
if ((row == 0) && (col != cols - 1)) { col++; }
else
{
if (col == cols - 1) { row++; }
else { row--; col++; }
}
}
else
{
if ((col == 0) && (row != rows - 1)) { row++; }
else
{
if (row == rows - 1) { col++; }
else { row++; col--; }
}
}
k += 1;
}
}
and the usage:
SetArray(arr2);
PrintArray(arr2);
Diagonal(n, m, (r, c, i) => arr1[i] = arr2[r, c]);
PrintArray(arr1);
// Inverse
var arr3 = new int[n, m];
Diagonal(n, m, (r, c, i) => arr3[r, c] = arr1[i]);
PrintArray(arr3);
This seems to be working for me for backward Diagonal:
static void BackwardDiagonal(int[,] array2, int[] array1) {
int k = 0;
int row = 0;
int col = 0;
while (k < array1.Length) {
array2[row, col] = array1[k]; // just swap sides of the assignment...
if ((row + col) % 2 == 0) {
if ((row == 0) && (col != array2.GetLength(1) - 1)) { col++; } else {
if (col == array2.GetLength(1) - 1) { row++; } else { row--; col++; }
}
} else {
if ((col == 0) && (row != array2.GetLength(0) - 1)) { row++; } else {
if (row == array2.GetLength(0) - 1) { col++; } else { row++; col--; }
}
}
k += 1;
}
}
For backward Spiral:
private static void BackwardSpiral(int[,] array2, int[] array1)
{
int lengthX = array2.GetLength(0);
int lengthY = array2.GetLength(1);
int Product = lengthX * lengthY;
int CorrectY = 0;
int CorrectX = 0;
int Count = 0;
while (lengthX > 0 && lengthY > 0)
{
for (int j = CorrectY; j < lengthY && Count < Product; j++)
{
array2[CorrectX, j] = array1[Count]; // just swap sides of the assignment...
Count++ ;
}
CorrectX++;
for (int i = CorrectX; i < lengthX && Count < Product; i++)
{
array2[i, lengthY - 1] = array1[Count];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthY-- ;
else break;
for (int j = lengthY - 1; j >= CorrectY && Count < Product; j--)
{
array2[lengthX - 1, j] = array1[Count];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthX-- ;
else break;
for (int i = lengthX - 1; i >= CorrectX && Count < Product; i--)
{
array2[i, CorrectY] = array1[Count];
Count++ ;
}
CorrectY++;
}
}
I also added this to the switch statement to implement it:
case 4:
{
SetArray(arr2);
PrintArray(arr2);
Diagonal(arr2, arr1);
PrintArray(arr1);
int[,] arr3 = new int[n, m]; // new blank array to fill with arr1
BackwardDiagonal(arr3, arr1); // fill arr3 from backward Diagonal algorithm
PrintArray(arr3);
break;
}
case 5:
{
SetArray(arr2);
PrintArray(arr2);
Spiral(arr2, arr1);
PrintArray(arr1);
int[,] arr3 = new int[n, m]; // new blank array to fill with arr1
BackwardSpiral(arr3, arr1); // fill arr3 from backward Spiral algorithm
PrintArray(arr3);
break;
}
While you're at it, also make sure to have } while (choice != 3); at the end of your do loop so that you can exit the program!