Floresta Misteriosa
Para iniciar vamos dar um raio-x sobre nosso primeiro jogo, em a floresta misteriosa o jogador assume um papel de um aventureiro corajoso que se aventura por uma floresta misteriosa. A cada escolha que o jogador faz vão influenciar a sua jornada, dependendo da sua decisão você vai ganhar ou perder pontos se você alcançar 100 pontos você vence o jogo.
Regras
Nosso jogo apresentará um menu ao nosso jogador com as opções que ele pode escolher. Como nosso escopo é pequeno vamos limitar em 4 escolhas.
- Ele pode beber agua no rio onde o jogador vai ganhar 10 pontos.
- Ele pode passar pela ponte frágil onde ele vai perder 20 pontos.
- Ele pode querer entrar na caverna escura ele vai ganhar 50 pontos.
- Ele pode passar pelo caminho iluminado onde vai perder 20 pontos.
Essas escolhas vão aparecendo toda vez que o jogador faz uma escolha até ele ganhar ou perder o jogo. Caso ele consiga 100 pontos o jogador ganha e se o jogador chegar a 0 ele perde.
Criando o projeto
Bom primeiro vamos criar um diretório onde vamos armazenar nossos projetos do curso, minha sugestão é criar um diretório chamado projects. Então vamos abrir um terminal primeiro vamos usar o comando cd
para ir até o diretório Home
do seu computador e depois vamos usar o comando mkdir
para criar um diretório.
cd
mkdir projects
Caso queria se aprofundar sobre os comandos via terminal minha sugestão é dar uma conferida no guia focalinux ele vai lhe ajudar a ter um entendimento melhor do funcionando dos comandos posix mas, vou explicando cada comando no terminal que vamos usar ao decorrer do curso.
Bom agora vamos acessar o diretório que criamos.
cd projects
Agora que acessamos o diretório que vamos trabalho, o próximo passo é criarmos nosso projeto em rust, para criar um projeto em rust vamos usar o comando cargo new
e o nome do nosso projeto é chamado mysterious_forest
. Assim ele vai criar um diretório chamado mysterious_forest
para confirmar-mos se a pasta foi criada vamos usar o comando ls -la
onde o -la
é um parametro apenas para listarmos também os arquivos ocultos.
cargo new mysterious_forest
ls -la
Agora vamos acessar o direorio que criamos no qual podemos acessa-lo através do comando cd mysterious_forest
.
cd mysterious_forest
Agora podemos usar novamente o comando ls -la
para vermos o que o comando cargo criou no nosso projeto.
.git
.gitignore
Cargo.toml
src
Uma observação os arquivos com o .
na frente como o .git
e o .gitignore
são arquivos ocultos no linux.
Bom agora vou dar o comando cargo run
para executar meu projeto.
Assim vamos ter a saída.
➜ cargo run
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `target/debug/mysterious_forest`
Hello, world!
Uma coisa interessante de notar quando executamos um projeto rust é que na primeira linha:
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Nós temos o nome do nosso executável, no caso mysterious_forest
e a versão do nosso executável no caso v0.1.0
.
Na segunda linha temos:
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Aqui temos a informação que nosso executável foi compilado em modo dev e o tempo de compilação no caso 0.12
Na terceira linha temos:
Running target/debug/mysterious_forest
Essa linha nos mostra onde fica nosso executável ele que vamos dar a para que as pessoas possam jogar nosso jogo.
Certo agora vamos entrar no projeto no arquivo no caminho src/main.rs
fn main() {
println!("Hello, world!");
}
Isso é um "Hello, world!" padrão de um projeto rust, então nesse caso não começamos com um "Hello, world!" no projeto pois ele já vem no momento da criação.
Falando de tipagem
A tipagem em programação se refere à maneira como as linguagens de programação tratam os tipos de dados, ou seja, como elas definem e gerenciam os diferentes tipos de valores que podem ser usados em um programa. Rust é uma linguagem de programação que utiliza um sistema de tipagem estática, o que significa que os tipos de dados são verificados em tempo de compilação, tornando o código mais seguro e eficiente. Tipagem Estática
Em Rust, você precisa declarar explicitamente o tipo de dado que uma variável pode armazenar. Isso é feito durante a declaração da variável, permitindo que o compilador verifique se o valor atribuído à variável é compatível com o tipo declarado. Se houver uma incompatibilidade de tipos, o código não será compilado, o que ajuda a evitar erros em tempo de execução. Tipos Primitivos em Rust
Rust possui uma série de tipos primitivos que podem ser usados para representar diferentes tipos de dados. Vamos dar uma olhada nos tipos primitivos mais comuns em Rust: 1. Integer Types (Tipos Inteiros)
Os tipos inteiros em Rust representam números inteiros sem parte fracionária. Aqui estão alguns dos tipos inteiros mais comuns, junto com sua faixa de valores:
i8: Intervalo de -128 a 127.
i16: Intervalo de -32,768 a 32,767.
i32: Intervalo de -2,147,483,648 a 2,147,483,647.
i64: Intervalo de -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807.
i128: Intervalo extremamente grande de números inteiros com sinal.
Por exemplo, você pode declarar uma variável inteira em Rust da seguinte forma:
rust
let numero: i32 = 42;
Os tipos inteiros sem sinal, representados com u, têm os mesmos tamanhos que os tipos inteiros com sinal e representam apenas valores não negativos. Por exemplo, u8 varia de 0 a 255, u16 varia de 0 a 65,535 e assim por diante. 2. Floating-Point Types (Tipos de Ponto Flutuante)
Os tipos de ponto flutuante em Rust representam números com parte fracionária. Os tipos mais comuns são:
f32: Representa números de ponto flutuante de precisão simples.
f64: Representa números de ponto flutuante de dupla precisão (mais precisos).
Exemplo:
rust
let pi: f64 = 3.14159;
- Boolean Type (Tipo Booleano)
O tipo booleano em Rust é usado para representar valores verdadeiro (true) ou falso (false). É frequentemente usado em expressões condicionais e lógicas.
Exemplo:
rust
let esta_chovendo: bool = true;
- Character Type (Tipo de Caractere)
Rust também possui um tipo de caractere chamado char, que representa um único caractere Unicode. Isso é útil para lidar com texto e caracteres especiais.
Exemplo:
rust
let letra: char = 'A';
- String Type (Tipo de Texto)
Rust diferencia entre dois tipos relacionados: str e String.
str: Representa uma sequência de caracteres imutável (não pode ser modificada após a criação) e é frequentemente usado com referências (&str) para manipulação de texto eficiente.
String: Representa uma sequência de caracteres mutável (pode ser modificada) e é mais flexível, geralmente alocada na memória de forma dinâmica.
Exemplo:
rust
let texto_estatico: &str = "Isso é um texto imutável";
let mut texto_mutavel: String = String::from("Isso é um texto mutável");
Essa é uma explicação mais abrangente sobre a tipagem em Rust, os tipos primitivos mais comuns e a diferença entre str e String. À medida que você se familiariza mais com Rust, poderá explorar tipos compostos, structs, enums e outros recursos poderosos que a linguagem oferece para lidar com problemas específicos de programação.
Variaveis
Bom para começar nosso jogo precisamos definir algumas estruturas de dados que vão armazenar a pontuação do nosso jogador e o qual escolha ele vai fazer em seguida, pra isso vamos precisar criar variáveis.
As variáveis em rust são declarados usando a palavra reservada let
o nome da variável e o tipo dela além do seu valor de inicialização.
Uma váriavel em rust é diferente de outras linguagens pois ela é imutável ou seja quando inicializamos ela, a mesma não altera seu valor, há uma forma de informar explicitamente que queremos que a variável receba valores dinamicamente mas, vamos ver mais a frente.
Então agora dentro do nosso main vamos declarar a primeira variável do nosso projeto.
fn main() {
let pontuacao: i32 = 0;
}
```
Vamos da uma olhada mais de perto no nosso código:
`fn` é a palavra reservada para declarar uma função
`main` é o nome da nossa função e os parenteses `()` é a estrutura que usamos para declarar os parametros da nossa função que no caso não temos nenhum então ela está vazia.
Para simplificar um pouco as coisas parametros nada mais é que as variáveis que uma função vai receber quando ela for executada, mas não tema em um outor momento vamos falar mais de funções e parametros.
`{}` determina um bloco de código então o que estiver ali dentro vai ser o código que será executado pela nossa função main.
`let pontuacao: i32 = 0;` aqui declaramos nossa variável começando com a palavra reservada `let` depois o nome da variável que no caso é `pontuacao` o tipo dela que no nosso caso é um `i32` ai temos o `=` que o nosso simbulo de atribuição ou seja, que `pontuacao` vai receber um valor, na sequencia temos o valor que estamos inicializando que no caso é o valor `0` e finalmente temos o simbulo `;` que indica pro compilador que a linha de execução foi encerrada finalizando a instrução.
Com isso podemos criar nossa segunda variável:
```rust
fn main() {
let pontuacao: i32 = 0;
let escolha: i32 = 1;
}
Então criamos uma variavel escolha que também é uma i32
só que agora colocamos como valor incial 1
.
Para dar sequência no nosso projeto vamos criar uma mensagem de boas-vindas, pra isso vamos usar uma macro no rust que nada mais é que uma sequência de instruções que vão rodar internamente quando ela for executada que no nosso caso é o println!
o !
no final nos indica que ela é uma macro.
fn main() {
let pontuacao: i32 = 0;
let escolha: i32 = 1;
==println!("Bem-vindo à floresta misteriosa")==
}
Um ponto importante pra se observar nós não usamos o simbolo ;
no final da nossa macro println!
isso por que em rust dentro de um bloco de código a ultima linha não precisa ter esse simbolo pois ele interpreta essa última linha como o valor a se retornar da função no nosso caso porém estamos executando uma macro que vai imprimir valores na tela então ele basicamente não está retornando nada.
Você pode observar que dentro dos parenteses da nossa macro temos os simbolos de aspas ""
e dentro delas colocamos nosso texto com acentos. Como o rust usa o padrão unicode para caracteres podemos usar qualquer simbolo ou diagrama representado pela tabela unicode. Mas, no nosso código em si nós evitamos usar acentos e caracteres especiais.
Agora vamos imprimir na tela o valor da nossa escolha e a pontuação pra isso vamos usar novamente a macro println!
.
fn main() {
let pontuacao: i32 = 0;
let escolha: i32 = 1;
println!("Bem-vindo à floresta misteriosa");
==
println!("A sua escolha foi {}", escolha);
println!("A sua pontuação foi {}", pontuacao)
==
}
Observe que só deixamos sem o ;
a ultima linha por isso no nosso primeiro println!
agora tem a pontuação. Outra coisa é que nosso código está usando a macro de uma forma diferente.
Temos o simbolo das chaves {}
dentro das aspas, isso indica que queremos imprimir o valor de uma variável que no nosso caso são as variáveis escolha
e pontuacao
. No caso se quisermos colocar mais variáveis dentro de uma string que é o caso do nosso println!
podemos usar mais chaves que ele vai entender.
Agora podemos rodar novamente o cargo run
para ver o retorno da nossa função.
➜ cargo run
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
A sua escolha foi 1
A sua pontuação foi 0
Perfeito tudo funcionando!
Controle de fluxo condicional com if
Vamos da uma olhada agora em como dar escolhas para nosso jogador. Primeiro vamos colocar um println!
pedindo a escolha e 4 opções númericas para ele escolher.
\\ código
println!("Bem-vindo à floresta misteriosa");
println!("Por favor escolha uma opção:");
println!("1 - Entrar na caverna escura");
println!("2 - Seguir no caminho iluminado");
println!("3 - Cruzar a ponte frágil");
println!("4 - Descansar na beira do riacho");
\\código
Agora precisamos de um recurso que nos mostre que quando digitarmos no teclado a opção 1 ele faça a ação Entrar na caverna escura
e assim com as demais opções e quando ele escolher a opção faça a soma ou a subtração dos pontos. Pra isso vamos usar o if
ele é nosso primeiro condicional e com ele podemos fazer que com determinada escolha ele faça uma sequencia de ações no nosso caso se o jogador escolher a opção 1 precisa realizar a ação de somar 50 pontos na pontuação atual.
\\código
println!("4 - Descansar na beira do riacho");
if escolha == 1 {
pontuacao = pontuacao + 50;
}
\\código
Vamos ter um erro mas, vamos ignora-lo por enquanto, agora precisamos colocar as outras condições então usamos a palavra reservada if
e poderiamos ficar usando ela para as demais opções mas, há um problema, nosso código usando 4 if's
nesse caso ele vai verificar todas 4 vezes em todos os casos. Então podemos usar um outro recurso que é o senão se que basicamente vai verificar a primeira condição e se ela não for verdade e vai verificar a próxima condição e assim sucessivamente.
O código ficaria assim:
fn main() {
let pontuacao: i32 = 0;
let escolha: i32 = 1;
println!("Bem-vindo à floresta misteriosa");
println!("Por favor escolha uma opção:");
println!("1 - Entrar na caverna escura");
println!("2 - Seguir no caminho iluminado");
println!("3 - Cruzar a ponte frágil");
println!("4 - Descansar na beira do riacho");
==
if escolha == 1 {
pontuacao = pontuacao + 50;
} else if escolha == 2 {
pontuacao = pontuacao - 20;
} else if escolha == 3 {
pontuacao = pontuacao - 20;
} else if escolha == 4 {
pontuacao = pontuacao + 10;
}
==
println!("A sua escolha foi {}", escolha);
println!("A sua pontuação foi {}", pontuacao)
}
Agora vamos rodar nosso código ele vai receber um erro igual o abaixo:
error[E0384]: cannot assign twice to immutable variable `pontuacao`
--> src/main.rs:20:9
|
2 | let pontuacao: i32 = 0;
| ---------
| |
| first assignment to `pontuacao`
| help: consider making this binding mutable: `mut pontuacao`
...
20 | pontuacao = pontuacao + 10;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
Aqui ele está dizendo que não pode mudar uma variável imutável e é isso que vamos explorar a seguinte.
Introdução a váriaveis e imutabilidade
Se você está começando a aprender sobre programação, é importante entender o que são variáveis e constantes em Rust, uma linguagem de programação moderna e segura. Vamos explorar esses conceitos e suas implicações, incluindo exemplos de constantes. Variáveis em Rust
Uma variável em Rust é uma forma de armazenar e manipular dados em um programa. É como uma caixa que você pode usar para guardar informações temporariamente. No entanto, Rust difere de muitas outras linguagens de programação em um aspecto fundamental: por padrão, as variáveis são imutáveis, o que significa que não podem ser alteradas após a primeira atribuição.
Por exemplo, considere o seguinte código:
rust
let nome = "Alice";
nome = "Bob"; // Isso geraria um erro de compilação!
Neste exemplo, a tentativa de mudar o valor de nome para "Bob" resultaria em um erro de compilação. Isso ocorre porque, por padrão, Rust preza pela segurança e evita que você modifique dados acidentalmente. A Palavra Reservada mut
Mas e se você quiser que uma variável seja mutável, ou seja, que possa ser alterada? É aí que entra a palavra reservada mut. Quando você declara uma variável com a palavra-chave mut, você está indicando explicitamente que a variável pode ser modificada.
Exemplo:
rust
let mut contador = 0;
contador = contador + 1; // Isso é permitido, pois 'contador' é mutável
Neste caso, contador é uma variável mutável, e você pode aumentar seu valor sem problemas. Constantes em Rust
Além de variáveis, Rust também oferece o conceito de constantes. As constantes são valores imutáveis que são definidos em tempo de compilação. Elas são declaradas usando a palavra-chave const e sempre devem ter um tipo de dado específico.
Exemplo:
rust
const PI: f64 = 3.14159;
Aqui, PI é uma constante que representa o valor de π (pi) com uma precisão de ponto flutuante de dupla precisão (f64). Essa constante não pode ser alterada após sua definição e é acessível em todo o escopo em que está definida. Vantagens e Desvantagens da Imutabilidade por Padrão
A abordagem de imutabilidade por padrão em Rust oferece algumas vantagens importantes: 1. Segurança:
Evita erros comuns relacionados à mutação de dados, como condições de corrida (race conditions) em programas concorrentes.
Facilita a previsibilidade do código, uma vez que você não precisa se preocupar com efeitos colaterais inesperados.
-
Melhora a Legibilidade:
Torna o código mais fácil de entender, uma vez que você sabe que uma variável não será alterada em lugares inesperados.
-
Facilita a Concorrência:
Permite que Rust garanta a segurança na concorrência, pois a imutabilidade reduz o risco de acesso concorrente a dados mutáveis.
No entanto, essa abordagem também pode ter desvantagens, como: 1. Mais Digitação:
Pode ser necessário digitar mais código para criar variáveis mutáveis quando necessário.
-
Curva de Aprendizado:
Pode levar algum tempo para se acostumar com a imutabilidade por padrão, especialmente se você está familiarizado com linguagens que não a adotam.
Outras Linguagens com Características Semelhantes
Algumas outras linguagens de programação também adotam a imutabilidade por padrão ou oferecem suporte a variáveis imutáveis:
Haskell
Elm
Clojure
Em resumo, variáveis e constantes em Rust têm a característica única de serem imutáveis por padrão, proporcionando segurança e legibilidade. A palavra-chave mut permite que você torne variáveis mutáveis quando necessário, mantendo o controle sobre a mutabilidade dos dados em seu código. Rust também suporta constantes, que são valores imutáveis definidos em tempo de compilação. Essa abordagem pode ser diferente de outras linguagens, mas traz benefícios significativos em termos de segurança e concorrência.
É importante reforçar que com isso você pode usar uma variável imutável durante a maior parte da execução e quando ela precisar ser alterada redeclarar ela como mutável mais a frente vamos falar do conceito de como funciona o gerenciamente de memória do rust e isso vai acabar ficando mais claro.
Variáveis e mutabilidade
Bom conforme vimos anteriormente nosso código estava dando erro pois o rust acusava que estavamos tentando mudar uma variável imutável. Isso acontece por que em rust todas as variáveis por padrão são imutáveis, então não podemos modifica-la depois inicializar ela.
Para isso vamos precisamos indicar pro rust que nossa variável é mutável usando a palavra reservada mut
depois do let
.
fn main() {
==let mut pontuacao: i32 = 0;==
let escolha: i32 = 1;
// código
}
Agora você pode ver que seu editor deve parar de dar algum aviso de erro. Vamos tentar rodar nosso código.
mysterious_forest on main [?] is 📦 v0.1.0 via 🦀 v1.73.0 on ☁️ (eu-west-2) took 4m4s
➜ cargo run
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
Por favor escolha uma opção:
1 - Entrar na caverna escura
2 - Seguir no caminho iluminado
3 - Cruzar a ponte frágil
4 - Descansar na beira do riacho
A sua escolha foi 1
A sua pontuação foi 50
Certo agora nosso código foi executado com sucesso mostrando que nossa pontuação foi 50.
Recebendo parametros do jogador e usando a condicional match
Bom nosso jogo está nos devolvendo a pontuação da nossa escolha, mas nosso jogador ainda não consegue nos passar a opção que ele quer, então pra isso vamos precisar receber os dados do usuário isso quer dizer que precisamos pedir pro rust pedir o input do teclado do usuário. Pra isso vamos importar uma biblioteca que existe dentro do built in do rust ou seja uma biblioteca que ele já nos fornece por padrão pra ser usada.
Para importa-la precisamos usar a palavra reservada use
chamar a biblioteca que queremos que no caso é a std
que á biblioteca standard do rust, e no caso eu quero um módulo especifico da biblioteca e não ela toda pra chamar o módulo precisamos usar o simbolo ::
para indicar que vamos selecionar um módulo e escolhe-lo que no caso é o módulo io
.
Nosso código ficaria assim:
use std::io;
Agora vamos precisar criar uma variável mutavel para receber a escolha do nosso usuário, no caso a escolha de um usuário sempre será uma sequencia de caracteres no caso podemos incializa-la com uma String
vazia conforme abaixo:
//código
println!("4 - Descansar na beira do riacho");
==let mut escolha_str: String = String::new();==
if escolha == 1 {
//código
Aqui usamos o simbolo ::
para chamar um método associado chamado new
dentro da Struct
chamada String
que é uma sequência de caracteres.
Agora vamos usar o módulo io
e chamar duas funções a stdin
e a read_line
, nesse primeiro momento não precisa se preocupar muito com a chamada que vou fazer, mas atente-se que vou colocar como parametro de read_line
nossa variável escolha_str
mais a frente vamos explicar com mais detalhes como funciona essa chamada que vamos fazer.
// código
let mut escolha_str: String = String::new();
==io::stdin().read_line(&mut escolha_str);==
if escolha == 1 {
// código
Agora vamos fazer um println!
para imprimir o que o usuário escolheu no meu caso vou escolha a opção 4
.
// código
io::stdin().read_line(&mut escolha_str);
==println!("Escolha str é {}", escolha_str);==
if escolha == 1 {
// código
Com a saída:
warning: `mysterious_forest` (bin "mysterious_forest") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
Por favor escolha uma opção:
1 - Entrar na caverna escura
2 - Seguir no caminho iluminado
3 - Cruzar a ponte frágil
4 - Descansar na beira do riacho
5
Escolha str é 4
A sua escolha foi 1
A sua pontuação foi 50
Atente-se que a escolha é ainda 1 mas, a escolha str foi 4.
Agora quero que meu escolha receba o valor de escolha_str, porém o escolha_str é uma String
e o escolha é um i32
. Então pra conseguir fazer o que quero vou mudar minha variável escolha para u32
para não receber número negativos e vou converter minha String
para isso preciso remover espaços e quebras de linha e pra isso uso a função trim
e depois chamo a função parse
que vai tentar converter pro tipo da variável que quero.
É importante ressalta que a função parse
vai me voltar um Rusult
que é uma estrutura no formato abaixo:
(OK, Err)
Onde OK
vai ter o valor do parse caso de certo e em Err
vai voltar o erro caso ocorra um erro. Essa estrutura nunca vai voltar os dois valores. Pois ele ou vai retornar um valor do tipo OK
ou um valor do tipo Err
assim não precisando ter recursos como o null de algumas linguagens.
Então vamos mover nosso escolha para abaixo de escolha_str e fazer o parse.
println!("Escolha str é {}", escolha_str);
==let escolha: i32 = escolha_str.trim().parse();==
if escolha == 1 {
No caso como o parse
vai nos retornar ou OK
ou Err
eu quero que quando vier um erro nossa escolha receba o valor 0
.
Poderiamos fazer isso com um if
que nossa estrutura condicional que já conhecemos, mas, nesse momento quero lhe mostrar outra estrutura que no caso é o match
.
//código
println!("Escolha str é {}", escolha_str);
let escolha: i32 = match escolha_str.trim().parse() {
Ok(num) => num,
Err(_) => 0,
};
if escolha == 1 {
Sua estrutura é:
match <condição> {
possivel retorno => retorno do código,
possivel retorno 2 => retorno do código,
...
possível retorno n => retorno do código
}
Outro ponto é o simbolo _
que é um coringa o que quer dizer que não importa o valor que vir ele vai considerar ele um valor válido é como uma condição "Se tudo que foi verificado antes não deu certo me use".
Tudo certo agora vamos rodar nosso código.
Agora nossa saída fica assim:
``bash
warning:
mysterious_forest(bin "mysterious_forest") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
Running
target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
Por favor escolha uma opção:
1 - Entrar na caverna escura
2 - Seguir no caminho iluminado
3 - Cruzar a ponte frágil
4 - Descansar na beira do riacho
4
Escolha str é 4
A sua escolha foi 4 A sua pontuação foi 10
## Trabalhando com loop
Bom agora a primeira coisa que quero fazer é parar de dar o warning na linha onde capturamos a entrada do jogador pra isso vamos fazer uma alteração no código:
```rust
let _ = io::stdin().read_line(&mut escolha_str);
Há outras formas de resolver isso mas, nesse momento vamos fazer esse que é o mais simples. Agora vamos fazer nossa condição de vitória e derrota.
// main.rs
use std::io;
fn main() {
let mut pontuacao: i32 = 0;
println!("Bem-vindo à floresta misteriosa");
println!("Por favor escolha uma opção:");
println!("1 - Entrar na caverna escura");
println!("2 - Seguir no caminho iluminado");
println!("3 - Cruzar a ponte frágil");
println!("4 - Descansar na beira do riacho");
let mut escolha_str: String = String::new();
let _ = io::stdin().read_line(&mut escolha_str);
let escolha: i32 = match escolha_str.trim().parse() {
Ok(num) => num,
Err(_) => 0,
};
if escolha == 1 {
pontuacao = pontuacao + 50;
} else if escolha == 2 {
pontuacao = pontuacao - 20;
} else if escolha == 3 {
pontuacao = pontuacao - 20;
} else if escolha == 4 {
pontuacao = pontuacao + 10;
}
==
if pontuacao >= 100 {
println!("Parabéns você é um verdadeiro aventureiro!");
} else if pontuacao <= 0 {
println!("Que pena você perdeu");
}
println!("Obrigado por jogar 'A floresta misteriosa!'")
==
}
Aqui eu fiz um if verificando se a pontuação é maior ou igual a 100 coloco um print parabenizando pela vitória ou se a pontuação for menor ou igual a zero informando a derrota. Há também mais um print para informar o fim do jogo além de ter tirado nosso println! para escolha str.
Agora podemos rodar nosso jogo e ver a condição de derrota já que a de vitória ainda não vamos conseguir por conta da pontuação.
✦ ➜ cargo run
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Finished dev [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
Por favor escolha uma opção:
1 - Entrar na caverna escura
2 - Seguir no caminho iluminado
3 - Cruzar a ponte frágil
4 - Descansar na beira do riacho
3
Obrigado por jogar 'A floresta misteriosa!'
[!info] Condicionais
Vale ressaltar que podemos usar
==
para verificar igualdades,!=
para verificar >diferenças,<=
para verificar se é menor ou igual,>=
para verificar se é maior ou igual assim como<
e>
para verificar se é menor e igual respectivamente.
Agora vamos por 100 na ultima opção para conseguirmos testar nossa condição de vitória.
} else if escolha == 4 {
pontuacao = pontuacao + 100;
}
Agora podemos testar.
mysterious_forest on main [?] is 📦 v0.1.0 via 🦀 v1.76.0 on ☁️ (eu-west-2) took 11s
✦ ➜ cargo run
Compiling mysterious_forest v0.1.0 (/home/feanor/projects/mysterious_forest)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `target/debug/mysterious_forest`
Bem-vindo à floresta misteriosa
Por favor escolha uma opção:
1 - Entrar na caverna escura
2 - Seguir no caminho iluminado
3 - Cruzar a ponte frágil
4 - Descansar na beira do riacho
4
Parabéns você é um verdadeiro aventureiro!
Obrigado por jogar 'A floresta misteriosa!'
Certo agora temos nossa condição de vitória e derrota funcionando, mas basicamente nosso jogo por enquanto só podemos escolher uma opção e o jogo acaba. Então precisamos de uma forma de pode escolher repetidas vezes. Primeiro vamos ajustar nossa pontuação inicial e o ganho e perda da pontuação do jogo.
use std::io;
fn main() {
let mut pontuacao: i32 = 50;
println!("Bem-vindo à floresta misteriosa");
println!("Por favor escolha uma opção:");
println!("1 - Entrar na caverna escura");
println!("2 - Seguir no caminho iluminado");
println!("3 - Cruzar a ponte frágil");
println!("4 - Descansar na beira do riacho");
let mut escolha_str: String = String::new();
let _ = io::stdin().read_line(&mut escolha_str);
let escolha: i32 = match escolha_str.trim().parse() {
Ok(num) => num,
Err(_) => 0,
};
if escolha == 1 {
pontuacao = pontuacao + 30;
} else if escolha == 2 {
pontuacao = pontuacao - 20;
} else if escolha == 3 {
pontuacao = pontuacao - 20;
} else if escolha == 4 {
pontuacao = pontuacao + 10;
}
if pontuacao >= 100 {
println!("Parabéns você é um verdadeiro aventureiro!");
} else if pontuacao <= 0 {
println!("Que pena você perdeu");
}
println!("Obrigado por jogar 'A floresta misteriosa!'")
}
Agora não conseguimos chegar nem a 100 e nem a 0 na primeira escolha, agora precisamos de algo que ajude nosso jogo a se repetir para isso vamos usar uma estrutura chamada loop
.
use std::io;
fn main() {
let mut pontuacao: i32 = 50;
println!("Bem-vindo à floresta misteriosa");
==loop
println!("Por favor escolha uma opção:");
println!("1 - Entrar na caverna escura");
println!("2 - Seguir no caminho iluminado");
println!("3 - Cruzar a ponte frágil");
println!("4 - Descansar na beira do riacho");
let mut escolha_str: String = String::new();
let _ = io::stdin().read_line(&mut escolha_str);
let escolha: i32 = match escolha_str.trim().parse() {
Ok(num) => num,
Err(_) => 0,
};
if escolha == 1 {
pontuacao = pontuacao + 30;
} else if escolha == 2 {
pontuacao = pontuacao - 20;
} else if escolha == 3 {
pontuacao = pontuacao - 20;
} else if escolha == 4 {
pontuacao = pontuacao + 10;
}
if pontuacao >= 100 {
println!("Parabéns você é um verdadeiro aventureiro!");
==break;==
} else if pontuacao <= 0 {
println!("Que pena você perdeu");
==break;==
}
==
println!("Obrigado por jogar 'A floresta misteriosa!'")
}
No código acima envolvelmos a lógica do nosso jogo dentro do loop
com o bloco de código {}
evitando as mensagens de vitória e derrota.
Se deixarmos só o loop
nosso código iria rodar infinitamente, então precisamos definir uam condição para ele parar e no nosso caso podemos usar nossa condição de vitória/derrota, para isso depois da mensagens usamos a palavra reservada break
.
Agora se rodarmos nosso jogo com cargo run
nosso jogo já está funcionando perfeitamente.
Alguns ajustes
Vamos fazer algumas melhorias no código, primeiro vou simplicicar a soma e subtração da nossa pontuação usando a expressão +=
e -=
.
if escolha == 1 {
pontuacao += 30;
} else if escolha == 2 {
pontuacao -= 20;
} else if escolha == 3 {
pontuacao += 20;
} else if escolha == 4 {
pontuacao += 10;
}
Agora vamos por alguma mensagem de feedback pro jogador saber se ele está fazendo uma ação correta ou não.
if escolha == 1 {
==println!("Você entrou na caverna escura e econtrou um tesouro parabéns!");==
pontuacao += 30;
} else if escolha == 2 {
==println!("Você encontrou um Ogro poderoso, mas com sorte conseguiu escapar!");==
pontuacao -= 20;
} else if escolha == 3 {
==println!("A ponte se quebrou com sorte você conseguiu nadar de volta para a margem!");==
pontuacao += 20;
} else if escolha == 4 {
==println!("Você conseguiu recuperar um pouco das suas forças!");==
pontuacao += 10;
}
Agora se rodarmos o feedback ficou muito mais fácil pro jogador.
Como desafio tente colocar uma opção de jogar novamente o jogo com a opção S/N.
Com isso finalizamos nosso primeiro jogo em Rust, agora você pode tentar fazer os desafios abaixo.
Exercicíos sugeridos
Aqui vou colocar os projetos para você fazer suas revisões, muitas vezes os desafios poderão não ser jogos infelizmente, mas estarei disponível no forum ou no Revolt para tirar dúvidas.
Revisão 1
- Crie um programa em Rust que simule o controle de estoque de uma loja, faça simples só com um unico produto utilizando variáveis para armazenar a quantidade do produto e permitindo a atualização dos valores de estoque de forma mutável.
Revisão 2
- Desenvolva um programa que calcule o fatorial de um número inserido pelo usuário. Utilize uma variável mutável para armazenar o resultado parcial do cálculo.
Revisão 3
- Crie um programa que simule uma calculadora simples em Rust, permitindo que o usuário realize operações de adição, subtração, multiplicação e divisão. Utilize variáveis mutáveis para armazenar os valores inseridos pelo usuário e o resultado das operações.
Revisão 4 - Implemente um programa em Rust que converta temperaturas entre Celsius e Fahrenheit. Utilize variáveis mutáveis para armazenar os valores e permitir que o usuário escolha a conversão desejada.