I have fully coded the program from "The Rust Programming Language" book online, chapter 2. I have also developed it a tiny bit further than provided: by adding a simple question/response where the user gets to play again by inputting "y".
However, I am experiencing a slight bug in my program. When a user opts to run the game again, the text output "Please input a (number) guess" is repeated twice. Of course, this does not take away from the main functionality of the program (it still functions fine after the repeat), but it does seem weird and I'd prefer to remove the issue now rather than leaving it.
I have done some debugging, which has resulted in me concluding it is definitely happening in the [figure 3] area in the code. To see how I did so, go to the debugging area below.
Code
extern crate rand;
#[macro_use]
extern crate text_io;
use rand::Rng;
use std::io;
use std::cmp::Ordering;
//Main code
fn main() {
// Generate random number, create premise
println!("Guess the number!");
let mut breaking_choice = false;
while !breaking_choice {
let secret_number = rand::thread_rng().gen_range(1, 101);
// **Problem area**
loop {
println!("Please input a (number) guess");
println!("1"); // [**REFERENCE 1**]
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("2"); // [**REFERENCE 2**]
let guess: u32 = match guess.trim().parse() { // [FIGURE 3]
Ok(num) => num, // [FIGURE 3]
Err(_) => continue, // [FIGURE 3]
};
// ...until correct
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small"),
Ordering::Greater => println!("Too big"),
Ordering::Equal => {
println!("Correct!");
break;
}
}
}
// **Possible problem area**
println!("Would you like to continue playing? Y or N");
let choice: String = read!();
if choice == "N" {
breaking_choice = true
} else if choice == "n" {
breaking_choice = true
} else if choice == "Y" {
continue;
} else if choice == "y" {
continue;
}
}
}
Debugging
The first thing I did was place some simple println! commands at the main processing areas of the questionable code: [Reference 1] and [Reference 2]. This allowed me to see whether any of the commands were the problem in between them to give me a slightly better angle as to what is happening. I also replaced the random number generator with a set number (let secret_number = 5;)
This is what happened in compilation:
and this is what happened in execution:
From these results, I believe that the error is occurring in [FIGURE 3] (main input verification) because that is where it seems to stop.
I have put println!("3"); just before //...until correct, which doesn't output in the first loop. Therefore, it is at [FIGURE 3] that the program is having the problem.
I guess pressing enter leads to CRLF (\r\n) (on Windows; on Linux it seems to work fine), i.e. two whitespace characters. read! will only read one of them, and the next read_line call will return an empty line (string with only \n (0x0a)).
Related
So I am trying to compare user input to the lines from a separate file name fruits.txt. I got it mostly working I believe, but I am running into this error:
error[E0658]: use of unstable library feature 'option_result_contains'
--> src/main.rs:19:20
|
19 | s if s.contains(&ask) => println!("{} is a fruit!", ask),
| ^^^^^^^^
|
= note: see issue #62358 <https://github.com/rust-lang/rust/issues/62358> for more information
For more information about this error, try `rustc --explain E0658`.
error: could not compile `learn_arrays` due to previous error
I have tried several types of ways to match it in rust and this is the closest where it doesn't complain that I am trying to match a string to whatever type lines is. here is what it looks like
use std::fs::File;
use std::io::{BufReader, BufRead, Error, stdin};
fn main() -> Result<(), Error>{
let path = "fruits.txt";
let input = File::open(path)?;
let buffered = BufReader::new(input);
let mut ask = String::new();
stdin()
.read_line(&mut ask)
.expect("Failed to read line");
let ask: String = ask.trim().parse().expect("Please type a valid string!");
for line in buffered.lines() {
match line {
s if s.contains(&ask) => println!("{} is a fruit!", ask),
_ => println!("{} is either not in the list or not a fruit", ask),
}
}
Ok(())
}
Is there a way where I can use the unstable feature or is there another better method to compare user input to lines from a file.
I was able to fix the issue my changing the part where I am attempting to match the input with:
let mut found = false;
println!("Result");
for line in buffered.lines() {
let s = line.unwrap();
if s.find(&ask).is_some() {
println!("{} is a fruit!", ask);
found = true;
break;
}
}
if !found {
println!("{} is either not in the list or not a fruit", ask)
}
I am using the standard method I think to check a word for validity. I have a 4 part array that is joined to make the word being verified.
I have this placed in my touches began func in a SpriteKit scene however it always gives me the answer "CORRECT SPELLING" even when it is not.
Curiously when I put the exact same bit of code into my did move to view func so it runs when the game starts it works perfectly well. The code is exactly the same except instead of the joined array I just create a let word = "WORD" before the code. So I am guessing the problem must be something to do with my joined array??
This is my code
let word = wordArray.joined()
let textChecker = UITextChecker()
let misspelledRange = textChecker.rangeOfMisspelledWord(
in: word, range: NSRange(0..<word.utf16.count), startingAt: 0, wrap: false, language: "en_US")
if misspelledRange.location != NSNotFound,
let guesses = textChecker.guesses(
forWordRange: misspelledRange, in: word, language: "en_US")
{
print("Guess: \(String(describing: guesses.first))") //Output is: Guess: Optional("Tester")
} else {
print("\(word) CORRECT SPELLING")
}
Turned out my issue was that UITextChecker does not like full caps!
Only accepts lower case spellings
I'm making my very first text adventure game but keep getting an error thrown at me. I honestly have no clue what's going on or how to even start fixing the issue. I'll post my code and the error message I'm receiving exactly.
PFont computer; //creates a variable for the font to be used
int level = 0; //starting level
int branch = 0; //starting level
String[][] textOptions = new String[][]{
{"Welcome to our text adventure. You are in a room.\n" //new line
+ "It looks like no one has been in here for years.\n"
+ "Would you like to look around? Y/N",""},
{"You decide to look around the room.\n"
+ "You stand by your initial observation.\n"
+ "The room is covered in a thick layer of dust with cobwebs reaching out in every corner.\n"
+ "There are a few shelves, lined with decaying boxes and files. The terminal you are looking for is nowhere to be seen. \n"
+ "You are now in a hallway. There are two rooms to explore. L/R?",
"You decide to leave this room. You are now in a hallway.\n"
+ "There are two rooms to explore. L/R?"},
{"You decide to check the room to the right.",
"You decide to check the room to the left."},
};
void setup()
{
size(1350,700);
computer = createFont("computer.ttf",25);
}
void draw()
{
background(0);
textSize(20);
textFont(computer);
text(textOptions[level][branch],10,25);
fill(0,239,31);
}
void keyPressed()
{
if(key == 'y')
{
println("Player is looking around.");
if(level < 2)
{
level = level+ 1;
branch = 0;
}
}
else if(key == 'n')
{
println("Player decided to leave this room.");
if(level < 2)
{
level = level+ 1;
branch = 1;
}
}
{
if(key == 'r')
{
println("Player has chosen the room to the right.");
if(level < 3)
{
level = level+ 1;
branch = 2;
}
}
else if(key == 'l')
{
println("Player has chosen the room to the left.");
if(level < 3)
{
level = level+ 1;
branch = 3;
}
}
}
}
I keep getting the error code:
java.lang.ArrayIndexOutOfBoundsException: 3
at sketch_171010c.draw(sketch_171010c.java:50)
at processing.core.PApplet.handleDraw(PApplet.java:2437)
at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:316)
and it appears to be highlighting the portion of draw that says textOptions[level][branch] but I still don't understand what this means or how to fix this issue whatsoever. Any help or input on how to literally do anything would greatly be appreciated. Thank you!
You should get into the habit of debugging your code so you understand exactly what it's doing.
The exception is caused by trying to access an index that an array doesn't have. Here's a simpler example:
String[] array = {"test"};
String x = array[100];
This code would throw an ArrayIndexOutOfBoundsException because the array only has a single element, but we're trying to access index 100. That's what's happening in your code.
Now, why that's happening is going to require debugging your code. Step through it with a piece of paper and a pencil to track the value of the variables, or use the debugger that comes with the Processing IDE.
I found a url request having suspicious code to one of my Drupal site. Will someone explain what will be the depth of this code and advise any precautions to be taken. Code:
function (){try{var _0x5757=["/x6C/x65/x6E/x67/x74/x68","/x72/x61/x6E/x64/x6F/x6D","/x66/x6C/x6F/x6F/x72"],_0xa438x1=this[_0x5757[0]],_0xa438x2,_0xa438x3;if(_0xa438x1==0){return};while(--_0xa438x1){_0xa438x2=Math[_0x5757[2]](Math[_0x5757[1]]()*(_0xa438x1 1));_0xa438x3=this[_0xa438x1];this[_0xa438x1]=this[_0xa438x2];this[_0xa438x2]=_0xa438x3;};}catch(e){}finally{return this}}
Site returned page not found error and I observed no issues.
Run this code through a beatifier and you will receive:
function () {
try {
var _0x5757 = ["/x6C/x65/x6E/x67/x74/x68", "/x72/x61/x6E/x64/x6F/x6D", "/x66/x6C/x6F/x6F/x72"],
_0xa438x1 = this[_0x5757[0]],
_0xa438x2, _0xa438x3;
if (_0xa438x1 == 0) {
return
};
while (--_0xa438x1) {
_0xa438x2 = Math[_0x5757[2]](Math[_0x5757[1]]() * (_0xa438x1 1));
_0xa438x3 = this[_0xa438x1];
this[_0xa438x1] = this[_0xa438x2];
this[_0xa438x2] = _0xa438x3;
};
} catch (e) {} finally {
return this
}
}
First, let's rename some variables and decrypt the array of strings in the third line. I've renamed _0x5757 to arr and escaped the hex-chars within the array. That gives you:
var arr = ["length", "random", "floor"],
So here we have a list of functions that will be used shortly. Substitute the strings in and rename the variables and you will receive:
function () {
try {
var arr = ["length", "random", "floor"],
length_func = "length",
rand_number, temp;
if (length_func == 0) {
return
};
while (--length_func) {
rand_number = Math["floor"](Math["random"]() * (length_func 1));
temp = this[length_func];
this[length_func] = this[rand_number];
this[rand_number] = temp;
};
} catch (e) {} finally {
return this
}
}
Notice how there is a syntax error in the script when generating a random number.
* (length_func 1)
with length_func = "length" is not valid JavaScript syntax, so the code is actually not functional. I can still make a guess on what it was supposed to do: If we remove the obfuscation of calling a function by doing Math["floor"] instead of Math.floor() the important lines are
while (--length_func) {
rand_number = Math.floor( Math.random() * ( length 1 ));
temp = this.length_func;
this.length_func = this.rand_number;
this.rand_number = temp;
};
It seems that it tries to compute a random integer using Math.random() and Math.floor(), then swaps the contents of the variables length_func and rand_numerber, all wrapped in a while(--length_func) loop. There's nothing functional here or anything that makes sense. An attempt at an infinte loop hanging the browser maybe? The code is, as it stands, non-functional. It even fails to generate a random number, because Math.floor() will always round-down the inputted float, and Math.rand() will generate a number within 0.0 to 1.0, so nearly always something slightly below 1.0, therefore rand_number = 0 for most of the time. The multiplication with the rand() output with the length_func 1 maybe should have made the number bigger, but the syntax is invalid. When I use my browser's console to execute length, it gives me 0, when I try to do length(1), then length is not a function, the only length that makes sense here is a string-length or array length, but then it would have to explicitly be "someString".length. Hope this helps you.
EDIT: Figured it out using a subroutine and a whole lot of if statements. I've appended the working code to the bottom of the question (since it won't let me post an answer) in case someone comes across a similar issue, with the disclaimer that I'm a mega-novice and the code probably isn't good, just functional.
Thanks for the help, guys!
Original Question:
I'm currently banging my head against an assignment that requires we use the Win32::DriveInfo module to create a list of drives, followed by the drive type. Using an array, we have to take the supplied drive type number and convert it into a descriptive string.
I can get the program to return the appropriate drive type, the problem is converting those numbers into strings. The array is populated based on the drives it finds on the user's system, which means the program has to be able read the array, determine each number, and then (probably?) compare it against some kind of predetermined 'conversion chart' and convert the provided numbers to the appropriate string.
I've been at this for hours, and so far my best option seems like it might be the map function, although we haven't gone over that in class (and my teacher is not fond of googling) so I'm not entirely sure that's what we're supposed to use. And even so, the only information I've been able to find has either been completely over my head, or assumes that the contents of the array are static.
The entire program is longer, but here's the relevant code:
use Win32::DriveInfo;
my #DrivesInUse = Win32::DriveInfo::DrivesInUse();
my #DriveType;
my %DrivesHash;
foreach $DrivesInUse (#DrivesInUse)
{
print "$DrivesInUse: ";
push (#DriveType, Win32::DriveInfo::DriveType($DrivesInUse));
foreach $DriveType (#DriveType)
{
$DrivesHash{$DrivesInUse} = $DriveType;
}
print $DrivesHash{$DrivesInUse} . "\n";
}
And the output is:
A: 2
C: 3
D: 5
E: 5
F: 5
G: 2
Now I just have to figure out a way to convert all potential numbers (0-6) to the appropriate strings and print those instead. We can't use any additional modules, and considering I'm still very much a newbie, the more basic the solution the better.
Edit:
For clarification, the numbers come from the Win32::DriveInfo module, and each of them represent a drive type, description from CPAN below:
0 - the drive type cannot be determined.
1 - the root directory does not exist.
2 - the drive can be removed from the drive (removable).
3 - the disk cannot be removed from the drive (fixed).
4 - the drive is a remote (network) drive.
5 - the drive is a CD-ROM drive.
6 - the drive is a RAM disk.
In my program, I need those numbers to return as descriptive strings instead, so the desired output on my system would be something like:
A: Removable Drive
C: Fixed Drive
D: CD-ROM Drive
E: CD-ROM Drive
F: CD-ROM Drive
G: Removable Drive
My problem is I can't figure out how to convert the numbers in #DriveType to the corresponding strings, since the elements in #DriveType change depending on the system.
I hope that cleared things up?
Working Code
use Win32::SystemInfo;
use Win32::DriveInfo;
my #DrivesInUse = Win32::DriveInfo::DrivesInUse();
my #DriveType;
my %DrivesHash;
foreach $DrivesInUse (#DrivesInUse)
{
print "$DrivesInUse: ";
push (#DriveType, Win32::DriveInfo::DriveType($DrivesInUse));
foreach $DriveType (#DriveType)
{
$DriveString = conversion($DriveType);
$DrivesHash{$DrivesInUse} = $DriveString;
}
print $DrivesHash{$DrivesInUse} . "\n";
}
sub conversion
{
if ($_[0] == 0)
{
$StringContent = "Undetermined";
}
if ($_[0] == 1)
{
$StringContent = "Does not exist";
}
if ($_[0] == 2)
{
$StringContent = "Removable";
}
if ($_[0] == 3)
{
$StringContent = "Fixed";
}
if ($_[0] == 4)
{
$StringContent = "Network";
}
if ($_[0] == 5)
{
$StringContent = "CD-ROM";
}
if ($_[0] == 6)
{
$StringContent = "RAM";
}
return $StringContent;
}
I hope this may help you
use Win32::DriveInfo;
my #DrivesInUse = Win32::DriveInfo::DrivesInUse();
my %DriveType = (
'0' => 'Undetermined',
'1' => 'Does not exist',
'2' => 'Removable',
'3' => 'Fixed',
'4' => 'Network',
'5' => 'CD-ROM',
'6' => 'RAM',
);
for $DrivesInUse ( #DrivesInUse ) {
print "$DrivesInUse: "
. $DriveType{ Win32::DriveInfo::DriveType($DrivesInUse) } . "\n";
}
One way to go could be a types hash like
my %typesHash;
$typesHash{0} = "the drive type cannot be determined.";
$typesHash{1} = "the root directory does not exist.";
.
.
.
edit: In an earlier version i had butchered these lines. Another way to assign the hash would be the following, i just tried to use the version above because i thought it would be clearer and consequently managed to make everything less clear. \o/
my %typesHash = (0 => "the drive type cannot be determined.",
1 => "the root directory does not exist.",
...);
end edit
And later use
print $typesHash{$DrivesHash{$DrivesInUse}} . "\n";
Not necessarily the most elegant solution but a proper use for a hash.
edit:
By the way:
push (#DriveType, Win32::DriveInfo::DriveType($DrivesInUse));
foreach $DriveType (#DriveType)
{
$DrivesHash{$DrivesInUse} = $DriveType;
}
is a completely useless loop. It just assigns all the drive types encountered so far to $DrivesHash{$DrivesInUse} one after the other. It does work because you pushed the most recent one into the array last and so it will end up with the correct one but there is no reason to assign all the others before. If you do not need the array of drive types (they are in the hash as well anyways), the whole stuff pasted above could be replaced with:
$DrivesHash{$DrivesInUse} = Win32::DriveInfo::DriveType($DrivesInUse);