]> git.seodisparate.com - EN605.607.81.SP22_ASDM_Project/commitdiff
Impl buttons indicator that won the game
authorStephen Seo <seo.disparate@gmail.com>
Wed, 9 Mar 2022 09:10:13 +0000 (18:10 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 9 Mar 2022 09:10:13 +0000 (18:10 +0900)
front_end/index.html
front_end/src/game_logic.rs
front_end/src/html_helper.rs
front_end/src/state.rs
front_end/src/yew_components.rs

index d53901431301468d6f518c29a0fb6d174dfc1709..1e3f5bc5cdfd4635a87c0c1db09f5f9c25a8b43e 100644 (file)
       button.magenta {
         background: #F0F;
       }
+      button.win {
+        animation-duration: 400ms;
+        animation-name: blink;
+        animation-iteration-count: infinite;
+        animation-direction: alternate;
+      }
+      @keyframes blink {
+        from {
+          opacity: 1;
+        }
+        to {
+          opacity: 0;
+        }
+      }
     </style>
   </head>
 </html>
index e2c51110afb21316b514fdd9ec5a5ab6b675ce32..9d31d106e0667b121959627f0a4fc61049428e7c 100644 (file)
@@ -1,8 +1,17 @@
 use crate::constants::{COLS, ROWS};
 use crate::state::{BoardState, BoardType};
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum WinType {
+    Horizontal(usize),
+    Vertical(usize),
+    DiagonalUp(usize),
+    DiagonalDown(usize),
+    None,
+}
+
 /// Returns a BoardState if win/draw, None if game is still going
-pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
+pub fn check_win_draw(board: &BoardType) -> Option<(BoardState, WinType)> {
     let mut has_empty_slot = false;
     for slot in board {
         match slot.get() {
@@ -10,28 +19,32 @@ pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
                 has_empty_slot = true;
                 break;
             }
-            BoardState::Cyan | BoardState::Magenta => (),
+            BoardState::Cyan
+            | BoardState::CyanWin
+            | BoardState::Magenta
+            | BoardState::MagentaWin => (),
         }
     }
 
     if !has_empty_slot {
-        return Some(BoardState::Empty);
+        return Some((BoardState::Empty, WinType::None));
     }
 
     let check_result = |state| -> Option<BoardState> {
         match state {
             BoardState::Empty => None,
-            BoardState::Cyan => Some(BoardState::Cyan),
-            BoardState::Magenta => Some(BoardState::Magenta),
+            BoardState::Cyan | BoardState::CyanWin => Some(BoardState::Cyan),
+            BoardState::Magenta | BoardState::MagentaWin => Some(BoardState::Magenta),
         }
     };
 
     // check horizontals
     for y in 0..(ROWS as usize) {
         for x in 0..((COLS - 3) as usize) {
-            let result = check_result(has_right_horizontal_at_idx(x + y * (COLS as usize), board));
+            let idx = x + y * (COLS as usize);
+            let result = check_result(has_right_horizontal_at_idx(idx, board));
             if result.is_some() {
-                return result;
+                return Some((result.unwrap(), WinType::Horizontal(idx)));
             }
         }
     }
@@ -39,9 +52,10 @@ pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
     // check verticals
     for y in 0..((ROWS - 3) as usize) {
         for x in 0..(COLS as usize) {
-            let result = check_result(has_down_vertical_at_idx(x + y * (COLS as usize), board));
+            let idx = x + y * (COLS as usize);
+            let result = check_result(has_down_vertical_at_idx(idx, board));
             if result.is_some() {
-                return result;
+                return Some((result.unwrap(), WinType::Vertical(idx)));
             }
         }
     }
@@ -49,9 +63,10 @@ pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
     // check up diagonals
     for y in 3..(ROWS as usize) {
         for x in 0..((COLS - 3) as usize) {
-            let result = check_result(has_right_up_diagonal_at_idx(x + y * (COLS as usize), board));
+            let idx = x + y * (COLS as usize);
+            let result = check_result(has_right_up_diagonal_at_idx(idx, board));
             if result.is_some() {
-                return result;
+                return Some((result.unwrap(), WinType::DiagonalUp(idx)));
             }
         }
     }
@@ -59,12 +74,10 @@ pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
     // check down diagonals
     for y in 0..((ROWS - 3) as usize) {
         for x in 0..((COLS - 3) as usize) {
-            let result = check_result(has_right_down_diagonal_at_idx(
-                x + y * (COLS as usize),
-                board,
-            ));
+            let idx = x + y * (COLS as usize);
+            let result = check_result(has_right_down_diagonal_at_idx(idx, board));
             if result.is_some() {
-                return result;
+                return Some((result.unwrap(), WinType::DiagonalDown(idx)));
             }
         }
     }
index 6e4efdfa983139bb743b22ef48bb8f49593fcce8..a1b9599260b7b0852a80bd03ebdb34d830dc6b0b 100644 (file)
@@ -52,3 +52,13 @@ pub fn append_to_info_text(
 
     Ok(())
 }
+
+pub fn element_append_class(document: &Document, id: &str, class: &str) -> Result<(), String> {
+    let element = document
+        .get_element_by_id(id)
+        .ok_or_else(|| format!("Failed to get element with id \"{}\"", id))?;
+    let new_class = format!("{} {}", element.class_name(), class);
+    element.set_class_name(&new_class);
+
+    Ok(())
+}
index 5c571e6eb70ea71e77080ed93461065750d1f017..dabbdb1ec1e84cc05a86523e67babcef82e71810 100644 (file)
@@ -33,6 +33,8 @@ pub enum BoardState {
     Empty,
     Cyan,
     Magenta,
+    CyanWin,
+    MagentaWin,
 }
 
 impl Default for BoardState {
@@ -46,7 +48,9 @@ impl Display for BoardState {
         match *self {
             BoardState::Empty => f.write_str("open"),
             BoardState::Cyan => f.write_str("cyan"),
+            BoardState::CyanWin => f.write_str("cyan win"),
             BoardState::Magenta => f.write_str("magenta"),
+            BoardState::MagentaWin => f.write_str("magenta win"),
         }
     }
 }
@@ -64,6 +68,22 @@ impl BoardState {
     pub fn is_empty(&self) -> bool {
         *self == BoardState::Empty
     }
+
+    pub fn into_win(&self) -> Self {
+        match *self {
+            BoardState::Empty => BoardState::Empty,
+            BoardState::Cyan | BoardState::CyanWin => BoardState::CyanWin,
+            BoardState::Magenta | BoardState::MagentaWin => BoardState::MagentaWin,
+        }
+    }
+
+    pub fn from_win(&self) -> Self {
+        match *self {
+            BoardState::Empty => BoardState::Empty,
+            BoardState::Cyan | BoardState::CyanWin => BoardState::Cyan,
+            BoardState::Magenta | BoardState::MagentaWin => BoardState::MagentaWin,
+        }
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -84,8 +104,8 @@ impl Display for Turn {
 impl From<BoardState> for Turn {
     fn from(board_state: BoardState) -> Self {
         match board_state {
-            BoardState::Empty | BoardState::Cyan => Turn::CyanPlayer,
-            BoardState::Magenta => Turn::MagentaPlayer,
+            BoardState::Empty | BoardState::Cyan | BoardState::CyanWin => Turn::CyanPlayer,
+            BoardState::Magenta | BoardState::MagentaWin => Turn::MagentaPlayer,
         }
     }
 }
index b6fe872a344b7a1da3c3a8689e1202dc5f60c58b..8b78d2984197cc66392aacd2e37bc376304e4245 100644 (file)
@@ -1,6 +1,6 @@
 use crate::constants::{COLS, INFO_TEXT_MAX_ITEMS, ROWS};
-use crate::game_logic::check_win_draw;
-use crate::html_helper::{append_to_info_text, get_window_document};
+use crate::game_logic::{check_win_draw, WinType};
+use crate::html_helper::{append_to_info_text, element_append_class, get_window_document};
 use crate::state::{BoardState, GameState, SharedState, Turn};
 
 use std::cell::Cell;
@@ -281,7 +281,7 @@ impl Component for Wrapper {
 
                 // check for win
                 let check_win_draw_opt = check_win_draw(&shared.board);
-                if let Some(endgame_state) = check_win_draw_opt {
+                if let Some((endgame_state, win_type)) = check_win_draw_opt {
                     if endgame_state == BoardState::Empty {
                         // draw
                         let text_append_result = append_to_info_text(
@@ -307,6 +307,175 @@ impl Component for Wrapper {
                         if let Err(e) = text_append_result {
                             log::warn!("ERROR: text append to info_text0 failed: {}", e);
                         }
+
+                        match win_type {
+                            WinType::Horizontal(idx) => {
+                                let append_result =
+                                    element_append_class(&document, &format!("slot{}", idx), "win");
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 1),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 2),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 3),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+
+                                shared.board[idx].replace(shared.board[idx].get().into_win());
+                                shared.board[idx + 1]
+                                    .replace(shared.board[idx + 1].get().into_win());
+                                shared.board[idx + 2]
+                                    .replace(shared.board[idx + 2].get().into_win());
+                                shared.board[idx + 3]
+                                    .replace(shared.board[idx + 3].get().into_win());
+                            }
+                            WinType::Vertical(idx) => {
+                                let append_result =
+                                    element_append_class(&document, &format!("slot{}", idx), "win");
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 1 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 2 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 3 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+
+                                shared.board[idx].replace(shared.board[idx].get().into_win());
+                                shared.board[idx + 1 * (COLS as usize)].replace(
+                                    shared.board[idx + 1 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 2 * (COLS as usize)].replace(
+                                    shared.board[idx + 2 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 3 * (COLS as usize)].replace(
+                                    shared.board[idx + 3 * (COLS as usize)].get().into_win(),
+                                );
+                            }
+                            WinType::DiagonalUp(idx) => {
+                                let append_result =
+                                    element_append_class(&document, &format!("slot{}", idx), "win");
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 1 - 1 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 2 - 2 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 3 - 3 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+
+                                shared.board[idx].replace(shared.board[idx].get().into_win());
+                                shared.board[idx + 1 - 1 * (COLS as usize)].replace(
+                                    shared.board[idx + 1 - 1 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 2 - 2 * (COLS as usize)].replace(
+                                    shared.board[idx + 2 - 2 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 3 - 3 * (COLS as usize)].replace(
+                                    shared.board[idx + 3 - 3 * (COLS as usize)].get().into_win(),
+                                );
+                            }
+                            WinType::DiagonalDown(idx) => {
+                                let append_result =
+                                    element_append_class(&document, &format!("slot{}", idx), "win");
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 1 + 1 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 2 + 2 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+                                let append_result = element_append_class(
+                                    &document,
+                                    &format!("slot{}", idx + 3 + 3 * (COLS as usize)),
+                                    "win",
+                                );
+                                if let Err(e) = append_result {
+                                    log::warn!("ERROR: element_append_class failed: {}", e);
+                                }
+
+                                shared.board[idx].replace(shared.board[idx].get().into_win());
+                                shared.board[idx + 1 + 1 * (COLS as usize)].replace(
+                                    shared.board[idx + 1 + 1 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 2 + 2 * (COLS as usize)].replace(
+                                    shared.board[idx + 2 + 2 * (COLS as usize)].get().into_win(),
+                                );
+                                shared.board[idx + 3 + 3 * (COLS as usize)].replace(
+                                    shared.board[idx + 3 + 3 * (COLS as usize)].get().into_win(),
+                                );
+                            }
+                            WinType::None => todo!(),
+                        }
                     }
 
                     let text_append_result =