✅ getting length of a list???
In my database file, I have a function that loads all of the ghost items back into a list and returns it
and in my game file, I am obtaining that list and attempting to get the length of it
I'm passing the length of the list to my random number generator, however, it says that ghosts doesn't have the Length property, so how do I get the length of the ghosts list to pass to my random number generator?
137 Replies
a few things
one: json serializer can serialize/deserialize a list just fine
you don't need to help it. Just
JsonSerializer.Deserialize<List<Ghost>>(...)
and your code above doesnt really make sensethat saved me some code. cool
read all the text into a string
create an empty list
for each item in that empty list
deserialize the same string into a single ghost, add it to the list we are currently looping over (not allowed)
there are so many things not making sense there
looping over an empty list, adding to it while looping over it, deserialzing the same thing several times
I changed the load function to deseralize into a list and return it
don't have to worry about the loop anymore. I changed the code
now I just need to figure out why
.Length
won't work on the returned listI get that, but you wrote that code and at least somewhat expected it to be correct-ish, no?
I thought it was, but I read back over it and saw the mistake.
You can't come ask for help on every single method you write for the rest of your life, so its probably good to try to learn
well, thats because
.Length
is for arrays
lists have .Count
arrays are fixed-size, constant length
lists are variable sizeI'm retaining everything that I can that is told to me, but I can just stop asking. Not being dramatic, but if I'm getting on peoples nerves then I can just stop.
thanks for this info. I wasn't aware of this and the tutorial I went through a couple of months ago didn't specify that
no no, just you have a way of writing like "oh yeah those four issues you just mentioned dont matter anymore as I changed the code"
no, the four issues still matter as you made those mistakes and should try to learn from them. that said, in this particular case the "solution" was to change the code,
one: json serializer can serialize/deserialize a list just fine you don't need to help it. Just JsonSerializer.Deserialize<List<Ghost>>(...)you're not wrong. As soon as you mentioned this, I looked back at the code and saw the problem. It's not that I was avoiding the issue. I saw the issue, understood what I did wrong and just tried to move on to the next problem. It's my fault that I forgot that json can deseralize to a list. That's my bad, but when you said that and I looked back at my code, I saw that I was iterating over an empty list instead of the information read from the file which still would have been wrong anyways.
Even so, how would you iterate over a string?
also, this is .net 7 right?
yes .net 7
right, ok
nvm then. .NET 8 adds some helper methods to easily pick a random item from a list
but in .net 7 you need to write it yourself
still, I encourage you to write it like an extension method
imagine using it like
var randomItem = list.GetRandomItem();
If you ever have a programming question, it's a lot faster to just google the question and slap "c#" at the end
this is literally the first thing I do for almost every question about coding I have. just briefly scan the top 5-10 hits and see if anything seems relevant
ok well after attempting to google, trying to print the type of the variables to the console, and so on, I cannot figure out the type casts for the objects on the left. They're defined in the ghost class on the right, however, when I print the
typeof
or GetType
to console, it only tells me PhasmoTriviaConsole.Ghost.Evidence[]
and I have tried List<string>...
, List<Ghost>...
, and other options and can't figure it outUhm, Im not sure what you are asking here really
I don't see any code for printing anything except the "could not determine..." stuff
because I didn't physically type it out.
okay so what is the problem?
if
PhasmoTriviaConsole.Ghost.Evidence[]
is being printed, you likely did Console.WriteLine(evidenceArray);
you cant just send an array to writeline
you probably want to use string.Join
to make a suitable string firstyes I'm aware of that. that's not what I did.
okay so what is the problem?having problems determining types.
ifno I didn't I didPhasmoTriviaConsole.Ghost.Evidence[]
is being printed, you likely didConsole.WriteLine(evidenceArray);
Console.WriteLine(typeof(Evidence))
and var evidence = ghost.Evidence; Console.WriteLine(evidence.GetType())
and that's what it gave me.
you can't just send an array to writelineyes I know this.
you probably want to use string.Join
to make a suitable string first
I don't know about this because I cannot figure out the type of the evidence, however, seeing evidenceArray
that tells me that it's an array so now I can go google how to type case an array. Thank youat this point I have no idea what you are talking about
your screenshot doesnt show anything about a
Evidence
classthought it did. that's my fault
it's an internal record. I know that much
Oh okay so its just a "Name"
these are not different types, btw
they are all just
Evidence
but when deserializing the json, and trying to type cast it, I'm drawing blanks
yup, that will work
but there are no types to cast here
all your different evidences are all
Evidence
instances
tehy are the same typeunderstandable on that. So this worked
Evidence[] evidence = ghost.Evidence;
however I still can't print the items to the console.you want to print the names, right?
so I'm wanting to learn how to get this result
ye
I'm wanting to learn how to get that information like that, but I don't know how to google that
you'll need string.join
there we go 😛
using a loop isn't waht you want thou, since you want it in one line and comma separated
much easier to do with string.join, its literally what its for
googlin what you showed in your picture, what about
Array.ForEach(yourArray, Console.WriteLine);
however, I don't want it to print them like that each time but rather put them in a csv stringtry it, but its not very idiomatic C#
and it wouldn't give you the desired result
like
string evidence = "EMF 5, Writing, Spirit Box";
that would be the wanted resultthink about what
Console.WriteLine
does
I can say string.Join
again if it helps?
only did it... 4 times so far?
:pjust because I haven't physically responded to it doesn't mean I didn't see it or try it. Right now I'm trying to google and work through why
string evidence = string.Join(", ", ghost.Evidence);
isn't working
I figured it out. I had to put the .ToList() on the ghost.Evidencehm, probably better to cast it to IEnumerabe
Console.WriteLine(string.Join(", ", (IEnumerable<Evidence>)list));
what's the difference?
.ToList actually allocates a new list and copies the data from the array in
casting just says "eh treat this object as if it was this other type instead"
ok that makes more sense
so still trying to get them to a string, these have the following
How would I do these?
you only need the cast if the thing is an array
understandable. It's not an int and it's not a string so what am I missing?
I don't know
you haven't shown the
Ghost
class for one :pbecause it doesn't show the type. Just that it's a public required Speed Speed
unless I"m missing it
?
I mean, that is the type.
Speed
is the type of the Speed
property
and thats jsut a wrapper around a double, as far as I can tell
so dont use string.Join
there, since there is only a single thing in speed
its not an arrayok I can understand that, but it's not an int, string, or double
sure
its a
Speed
and it won't let me double.TryParse
what are you trying to do? just print the speed value?
Console.WriteLine(ghost.Speed);
you've overriden the ToString
for Speed
so just print itno. I would like to have everything to a string. see how HuntSanity has a public override to put the values in the string? Each one of these has that public override and I'm trying to get the value from the json and return it in that string
string speed = ghost.Speed.ToString();
in that case.ohhhhhh. that makes sense
casting it to a string causes that override to take place
no casts taking place here
because it's a ToString override
we are just invoking the
Tostring
method on the Speed
objectright
(string)ghost.Speed
would be a cast, and it would crash :pI thought
string <- cast speed = ghost.Speed;
was a castnope
string speed
is just declaring a new variable of type stringgotcha
now I see the difference. cool
you could declare what we call an "implicit operator" to make
string x = ghost.Speed;
work, but why bother when ToString existsis it better to use ToString?
yes
explicit is often better than implicit in coding
implicit can lead to mistakes, and feels "magic"
that makes sense
so here's something else I would like to learn. Input validation. I never worked with regex in Python as I never needed to so I have no idea to use it, so how would I validate that a user's input was only the letters of the english alphabet?
could I do something like
or is there an easier way to check a whole word at one time instead of each individual letter?
not really
strings are just char arrays after all
so iterate through the string input and check each letter
is there maybe a regex I can check it against instead?
or would regex even be better in this instance?
you could use a regex, it would not be faster.
but if you wanted to use it, thats fine
like, if your rules were more complicated than "every char has to be one of these letters", you might need regex
oh ok. yea no my rule is every letter has to be between Aa and Zz
so I'll keep the iteration then
Wow you descriminate against scandinavians? 😦
what about
ÅÄÖ
and other amazing letters
😄lol nothing against them 😛 just using one alphabet type as the ghost names only use the 26-letter english alphabet
just joking
ok another learning question. When is it better to do
and
? or what's the difference. We don't have these in python
while (...){}
runs 0 or more times
do {} while()
runs 1 or more times
thats the major differencethe difference is one turn cycle?
not a term in familiar with, but sure
do runs BEFORE checking the condition. while runs AFTER checking the condition
ok rephrasing it. Here I'm giving the user 5 tries to get their answer correct. Is a while-loop better or a do-while-loop better and why?
so a regular while-loop is better here
yeah
in general, prefer while over do-while where it doesnt matter
gotcha.
but when you need the properties of do-while, go ahead and use its
cool cool
so using a regular while-loop to give the user 5 tries, how would I go about continuing with the rest of my code? What I mean is, if they run out of tries, the score does not increase but if they get it right with at least 1 try remaining, then the score increments by 1?
well, you have two exit conditions now
tries and guessed right
you need to know which one triggered the exit
so after the loop, you could test
if (tries > 0)
to know if they guessed it right or notok so giving this a shot
this is the entire game function. What do you think?
oh I messed it up
if (line != "None")
this is never false
You never ask the user to guess the ghost. I guess its implied, but still, I'd want a prompt.
Recursion to loop the game instead of a proper loop, bad.
score++;
maybe also print "you guessed correct, good job"?
userInput != name
means you are looking for case sensetive match, so Poltergeist
and poltergeist
wont matchdo
Equals()
with StringComparison.OrdinalIgnoreCase
when you want case insensitive comparisons`if (line != "None") this is never falseI see my mistake there
You never ask the user to guess the ghost. I guess its implied, but still, I'd want a prompt.I did get user input, but forgot my print statement to prompt for it. I see that mistake too.
Recursion to loop the game instead of a proper loop, badI just noticed that I messed it up by not wrapping the game in a loop that iterates for as many ghosts are in the file. I'm working on fixing that now.
score++;
what's wrong here?
maybe also print "you guessed correct, good job"?I haven't put this in yet. I wanted to get the logic down first, but you're not wrong. I'll add that in now too
I didn't notice this before, so another learning point. How can I check for both variations at the same time? I'll put the function in my helpers file as I can reuse it in the other game modes as well so this is that learning point in my last point above. Ok I'll look at the docs that on that. thanksuserInput != name
means you are looking for case sensetive match, soPoltergeist
andpoltergeist
won't match
score++;
was to show where the comment below belonged to, no issues with that line itselfcould also just call ToUpper() or ToLower() on both strings to make case insensitive but most people consider this kinda hacky and prefer the enum that exists for it 🙂
but good to keep in mind in case you forget about the proper way
it is hacky and wont work for some languages, like turkish
so prefer
StringComparison
:pdidn't know bout cases where its not working but good to know ^^
I guess thats why there is different IgnoreCase enum values for different cultures
ah yes, the turkish "dotless i"
ok so I've hit a snag
yepyep
I wrapped it in a while loop so that the questions repeat for the number of times that there are ghosts, however, I do not know how to get it to not pick the same ghost twice. How can I learn how to do that?
remember the randomGhostIndexes you have generated and keep generating when you already had that ghost
or remove ghosts from the list once you are done with them
I didn't realize that I was regenerating it on each iteration, however, it's how I pull a new random index on each iteration too to get a new ghost type. So having the list set to a variable
var ghosts = db.LoadGhosts();
and using something like the Pop()
method on it, won't erase it from the json file?
so like I could something at the bottom like
?
and doing the case match checking, would I do something like this https://stackoverflow.com/questions/6371150/comparing-two-strings-ignoring-case-in-c-sharp#:~:text=string.Equals(val%2C%20%22astringvalue%22%2C%20StringComparison.OrdinalIgnoreCase) ?
I just decided to put .ToLower()
on the name
and userInput
variables to make it easier
ok I've hit a problem while playing the game and testing it. There are two ghost types that have a space in their names. The Twins and The Mimic. How can I get the check to do correctly because right now, regardless to what I input eg: The Twins, thetwins, the twins, twins
it doesn't accept the answer. So how can I get my check to accept both The Twins/The Mimic and Twins/Mimic as an input and check for the capitolization match at the same time?The easiest way would be to add a new field to your ghost class
where you can have
NormalizedName
or something
which would always be lowercase and without the
so twins
or poltergeist
etc
granted, that wont allow you to guess the ...
so you'd perhaps need a special case for that too, by stripping the
from any guess
¯\_(ツ)_/¯
many options
note that you only use toLower
on the initial guess
you dont do that on userInput = Console.ReadLine();
true
ok so where and how would I check if
the
exists in the user's input and remove it if it does? I added in the normalized name to the ghost class and added in their names to just one word and all lowercase so that negated using .ToLower() on string username = ghost.NormalizedName;
Sounds like its time to make some utility methods
comparing the guessed name to the real name would be a good one, as you do it in two places and its about to get complicated
what about this?
thats a start
but like I said, stick that in a method
I replaced calling the ghost.Name with ghost.NormalizedName so that the game only uses the normalized name
thats good, but what if the user guesses
the twins
?
that wouldnt match the normalized nameok what about this?
notice how much repetition you have
right which is why I'm removing The/the from the users input
and
so put it all in the same method?
maybe combine those in a method of its own?
but I can't put them in one
you can
public static string GetValidatedNormalizedInput()
😄
you can just run those three methods in that method and then return the result
tada, less repetitionone checks for the word The/the and the other checks that each letter is a character of the 26 letter alphabet.
ok you caught my interest here I don't need to remove The/the from every user input. Only when they're guessing the ghost's name.
so only use that method when taking in ghost guesses
thats still in two places of your code currently
ok I"m a bit lost on what you mean. sorry
you can call your own methods from other methods
so just do that?
so call
ValidateInput
inside of CheckForThe
?no, make a new method that combines all of these is what I was going for
also, that
the
check is kinda... not great :p
it uses Contains
so it would trigger on "hello hello the" => "hello the"
StartsWith
sems more reasonable herenot a bad idea.
ok so what about
I know you said to make a function incorporating both, but my brain fried on trying to do that
.. really?
also, test "the best friend" in your "the" checker
oh it should be
input = input.Split(" ")[1:input.Length]
shouldn't it to remove the word "The" or "the" but return the rest
or input = input.Remove(0,4);
-execute
Mekasu0124
Decompile Result
Failed
Code
Result:
React with ❌ to remove this embed.
Mekasu0124
Decompile Result
Failed
Code
Result:
React with ❌ to remove this embed.
uhm, use
!e
Pobiega
REPL Result: Success
Console Output
Compile: 613.815ms | Execution: 29.461ms | React with ❌ to remove this embed.
so use the remove method instead of splitting and indexing
or
TrimStart
trim start?
eh, yeah that doesnt seem to work very well
I like the remove method
probably nicer with
return input[4..];
just straight remove the first 4 charactersMekasu0124
REPL Result: Success
Console Output
Compile: 655.392ms | Execution: 98.836ms | React with ❌ to remove this embed.
ok thank you for all your help. It's 5:15am my time and I've been working on this for nearly 13 hours now 😂 I'm going to close this help thread. Thank you all that helped
I actually have one more question. To create a save method in my database file that saves the games to the user.json when the game is over.
this is my Game Model for the game results.
how would I add to my json file? I currently have in it
and I want to make a new field that gets add to the file instead of overwriting it and erasing the user's profile like this
and the
"Games": {}
is where the saved games gets added to but never overwrites the fileyour model needs to have all the fields you wish to save in it
then you simply serialize the model and write that string to a file
so you'd probably take your existing UserInfo model and add a
GameModel Games
property on itam I doign this right so far?
almost
how is your
SaveGame
method defined?
since your top level model is User
, thats what you need to savesorry. I totally zoned out in working on the game. I've gotten that part figured out shortly after I posted that question. Thank you for your help