Initial commit

This commit is contained in:
Guilleag01
2023-08-06 17:40:50 +02:00
commit cd6624be37
42 changed files with 796 additions and 0 deletions

77
src/app.rs Normal file
View File

@@ -0,0 +1,77 @@
use serde::{Deserialize, Serialize};
// use serde_wasm_bindgen::to_value;
use wasm_bindgen::prelude::*;
// use web_sys::EventTarget;
// use wasm_bindgen_futures::spawn_local;
use yew::{prelude::*, html::Scope};
use log::info;
use wasm_bindgen::JsValue;
use minesweeper_ui::components::{button::Button, board::BoardComponent};
use minesweeper_ui::minesweeper::{cell::Cell, board::Board, Game};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "tauri"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
pub enum Msg {
Discover{cell: Cell}
}
pub struct App {
link: Scope<Self>,
game: Game
}
// #[function_component(App)]
// pub fn app() -> Html {
// html! {
// }
// }
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
let mut game = Game::new(25, 40, 50);
game.start_board();
info!("\n{}", game.get_board().to_string());
Self {
link: ctx.link().clone(),
game
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let b = self.game.get_board().clone();
html!{
<main class="container">
<BoardComponent onsignal={self.link.callback(|cell| Msg::Discover{cell})} board={b}/>
</main>
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Discover {cell} => {
// info!("Pos (from App): {}", format!("{:?}", cell.get_pos()));
self.game.show(cell.get_pos());
// info!("celhid (from App): {}", format!("{:?}", self.game.get_cell(cell.get_pos()).is_hidden()));
info!("\n{}", self.game.get_board().to_string())
}
}
true
}
}

77
src/components/board.rs Normal file
View File

@@ -0,0 +1,77 @@
use yew::{prelude::*, html::Scope};
use crate::minesweeper::{board::Board, cell::Cell};
use crate::components::button::Button;
use log::info;
use wasm_bindgen::JsValue;
pub struct BoardComponent {
link: Scope<Self>,
board: Board,
onsignal: Callback<Cell>
}
pub enum Msg {
Discover{ cell: Cell },
}
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub board: Board,
pub onsignal: Callback<Cell>,
}
impl Component for BoardComponent {
type Message = Msg;
type Properties = Props;
fn create(ctx: &Context<Self>) -> Self {
Self {
link: ctx.link().clone(),
board: ctx.props().board.clone(),
onsignal: ctx.props().onsignal.clone()
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let b = ctx.props().board.get_board().to_owned();
html! {
<div class="board">
{b.into_iter().map( |row| {
html! {
<>
{row.into_iter().map(|c| {
html! {
<Button onsignal={self.link.callback(move |_| Msg::Discover{cell: c})} cell={c}/>
}
}).collect::<Html>()}
<br/>
</>
}
}).collect::<Html>()}
</div>
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Discover {cell} => {
// info!("Pos (from board): {}", format!("{:?}", cell.get_pos()));
self.onsignal.emit(cell)
}
}
true
}
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
self.board = ctx.props().board.clone();
self.onsignal = ctx.props().onsignal.clone();
true
}
}

61
src/components/button.rs Normal file
View File

@@ -0,0 +1,61 @@
use yew::{prelude::*, html::Scope};
use crate::minesweeper::cell::Cell;
use log::info;
use wasm_bindgen::JsValue;
pub struct Button {
link: Scope<Self>,
cell: Cell,
onsignal: Callback<Cell>,
}
pub enum Msg {
Clicked,
}
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub cell: Cell,
pub onsignal: Callback<Cell>,
}
impl Component for Button {
type Message = Msg;
type Properties = Props;
fn create(ctx: &Context<Self>) -> Self {
Self {
link: ctx.link().clone(),
cell: ctx.props().cell.clone(),
onsignal: ctx.props().onsignal.clone()
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
html!{
<button class={if self.cell.is_hidden() {"button-hidden"} else {"button-shown"} } onclick={self.link.callback(|_| Msg::Clicked)}>
{ &self.cell.to_string() }
</button>
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Clicked => {
// info!("hid (from cell): {}", format!("{:?}", self.cell.is_hidden()));
self.onsignal.emit(self.cell)
}
}
true
}
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
self.cell = ctx.props().cell.clone();
self.onsignal = ctx.props().onsignal.clone();
true
}
}

2
src/components/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod button;
pub mod board;

2
src/lib.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod minesweeper;
pub mod components;

8
src/main.rs Normal file
View File

@@ -0,0 +1,8 @@
mod app;
use app::App;
fn main() {
wasm_logger::init(wasm_logger::Config::default());
yew::Renderer::<App>::new().render();
}

107
src/minesweeper/board.rs Normal file
View File

