Introduction
Hi to everyone, this is my first beginner project in Rust, I read the basics on Rust, and I made this game with Rust and some useful crates.
If you want to read or contribute to these project please feel free to do it.
The project is hosted in github at ealvan/battleship ππ
If you want to message me feel free to do it in by this link.
Project porpuse
This game was made because I like this game and I want to learn Rust. When I decided to it, I have read the Rust book until Chapter 7. My main porpuse was apply what I learn in this book and with a favorite game.
Definitions
I think the best way to explain this game it's explaning their definitions I made, from all the methods and function are used.
These are the definitions we need in the game.
- User : This is the user data, in this game there are 2 users.
- Piece: This is the war piece to play, a user can have many of them.
- Point: This is the base point where all the game is centered, because I will play with corrdinates
- Table: The board in which there are multiple points.
What each definitions needs to have?
In this section, I will throw the actual attributes that my definitions have. You can read the comments why I put that attribute.
pub struct User{
pub name: String,//their name
pub my_turn: bool,//is it my turn?
pub pieces: Vec<Piece>,//he own N Pieces
pub n_lives: u8,//the number spots of your pieces are your lives
pub give_up: bool//if they give up on the game
}
pub struct Point{
pub x: i8,//x coordinate
pub y:i8,//y coordinate
pub is_active: bool//is active if it's part of user's pieces
}
pub enum Piece{
//all pieces have their points that refers inside the Table struct
CARRIER(Vec<Point>),
BATTLESHIP(Vec<Point>),
CRUISER(Vec<Point>),
SUBMARINE(Vec<Point>),
DESTROYER(Vec<Point>),
}
//also this Piece needs to have direction struct.
pub enum Direction{
UP,//β¬οΈ
DOWN,//β¬οΈ
LEFT,//β¬
οΈ
RIGHT,//β‘οΈ
UP_RIGHT,//1,1
UP_LEFT,//1,-1
DOWN_LEFT,//-1,-1
DOWN_RIGHT,//-1,1
}
pub struct Table{
pub rows: u8,//the number of rows
pub columns: u8,//the number of columns
pub space: Vec<Point>,//number of points = rows*columns
}
How I handle coordinates?
The most important part of this game is how to handle coordinates in my Table.
As you can see, Table has space vector, which has many points. But I need a table with rows and columns.
To do this, the way I handle this is with this formula:
f(x,y) = self.columns*x + y
For example: I have 3x4 table. I need to find transform (1,3) coordinate to the actual index in the space. So:
- Coordinate: (1,3)
- f(x,y) = self.columns*x + y
- f(1,3) = 4*1 + 3 = 7
I wish this was the best implementation idea, but I think it isn't
Do you mind how we got until now so far?
- Pieces that a User's owns
- Table with owned Points
- A user can draw their pieces
My original idea was take references from Table's points, and take that references as a part of User's Points. So when the User needs to show or check their points, they can do it by each piece. Even I was thinking of mutable references to be placed in User's pieces.
However, I stumble with a big wall when the table cannot be borrowedπ more than one time in a while. So I decided to not borrow table's points.
Now the way it's the following:
- Table has owned points.
- When a User it's created, has empty vector of pieces.
- User use method `draw_pieces` to find free spots on the table to draw their Pieces.
- When finds a valid spots, the User creates points from this spots.
- On the table side, these points from User's pieces are activated: `is_active=True`
Problems solved
These are the problems I solved with the before implementation.
When a User needs to change his points, you can do so by just find the points in the table. And then get their mutable references based on your points. And change what you want.
- When a User attacks, I just need to find the point a see if hits himself(π), hits their enemy or just hit an empty spot. I just take their mutable reference one time at the time. And change what I want.
- When a User attacks, I just need to find the point a see if hits himself(π), hits their enemy or just hit an empty spot. I just take their mutable reference one time at the time. And change what I want.
- And when it hits a User, I did `n_lives -= 1` to minus their lives.
All the implementations after this idea was easier to do, because now I know how it works.
The difficult part: How draw a valid Piece?
When a Piece needs to be draw, Table needs to have free spots, but how I find it?
My solution is:
- Find a random free spot on the table with `find_free_point(&Table) -> Option<&Point>`
- From that point I take a direction from `Direction::get_directions()`.
- I made my piece with this direction.
- Check if these points are free_spots
- 1. If it is, then I change their state to `is_active=True`
- 2. If it isn't, I take anothe direction.
pub fn points_from_root_point(table: & mut Table, spots: i8) -> Result<Vec<Point>, String>{
let directions = Direction::get_directions();
let opportunities = 10;
for _time in 0..opportunities{
let free_spot = match User::find_free_point(table){
Some(point) => point,
None => panic!("There are any free spots")
};
for direction in directions.iter(){
match table.can_be_road((free_spot.x, free_spot.y), spots, direction){
Ok(points) => {
table.change_state(points.iter().collect());
return Ok(points);
},
Err(_) => continue,
};
}
}
return Err(format!("Any directions were sufficient to draw from root point"));
}
If you want to read or contribute to these project please feel free to do it.
The project is hosted in github at ealvan/battleship ππ