I am developing a chess engine in C#/Unity and want to print the board on a nice format. Preferably I want to print with some Unicode pieces but they end up making the board uneven, see image below:
The same seems to go for normal numbers since each row starts slightly off one another, row 1 starts more left than the others for example.
Why does my Debug.Log/prints end up like this, and how can I print them so that each character takes up the same amount of space?
EDIT:
Here is the code I use to Debug.Log the board if that helps:
public static void PrintBitboard(ulong bitboard)
{
string zero = " 0 ";
string one = " 1 ";
string printString = "";
// Loop through all squares and print a 1 if piece and 0 if not a piece on the square
for (int row = 0; row < 8; row++)
{
// Add numbering on the left side
printString += (8 - row) + " ";
for (int col = 0; col < 8; col++)
{
int currentSquare = row * 8 + col;
printString += BitOperations.GetBit(bitboard, currentSquare) != 0 ? one : zero;
}
// Change to new row
printString += "\n";
}
// Print bottom letters
printString += "\n" + " a b c d e f g h";
// Send message to the console
Debug.Log(printString);
}
What you are looking for is not "unicode" but monospace
-> As GiacomoCatenazzi already said, the only thing responsible for that is the font you are using
As a "quick and dirty" fix / alternative you could try and simply use tabs (\t) instead of spaces like (in general for larger string based concatenations I would recommend to use a StringBuider)
public static void PrintBitboard(ulong bitboard)
{
const string zero = "0\t";
const string one = "1\t";
var stringBuilder = new StringBuilder();
// Loop through all squares and print a 1 if piece and 0 if not a piece on the square
for (int row = 0; row < 8; row++)
{
// Add numbering on the left side
stringBuilder.Append((8 - row)).Append('\t');
for (int col = 0; col < 8; col++)
{
int currentSquare = row * 8 + col;
stringBuilder.Append(BitOperations.GetBit(bitboard, currentSquare) != 0 ? one : zero);
}
// Change to new row
stringBuilder.Append('\n');
}
// Print bottom letters
stringBuilder.Append("\n \ta\tb\tc\td\te\tf\tg\th");
// Send message to the console
Debug.Log(stringBuilder.ToString());
}
See .Net Fiddle which in the Unity console would look like
(in both I had to tricks a bit since I don't know what BitOperations implementation you are using)
Related
I Would really appreciate some help on this question I will sum it up myself but also include the actual instruction and my code so far.
Write a console C# program to do the following:
Ask user max number of characters. This should be an odd number if user enters even number add 1 to it to convert it to odd number.
Ask user the character to print
Your program should then output two inverted vertical triangles of base equal to number entered in #1 and made of characters in #2
Number of characters in one line of the triangle should differ by 2 from its next line such that the top of the triangle has only 1 character.
The top of the triangle (single character) should be centralized appropriately
Make sure your code follows these guidelines
-The output string should be returned as a single string variable from a class
-Class should have a public function that will returns the string and takes the input for #1 and #2 as argument
-Code should be well commented and indented
-Check for all invalid input values (e.g. for #1 no character should be accepted). Suitable message should be displayed to user for incorrect input
-All 5 requirements should be met
-Code should compile and run without any error or warnings
Example:
If user enters 9 for #1 and enters the character ‘*’ for #2 the program should print the following:
*
***
*****
*******
*********
*********
*******
*****
***
*
Thus far I can get the code to print out the correct number of characters, but not to align correctly into this shape.
I will attach my code at the bottom of this post. Whoever may respond, can you explain exactly how the for loop is working on order to achieve this? I know this is not an extremely difficult question, but C# is a new language to me, the course is entirely online, and I feel lost in such conceptual thinking. Thank you so much to whoever responds.
public class Class1
{
public void Main(string[] args)
{
int n;
char ch;
try
{
Console.Write("Enter the Max Number of Characters ::");
n = int.Parse(Console.ReadLine());
if (n % 2 == 0)
n++;
Console.Write("Enter Character Which You Want to Print ::");//output message for display
ch = char.Parse(Console.ReadLine());//value to get from user
Console.WriteLine(PatternPrint(n, ch));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public string PatternPrint(int n, char ch)
{
int i, j, k, l;//variable to declare
string str = "";//string to display
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n - i; j++)
{
str = str + " ";
}
for (k = 1; k <= i; k++)
{
str = str + ch;
}
for (l = i -1; l >= 1; l--)
{
str = str + ch;
}
str = str + "\n";
}
return str;//return string
}
}
}
You have a problem with your logic, as it prints only in one direction. Whereas, as per your requirement you need reverse direction pattern as well.
Your code output is :
*
***
*****
*******
*********
***********
*************
***************
*****************
Please try below code as it prints in both direction.
using System;
public class Test
{
public static void Main()
{
Console.Write("Enter the Max Number of Characters ::");
int totalChar = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter Character Which You Want to Print ::")
char character = char.Parse(Console.ReadLine());
totalChar = (totalChar % 2 == 0) ? totalChar += 1 : totalChar;
int mainIndex, spaceIndex, charIndex;
for(mainIndex = 1; mainIndex <= totalChar; mainIndex += 2)
{
for(spaceIndex = totalChar; spaceIndex >= mainIndex; spaceIndex -= 2)
Console.Write(" ");
for(charIndex = 1; charIndex <= mainIndex; charIndex++)
Console.Write(character);
Console.WriteLine();
}
for(mainIndex = totalChar; mainIndex >= 1; mainIndex -= 2)
{
for(spaceIndex = mainIndex; spaceIndex <= totalChar; spaceIndex += 2)
Console.Write(" ");
for(charIndex = 1; charIndex <= mainIndex; charIndex++)
Console.Write(character);
Console.WriteLine();
}
}
}
Sample Input : 9 & *
Sample Output:
*
***
*****
*******
*********
*********
*******
*****
***
*
This code works for me:
public string PatternPrint(int n, char ch) =>
String.Join(
Environment.NewLine,
Enumerable
.Range(1 - n / 2, n - 1)
.Select(x => Math.Abs(x))
.Select(i => "".PadLeft(i) + "".PadLeft(n - 2 * i - 1, ch)));
Given 5 and # I get:
#
###
#####
###
#
Here's brief explanation from me -
Observing example -
Input => Character to use '*', Maximum it can appear is 9 times (triangle's base).
Each line in triangle can be formatted in two ways -
White spaces, then characters.
White spaces, then characters, then again white spaces.
Observing your code -
You seem to using the first approach.
Your 1st loop add white spaces.
You may find this surprising, but your 2nd and 3rd do the same thing, they add characters, except 3rd loop has 1 less character.
What we need based on the example -
If max character usage per line is n, we need to have n+1 lines. (One more because lower triangle does not share base)
A triangle completes in (n+1)/2 lines.
To complete upper triangle, each line needs, each line needs
White spaces starting from (n-1)/2, decreasing by 1.
Characters starting from 1, increasing by 2.
To complete lower triangle, each line needs
White spaces starting from 0, increasing by 1.
Characters starting from n, decreasing by 2.
I would encourage you try yourself, but after you are done, here's the reference code -
public static string PatternPrint(int n, char ch)
{
StringBuilder sb = new StringBuilder();
int spaces, characters;
// Upper triangle
spaces = (n - 1) / 2;
characters = 1;
for (int i = 0; i < (n+1)/2; i++)
{
Enumerable.Repeat(' ', spaces).ToList().ForEach(space => sb.Append(space));
Enumerable.Repeat(ch, characters).ToList().ForEach(character => sb.Append(character));
sb.Append('\n');
spaces -= 1;
characters += 2;
}
// Lower triangle
spaces = 0;
characters = n;
for (int i = 0; i < (n+1)/2; i++)
{
Enumerable.Repeat(' ', spaces).ToList().ForEach(space => sb.Append(space));
Enumerable.Repeat(ch, characters).ToList().ForEach(character => sb.Append(character));
sb.Append('\n');
spaces += 1;
characters -= 2;
}
return sb.ToString();
}
Above code related notes -
Use StringBuilder to manipulate your string. It is more efficient, and easy I would say. Available in namespace System.Text
C# offers Linq library in namespace System.Linq. Enumerable used in code is part of it. It offers many more things, and extension methods. Really cool.
There's always room for improvement. My solution works based on assumptions. It silently fails when those assumptions are broken. Hint: evens
I am trying to modify a txt file, I need to change the 45 character with a P if the line starts with 8
for (int i = 0; i < textBox.Lines.Length; i++)//Loops through each line of text in RichTextBox
{
string text = textBox.Lines[i];
if ((text.Contains("8") == true)) //Checks if the line contains 8.
{
char replace = 'P';
int startindex = textBox.GetFirstCharIndexFromLine(i);
int endindex = text.Length;
textBox.Select(startindex, endindex);//Selects the text.
richTextBox1.Text = textBox.Text.Substring(0, textBox.SelectionStart) + (0, textBox.Lines) + replace + textBox.Text.Substring(textBox.SelectionStart + 45);
}}
To accomplish your goal the code could be changed in this way
//Loops through each line of text in RichTextBox
for (int i = 0; i < textBox.Lines.Length; i++)
{
string text = textBox.Lines[i];
//Checks if the line starts with "8".
if (text.StartsWith("8"))
{
// Find the 45th position from the start of the line
int startindex = textBox.GetFirstCharIndexFromLine(i) + 45;
// Starting from the found index select 1 char
textBox.Select(startindex, 1);
// Replace the selected char with the "P"
textBox.SelectedText = "P";
}
}
The key points changed are the way to select into a textbox. The Select method requires a starting index and the number of character to select, finally, once you have a SelectedText, (a read/write property) you can simply replace the current SelectedText with your own text. Lot easier than your current (and wrong) calculation.
I had an interviewer ask me to write a program in c# to figure out the max number of 4 members families that can sit consecutively in a venue, taking into account that the 4 members must be consecutively seated in one single row, with the following context:
N represents the number of rows availabe.
The Columns are labeled from the letter "A" to "K", purposely ommiting the letter "i" (in other words, {A,B,C,D,E,F,G,H,J,K})
M represents a list of reserved seats
Quick example:
N = 2
M = {"1A","2F","1C"}
Solution = 3
In the representation you can see that, with the reservations and the size given, only three families of 4 can be seated in a consecutive order.
How would you solve this? is it possible to not use for loops? (Linq solutions)
I got mixed up in the for loops when trying to deal with the reservations aray: My idea was to obtain all the reservations that a row has, but then I don't really know how to deal with the letters (Converting directly from letter to number is a no go because the missing "I") and you kinda need the letters to position the reserved sits anyway.
Any approach or insight on how to go about this problem would be nice.
Thanks in advance!
Here is another implementation.
I also tried to explain why certain things have been done.
Good luck.
private static int GetNumberOfAvailablePlacesForAFamilyOfFour(int numberOfRows, string[] reservedSeats)
{
// By just declaring the column names as a string of the characters
// we can query the column index by colulmnNames.IndexOf(char)
string columnNames = "ABCDEFGHJK";
// Here we transform the reserved seats to a matrix
// 1A 2F 1C becomes
// reservedSeatMatrix[0] = [0, 2] -> meaning row 1 and columns A and C, indexes 0 and 2
// reservedSeatMatrix[1] = [5] -> meaning row 2 and column F, index 5
List<List<int>> reservedSeatMatrix = new List<List<int>>();
for (int row = 0; row < numberOfRows; row++)
{
reservedSeatMatrix.Add(new List<int>());
}
foreach (string reservedSeat in reservedSeats)
{
int seatRow = Convert.ToInt32(reservedSeat.Substring(0, reservedSeat.Length - 1));
int seatColumn = columnNames.IndexOf(reservedSeat[reservedSeat.Length - 1]);
reservedSeatMatrix[seatRow - 1].Add(seatColumn);
}
// Then comes the evaluation.
// Which is simple enough to read.
int numberOfAvailablePlacesForAFamilyOfFour = 0;
for (int row = 0; row < numberOfRows; row++)
{
// Reset the number of consecutive seats at the beginning of a new row
int numberOfConsecutiveEmptySeats = 0;
for (int column = 0; column < columnNames.Length; column++)
{
if (reservedSeatMatrix[row].Contains(column))
{
// reset when a reserved seat is reached
numberOfConsecutiveEmptySeats = 0;
continue;
}
numberOfConsecutiveEmptySeats++;
if(numberOfConsecutiveEmptySeats == 4)
{
numberOfAvailablePlacesForAFamilyOfFour++;
numberOfConsecutiveEmptySeats = 0;
}
}
}
return numberOfAvailablePlacesForAFamilyOfFour;
}
static void Main(string[] args)
{
int familyPlans = GetNumberOfAvailablePlacesForAFamilyOfFour(2, new string[] { "1A", "2F", "1C" });
}
Good luck on your interview
As always, you will be asked how could you improve that? So you'd consider complexity stuff like O(N), O(wtf).
Underlying implementation would always need for or foreach. Just importantly, never do unnecessary in a loop. For example, if there's only 3 seats left in a row, you don't need to keep hunting on that row because it is not possible to find any.
This might help a bit:
var n = 2;
var m = new string[] { "1A", "2F", "1C" };
// We use 2 dimension bool array here. If it is memory constraint, we can use BitArray.
var seats = new bool[n, 10];
// If you just need the count, you don't need a list. This is for returning more information.
var results = new List<object>();
// Set reservations.
foreach (var r in m)
{
var row = r[0] - '1';
// If it's after 'H', then calculate index based on 'J'.
// 8 is index of J.
var col = r[1] > 'H' ? (8 + r[1] - 'J') : r[1] - 'A';
seats[row, col] = true;
}
// Now you should all reserved seats marked as true.
// This is O(N*M) where N is number of rows, M is number of columns.
for (int row = 0; row < n; row++)
{
int start = -1;
int length = 0;
for (int col = 0; col < 10; col++)
{
if (start < 0)
{
if (!seats[row, col])
{
// If there's no consecutive seats has started, and current seat is available, let's start!
start = col;
length = 1;
}
}
else
{
// If have started, check if we could have 4 seats.
if (!seats[row, col])
{
length++;
if (length == 4)
{
results.Add(new { row, start });
start = -1;
length = 0;
}
}
else
{
// // We won't be able to reach 4 seats, so reset
start = -1;
length = 0;
}
}
if (start < 0 && col > 6)
{
// We are on column H now (only have 3 seats left), and we do not have a consecutive sequence started yet,
// we won't be able to make it, so break and continue next row.
break;
}
}
}
var solution = results.Count;
LINQ, for and foreach are similar things. It is possible you could wrap the above into a custom iterator like:
class ConsecutiveEnumerator : IEnumerable
{
public IEnumerator GetEnumerator()
{
}
}
Then you could start using LINQ.
If you represent your matrix in simple for developers format, it will be easier. You can accomplish it either by dictionary or perform not so complex mapping by hand. In any case this will calculate count of free consecutive seats:
public static void Main(string[] args)
{
var count = 0;//total count
var N = 2; //rows
var M = 10; //columns
var familySize = 4;
var matrix = new []{Tuple.Create(0,0),Tuple.Create(1,5), Tuple.Create(0,2)}.OrderBy(x=> x.Item1).ThenBy(x=> x.Item2).GroupBy(x=> x.Item1, x=> x.Item2);
foreach(var row in matrix)
{
var prevColumn = -1;
var currColumn = 0;
var free = 0;
var div = 0;
//Instead of enumerating entire matrix, we just calculate intervals in between reserved seats.
//Then we divide them by family size to know how many families can be contained within
foreach(var column in row)
{
currColumn = column;
free = (currColumn - prevColumn - 1)/familySize;
count += free;
prevColumn = currColumn;
}
currColumn = M;
free = (currColumn - prevColumn - 1)/familySize;
count += free;
}
Console.WriteLine("Result: {0}", count);
}
I am currently sending and splitting long lines of data to Excel. Each split prints in a new row. I want to change this from splitting at a pipe symbol in the existing data to splitting at a character length of 85, but , there are chances that at character 85 it may split a word in two. How would I tell it to split further into the data if is going to split an actual word. I know if at 85 it should also find a space after. I'm curious on what to add.
// Add Description
string DescriptionSplit = srcAddOnPanel.Controls["txtProductDescAddOn" + AddRow].Text;
string[] descriptionParts = DescriptionSplit.Split('|');
int i;
for (i = 0; i <= descriptionParts.GetUpperBound(0); i++)
{
worksheet.Rows[currentRow].Insert(); //applies the description for the default bundle row
worksheet.Rows[currentRow].Font.Bold = false;
worksheet.Cells[currentRow, "E"].Value = rowIndent + descriptionParts[i].Trim();
currentRow++;
}
You could use this approach (Warning not fully tested)
int x = 85;
int y = 0;
int currentRow = 0;
// Loop until you have at least 85 char to grab
while (x + y < DescriptionSplit.Length)
{
// Find the first white space after the 85th char
while (x + y < DescriptionSplit.Length &&
!char.IsWhiteSpace(DescriptionSplit[x+y]))
x++;
// Grab the substring and pass it to Excel for the currentRow
InsertRowToExcel(DescriptionSplit.Substring(y, x), currentRow);
// Prepare variables for the next loop
currentRow++;
y = y + x + 1;
x = 85;
}
// Do not forget the last block
if(y < DescriptionSplit.Length)
InsertRowToExcel(DescriptionSplit.Substring(y), currentRow);
...
void InsertRowToExcel(string toInsert, int currentRow)
{
worksheet.Rows[currentRow].Insert();
worksheet.Rows[currentRow].Font.Bold = false;
worksheet.Cells[currentRow, "E"].Value = rowIndent + toInsert.Trim();
}
Here's a VBA version that seems to work. As suggested in my comment, it separates the string by spaces and then tests whether adding a word makes the length of the current line greater than the maximum (85). As is usual with these kinds of things getting the last word to populate correctly is hard.
If this works for you it should be simple enough to modify to C#. Let me know if that's not true:
Sub ParseRows()
Const ROW_LENGTH As Long = 85
Dim Text As String
Dim Words As Variant
Dim RowContent As String
Dim RowNum As Long
Dim i As Long
Text = ActiveCell.Text
Words = Split(Text, " ")
RowNum = 2
For i = LBound(Words) To UBound(Words)
If Len(RowContent & Words(i) & " ") > ROW_LENGTH Then
ActiveSheet.Range("A" & RowNum).Value = RowContent
RowNum = RowNum + 1
If i = UBound(Words) Then
RowContent = Words(i)
Else
RowContent = ""
End If
Else
RowContent = RowContent & Words(i) & " "
End If
Next i
If RowContent <> "" Then ActiveSheet.Range("A" & RowNum).Value = RowContent
End Sub
I am practising my programming skills with a rather common problem, to draw an ASCII tree composed of a letter (let's say x's) to draw a tree.
Ie:
Prompt: Enter the number of lines for your tree: 5
Output:
x
xxx
xxxxx
xxxxxxx
x
The solution I have is currently working as I want it to. I am only missing one feature (which is part of my question). The issue is, I do not understand the for-loop conditionals I have used. Yes, I did get help from another individual and I still do not understand their logic, but it works. Please, please, please explain to me how the for loop conditionals are actually working for me to draw what I want. x.x
Furthermore, I am unable to draw the last "stump" of the tree, the final x in the last row.
Here is my code.
static void Main(string[] args)
{
int lines = 0;
Console.WriteLine("Enter number of lines: ");
string LinesAsString = Console.ReadLine();
lines = Convert.ToInt32(LinesAsString);
print(lines);
}
public static void print(int lines)
{
for (int i = 0; i < lines; i++)
{
for (int a = 0; a < lines-i-1; a++)
{
Console.Write(" ");
}
for (int y = 0; y < i*2 + 1; y++)
{
Console.Write("x");
}
Console.WriteLine();
}
}
Any help is appreciated.
Thanks.
The first for loop prints the left padding (all spaces). The expression lines - i - 1 comes form the fact that you need to center the tree and you know that line 0 has a single x, line 1 has 3 (xxx), line 2 has 5 (xxxxx) and so on. But the number of left spaces depends on the total number of lines the tree has, therefore you need to take the lines into account as well as the index of the current line (which is the value of the variable i). To figure out the relationship between these two, you can just try with a small number of levels, let's say 3:
__x 2 for the 1st line.
_xxx 1 for the 2nd line.
xxxxx 0 for the 3rd line.
The second for loop prints the xs. It knows that for the first line (i = 0) it needs to print a single x, so when i is 0, y needs to be 1, therefore the + 1. The * 2 comes from the progression i * 2 + 1 = {1, 3, 5, 7...} which is the number of xs in each line.
To print the last stub character you can use the same logic as in the first for loop, inserting the number of spaces for the first line followed by a single x.
Console.Write(new String(' ', lines - 1) + "x");
This should be added just after the for loop that contains the two other loops.
It's quite simple:
Each iteration of the first for loop draws a line. Supposing you have 4 lines (I am not considering the one with the lonely x):
line 1 (i=0): 3 spaces 1 x
line 2 (i=1): 2 spaces 3 x
line 3 (i=2): 1 spaces 5 x
line 4 (i=3): 0 spaces 7 x
From these, you can obtain a relation between the number of spaces, x's, the line index i and the number of lines.
spaces = (lines - i) - 1 // decreases by one every iteration starting at lines - 1
x = i * 2 + 1 // the odd numbers in increasing order
The first loop draw the spaces and the second one the x's
int count = 0;
for (int i = 0; i < 8; i++)
{
for (int x = 0; x < 8-i-1; x++)
{
Console.Write(" ");
}
for (int j = 0; j < i*2+1; j++)
{
Console.Write("X");
}
Console.WriteLine();
}
//solution to your stump problem
for (int i = 0; i < 4; i++)//the no. 4 means that you stump will be made from four X's
{
for (int x = 0; x < 8-count-1; x++)
{
Console.Write(" ");
}
Console.Write("X");
Console.WriteLine();
}
Console.ReadKey();