@@ -0,0 +1,107 @@
use super::cell::Cell;
#[derive(Clone, PartialEq)]
pub struct Board {
board: Vec<Vec<Cell>>,
height: usize,
width: usize,
num_mines: usize
}
impl Board {
pub fn new(height: usize, width: usize, num_mines: usize) -> Self {
let mut t: Vec<Vec<Cell>> = Vec::new();
for i in 0..height {
t.push(Vec::new());
for j in 0..width {
t[i].push(Cell::new((i, j)))
}
}
return Self {
board: t,
height,
width,
num_mines
};
}
pub fn calculate_value(&self, pos: (usize, usize)) -> usize {
let mut value: usize = 0;
for i in -1..=1 {
for j in -1..=1 {
let new_pos: (isize, isize) = ((pos.0 as isize) + i, (pos.1 as isize) + j);
if new_pos.0 >= 0 && new_pos.0 < (self.height as isize) && new_pos.1 >= 0 && new_pos.1 < (self.width as isize) {
value += self.is_mine((new_pos.0 as usize, new_pos.1 as usize)) as usize;
}
}
}
return value;
}
pub fn get_board(&self) -> &Vec<Vec<Cell>> {
return &self.board;
}
pub fn set_mine(&mut self, pos: (usize, usize), value: bool) {
self.board[pos.0][pos.1].set_mine(value);
}
pub fn get_height(&self) -> usize {
return self.height;
}
pub fn get_width(&self) -> usize {
return self.width;
}
pub fn get_num_mines(&self) -> usize {
return self.num_mines;
}
pub fn is_mine(&self, pos: (usize, usize)) -> bool {
return self.board[pos.0][pos.1].is_mine();
}
pub fn get_value(&self, pos: (usize, usize)) -> usize {
return self.board[pos.0][pos.1].get_value();
}
pub fn get_cell(&self, pos: (usize, usize)) -> Cell {
return self.board[pos.0][pos.1];
}
pub fn set_value(&mut self, pos: (usize, usize), new_value: usize) {
return self.board[pos.0][pos.1].set_value(new_value)
}
pub fn show_cell(&mut self, pos: (usize, usize)) {
self.board[pos.0][pos.1].show();
}
}
impl ToString for Board {
fn to_string(&self) -> String {
let mut result = String::new();
result.push_str(" ");
for i in 0..self.width {
// result.push_str(" ");
result.push_str(i.to_string().as_str());
}
result.push_str("\n");
for i in 0..self.height {
result.push_str(i.to_string().as_str());
result.push_str(" ");
for j in 0..self.width {
result.push_str(self.get_cell((i, j)).to_string().as_str());
}
result.push_str("\n");
}
return result;
}
}

72
src/minesweeper/cell.rs Normal file
View File

@@ -0,0 +1,72 @@
#[derive(Clone, Copy, PartialEq)]
pub struct Cell {
pos: (usize, usize), // (height, width)
mine: bool,
value: usize,
hidden: bool,
flagged: bool
}
impl Cell {
pub fn new(pos: (usize, usize)) -> Self {
return Self {
pos,
mine: false,
value: 0,
hidden: true,
flagged: false
};
}
pub fn get_pos(&self) -> (usize, usize) {
return self.pos;
}
pub fn is_mine(&self) -> bool {
return self.mine;
}
pub fn set_mine(&mut self, new_mine: bool) {
self.mine = new_mine;
}
pub fn get_value(&self) -> usize {
return self.value;
}
pub fn set_value(&mut self, new_value: usize) {
self.value = new_value;
}
pub fn show(&mut self) {
self.hidden = false;
}
pub fn is_hidden(&self) -> bool {
return self.hidden;
}
pub fn is_flagged(&self) -> bool {
return self.flagged;
}
pub fn set_flag(&mut self, new_flag: bool) {
self.flagged = new_flag;
}
}
impl ToString for Cell {
fn to_string(&self) -> String {
if self.hidden {
return " ".to_string();
}
if self.is_mine() {
return "*".to_string();
}
if self.value == 0 {
return " ".to_string();
}
return self.value.to_string();
}
}

74
src/minesweeper/mod.rs Normal file
View File

@@ -0,0 +1,74 @@
pub mod cell;
pub mod board;
use board::Board;
use cell::Cell;
use rand::Rng;
// use getrandom::getrandom;
pub struct Game {
board: Board,
}
impl Game {
pub fn new(height: usize, width: usize, num_mines: usize) -> Self {
Self {
board: Board::new(height, width, num_mines),
}
}
pub fn start_board(&mut self){
// TODO: make a better implementation
let mut added_mines = 0;
let mut rng = rand::thread_rng();
while added_mines < self.board.get_num_mines() {
let pos = (rng.gen_range(0..self.board.get_height()), rng.gen_range(0..self.board.get_width()));
if !self.board.is_mine(pos) {
self.board.set_mine(pos, true);
added_mines += 1;
}
}
// Set values
for i in 0..self.board.get_height() {
for j in 0..self.board.get_width() {
self.board.set_value((i, j), self.board.calculate_value((i, j)))
}
}
}
pub fn show(&mut self, pos: (usize, usize)) {
self.board.show_cell(pos);
if self.board.get_value(pos) == 0 {
for i in -1..=1 {
for j in -1..=1 {
if pos.0 as isize + i >= 0 &&
pos.0 as isize + i < self.get_height() as isize &&
pos.1 as isize + j >= 0 &&
pos.1 as isize + j < self.get_width() as isize &&
self.board.get_cell(((pos.0 as isize + i) as usize , (pos.1 as isize + j) as usize)).is_hidden() {
self.show(((pos.0 as isize + i) as usize , (pos.1 as isize + j) as usize))
}
}
}
}
}
pub fn get_height(&self) -> usize {
return self.board.get_height();
}
pub fn get_width(&self) -> usize {
return self.board.get_width();
}
pub fn get_board(&self) -> &Board {
return &self.board;
}
pub fn get_cell(&self,pos: (usize, usize)) -> Cell {
self.board.get_cell(pos)
}
}