Repository: thomas-mauran/chess-tui (language: rust)

Issue:
History Notation Error
## Description

When playing as black, moves are being recorded incorrectly in the game history. After the board is flipped for black's perspective, the coordinates aren't being properly translated back to standard notation before being recorded. This causes moves to be logged with incorrect coordinates and can lead to move repetition in the history.

## To Reproduce

1. Start a new game
2. Play as white: Move pawn from e2 to e4
3. Play as black: Move pawn from d7 to d5
4. Check the move history
   - Expected to see: "1. e2-e4 d7-d5"
   - Actually sees: "1. e2-e4 e2-e4" (or similar incorrect notation)

## Expected behavior

Moves should be recorded in standard chess notation regardless of board orientation. When playing as black, even though the board is visually flipped, moves should be recorded using the standard coordinate system (a8-h1 orientation) in the move history.

## Screenshots

<img width="1512" alt="Image" src="https://github.com/user-attachments/assets/19ac83d8-e09c-4dca-8bc7-ce49c7a69c0a" />

## Environment

- OS: Any (this is a logic issue affecting all platforms)
- Terminal Emulator: Any
- Font: Any
- Crate version: Latest
- Backend: Any

## Additional context

The issue stems from move coordinates being recorded directly from the visual board state without accounting for board orientation. When playing as black, the board is flipped for visual purposes, but the coordinate translation isn't being properly reversed when recording moves in the game history.

The fix involves modifying the move recording logic to invert coordinates when playing as black before storing them in the move history, while maintaining the actual board state for gameplay purposes.

Technical cause: Move coordinates need to be inverted using the `invert_position()` function before being recorded in `move_history` when playing as black (excluding bot and multiplayer games).


Discussion / hints:

Fix patch:
diff --git a/src/game_logic/ui.rs b/src/game_logic/ui.rs
index d43ed6d..c7a0862 100644
--- a/src/game_logic/ui.rs
+++ b/src/game_logic/ui.rs
@@ -1,7 +1,7 @@
 use super::{coord::Coord, game::Game};
 use crate::{
     constants::{DisplayMode, BLACK, UNDEFINED_POSITION, WHITE},
-    pieces::{PieceColor, PieceMove, PieceType},
+    pieces::{PieceColor, PieceType},
     ui::{main_ui::render_cell, prompt::Prompt},
     utils::{convert_position_into_notation, get_cell_paragraph, invert_position},
 };
@@ -171,7 +171,7 @@ impl UI {
     }
 
     /// Method to render the right panel history
-    pub fn history_render(&self, area: Rect, frame: &mut Frame, move_history: &[PieceMove]) {
+    pub fn history_render(&self, area: Rect, frame: &mut Frame, game: &Game) {
         // We write the history board on the side
         let history_block = Block::default()
             .title("History")
@@ -182,32 +182,40 @@ impl UI {
 
         let mut lines: Vec<Line> = vec![];
 
-        for i in (0..move_history.len()).step_by(2) {
-            let piece_type_from = move_history[i].piece_type;
+        for i in (0..game.game_board.move_history.len()).step_by(2) {
+            let piece_type_from = game.game_board.move_history[i].piece_type;
 
             let utf_icon_white =
                 PieceType::piece_to_utf_enum(&piece_type_from, Some(PieceColor::White));
             let move_white = convert_position_into_notation(&format!(
                 "{}{}{}{}",
-                move_history[i].from.row,
-                move_history[i].from.col,
-                move_history[i].to.row,
-                move_history[i].to.col
+                game.game_board.move_history[i].from.row,
+                game.game_board.move_history[i].from.col,
+                game.game_board.move_history[i].to.row,
+                game.game_board.move_history[i].to.col
             ));
 
             let mut utf_icon_black = "   ";
             let mut move_black: String = "   ".to_string();
 
             // If there is something for black
-            if i + 1 < move_history.len() {
-                let piece_type_to = move_history[i + 1].piece_type;
+            if i + 1 < game.game_board.move_history.len() {
+                let piece_type_to = game.game_board.move_history[i + 1].piece_type;
+                let black_move = &game.game_board.move_history[i + 1];
+
+                // Invert black moves if not playing against bot
+                let (from, to) = if game.bot.is_none() {
+                    (
+                        invert_position(&black_move.from),
+                        invert_position(&black_move.to),
+                    )
+                } else {
+                    (black_move.from, black_move.to)
+                };
 
                 move_black = convert_position_into_notation(&format!(
                     "{}{}{}{}",
-                    move_history[i + 1].from.row,
-                    move_history[i + 1].from.col,
-                    move_history[i + 1].to.row,
-                    move_history[i + 1].to.col
+                    from.row, from.col, to.row, to.col
                 ));
                 utf_icon_black =
                     PieceType::piece_to_utf_enum(&piece_type_to, Some(PieceColor::Black));
@@ -218,7 +226,7 @@ impl UI {
                 Span::styled(format!("{utf_icon_white} "), Style::default().fg(WHITE)), // white symbol
                 Span::raw(move_white.to_string()), // white move
                 Span::raw("     "),                // separator
-                Span::styled(format!("{utf_icon_black} "), Style::default().fg(WHITE)), // white symbol
+                Span::styled(format!("{utf_icon_black} "), Style::default().fg(WHITE)), // black symbol
                 Span::raw(move_black.to_string()), // black move
             ]));
         }
diff --git a/src/ui/main_ui.rs b/src/ui/main_ui.rs
index 374f698..74c6c1a 100644
--- a/src/ui/main_ui.rs
+++ b/src/ui/main_ui.rs
@@ -251,11 +251,9 @@ pub fn render_game_ui(frame: &mut Frame<'_>, app: &mut App, main_area: Rect) {
     );
 
     // We make the inside of the board
-    app.game.ui.history_render(
-        board_block.inner(right_box_layout[1]),
-        frame,
-        &app.game.game_board.move_history,
-    );
+    app.game
+        .ui
+        .history_render(board_block.inner(right_box_layout[1]), frame, &app.game);
 
     //bottom box for black matetrial
     app.game.ui.white_material_render(


Test patch: