simplified memory layout
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use gtk4::{AlertDialog, Window, prelude::IsA};
|
||||
use rdraught::draughts::Player;
|
||||
use rdraught::Player;
|
||||
|
||||
pub(crate) async fn create_dialog<W: IsA<Window>>(window: W, winner: Player) {
|
||||
let msg = match winner {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use gtk4::{Align, Application, Box, CheckButton, Label, Orientation, Window, prelude::*};
|
||||
|
||||
use crate::types::SharedMutable;
|
||||
use rdraught::draughts::Player;
|
||||
use rdraught::Player;
|
||||
|
||||
pub(crate) fn create(application: &Application, current_player: SharedMutable<Player>) -> Window {
|
||||
let label = Label::builder().label("Main player:").build();
|
||||
|
@@ -1,13 +1,5 @@
|
||||
use glib::ExitCode;
|
||||
use rdraught;
|
||||
use rdraught::draughts::DraughtsGame;
|
||||
use rdraught_ui;
|
||||
mod geo2d;
|
||||
|
||||
mod final_dialog;
|
||||
mod greeting_dialog;
|
||||
mod rdraught_application;
|
||||
mod types;
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let game = DraughtsGame::default();
|
||||
|
@@ -5,8 +5,10 @@ use glib::ExitCode;
|
||||
use gtk4::glib::{MainContext, Propagation};
|
||||
use gtk4::{self as gtk, gdk::ffi::GDK_BUTTON_PRIMARY};
|
||||
use gtk4::{Application, DrawingArea, prelude::*};
|
||||
use rdraught::draughts::{DraughtsBoard, DraughtsGame, Error, Move, Piece, Player};
|
||||
use rdraught::position::Position;
|
||||
use rdraught::{
|
||||
DraughtsBoard, DraughtsGame, Move, Piece, Player, Position, RDraughtApplication,
|
||||
RectangularBoard,
|
||||
};
|
||||
use rsvg::SvgHandle;
|
||||
use std::thread;
|
||||
const SQUARE_SIZE: f64 = 1.0;
|
||||
@@ -169,7 +171,7 @@ fn draw_score_bar(
|
||||
) {
|
||||
fn modulate_score(relative_score: f64) -> f64 {
|
||||
let x = relative_score;
|
||||
f64::atan(8.0 * x - 4.0) / f64::atan(4.0) / 2.0 + 0.5
|
||||
1.0 - (f64::atan(8.0 * x - 4.0) / f64::atan(4.0) / 2.0 + 0.5)
|
||||
}
|
||||
let score_bar = Rectangle::new(
|
||||
board.tl().x() - board.width() / 10.0,
|
||||
@@ -177,31 +179,56 @@ fn draw_score_bar(
|
||||
board.width() / 16.0,
|
||||
board.height(),
|
||||
);
|
||||
let num_rects = 40usize;
|
||||
let spacing = board.height() / 200.0;
|
||||
let rect_height = (board.height() - spacing * (num_rects - 1) as f64) / (num_rects as f64);
|
||||
let score_percentage = modulate_score(draughts_game.relative_score(current_player) as f64);
|
||||
let threshold = (score_percentage * num_rects as f64) as usize;
|
||||
let tl = score_bar.tl();
|
||||
cr.save().unwrap();
|
||||
match current_player {
|
||||
Player::White => cr.set_source_rgb(1.0, 0.0, 0.0),
|
||||
Player::Red => cr.set_source_rgb(1.0, 1.0, 1.0),
|
||||
cr.set_line_width(spacing / 4.0);
|
||||
for i in 0..threshold {
|
||||
match current_player {
|
||||
Player::White => cr.set_source_rgb(1.0, 0.0, 0.0),
|
||||
Player::Red => cr.set_source_rgb(1.0, 1.0, 1.0),
|
||||
}
|
||||
cr.rectangle(
|
||||
tl.x(),
|
||||
tl.y() + i as f64 * (rect_height + spacing),
|
||||
score_bar.width(),
|
||||
rect_height,
|
||||
);
|
||||
cr.fill().unwrap();
|
||||
cr.set_source_rgb(0.0, 0.0, 0.0);
|
||||
cr.rectangle(
|
||||
tl.x(),
|
||||
tl.y() + i as f64 * (rect_height + spacing),
|
||||
score_bar.width(),
|
||||
rect_height,
|
||||
);
|
||||
cr.stroke().unwrap();
|
||||
}
|
||||
cr.rectangle(
|
||||
score_bar.tl().x(),
|
||||
score_bar.tl().y(),
|
||||
score_bar.width(),
|
||||
score_bar.height() * (1.0 - score_percentage),
|
||||
);
|
||||
cr.fill().unwrap();
|
||||
match current_player {
|
||||
Player::White => cr.set_source_rgb(1.0, 1.0, 1.0),
|
||||
Player::Red => cr.set_source_rgb(1.0, 0.0, 0.0),
|
||||
for i in threshold..num_rects {
|
||||
match current_player {
|
||||
Player::White => cr.set_source_rgb(1.0, 1.0, 1.0),
|
||||
Player::Red => cr.set_source_rgb(1.0, 0.0, 0.0),
|
||||
}
|
||||
cr.rectangle(
|
||||
tl.x(),
|
||||
tl.y() + i as f64 * (rect_height + spacing),
|
||||
score_bar.width(),
|
||||
rect_height,
|
||||
);
|
||||
cr.fill().unwrap();
|
||||
cr.set_source_rgb(0.0, 0.0, 0.0);
|
||||
cr.rectangle(
|
||||
tl.x(),
|
||||
tl.y() + i as f64 * (rect_height + spacing),
|
||||
score_bar.width(),
|
||||
rect_height,
|
||||
);
|
||||
cr.stroke().unwrap();
|
||||
}
|
||||
cr.rectangle(
|
||||
tl.x(),
|
||||
tl.y() + score_bar.height() * (1.0 - score_percentage),
|
||||
score_bar.width(),
|
||||
score_bar.height() * score_percentage,
|
||||
);
|
||||
cr.fill().unwrap();
|
||||
cr.restore().unwrap();
|
||||
}
|
||||
|
||||
@@ -316,7 +343,7 @@ fn create_game_window(
|
||||
draw_piece(
|
||||
cr,
|
||||
&square,
|
||||
rd.borrow().game.piece_at(position),
|
||||
position.map_or(Piece::NoPiece, |p| rd.borrow().game().piece_at(p)),
|
||||
&crown_red_handle,
|
||||
&crown_white_handle,
|
||||
)
|
||||
@@ -326,16 +353,12 @@ fn create_game_window(
|
||||
}
|
||||
if let Some(selected_position) = selected_piece.get() {
|
||||
let screen_position = match current_player {
|
||||
Player::White => {
|
||||
Position::new(8 - 1 - selected_position.row(), selected_position.col())
|
||||
}
|
||||
Player::Red => {
|
||||
Position::new(selected_position.row(), 8 - 1 - selected_position.col())
|
||||
}
|
||||
Player::White => (8 - 1 - selected_position.row(), selected_position.col()),
|
||||
Player::Red => (selected_position.row(), 8 - 1 - selected_position.col()),
|
||||
};
|
||||
let square = Rectangle::new(
|
||||
screen_position.col() as f64 * SQUARE_SIZE,
|
||||
screen_position.row() as f64 * SQUARE_SIZE,
|
||||
screen_position.1 as f64 * SQUARE_SIZE,
|
||||
screen_position.0 as f64 * SQUARE_SIZE,
|
||||
SQUARE_SIZE,
|
||||
SQUARE_SIZE,
|
||||
);
|
||||
@@ -349,7 +372,7 @@ fn create_game_window(
|
||||
cr.clip();
|
||||
cr.new_path();
|
||||
cr.set_source_rgb(0.0, 0.0, 1.0);
|
||||
cr.set_line_width((square.width() + square.height()) * 0.05);
|
||||
cr.set_line_width((square.width() + square.height()) * 0.035);
|
||||
cr.move_to(square.tl().x(), square.tl().y());
|
||||
cr.line_to(square.tl().x(), square.br().y());
|
||||
cr.line_to(square.br().x(), square.br().y());
|
||||
@@ -364,12 +387,12 @@ fn create_game_window(
|
||||
for mv in am.iter() {
|
||||
let end_pos = mv.get_end_position();
|
||||
let screen_position = match current_player {
|
||||
Player::White => Position::new(8 - 1 - end_pos.row(), end_pos.col()),
|
||||
Player::Red => Position::new(end_pos.row(), 8 - 1 - end_pos.col()),
|
||||
Player::White => (8 - 1 - end_pos.row(), end_pos.col()),
|
||||
Player::Red => (end_pos.row(), 8 - 1 - end_pos.col()),
|
||||
};
|
||||
let square = Rectangle::new(
|
||||
screen_position.col() as f64 * SQUARE_SIZE,
|
||||
screen_position.row() as f64 * SQUARE_SIZE,
|
||||
screen_position.1 as f64 * SQUARE_SIZE,
|
||||
screen_position.0 as f64 * SQUARE_SIZE,
|
||||
SQUARE_SIZE,
|
||||
SQUARE_SIZE,
|
||||
);
|
||||
@@ -383,7 +406,7 @@ fn create_game_window(
|
||||
cr.clip();
|
||||
cr.new_path();
|
||||
cr.set_source_rgb(0.0, 1.0, 0.0);
|
||||
cr.set_line_width((square.width() + square.height()) * 0.05);
|
||||
cr.set_line_width((square.width() + square.height()) * 0.035);
|
||||
cr.move_to(square.tl().x(), square.tl().y());
|
||||
cr.line_to(square.tl().x(), square.br().y());
|
||||
cr.line_to(square.br().x(), square.br().y());
|
||||
@@ -393,7 +416,7 @@ fn create_game_window(
|
||||
cr.restore().unwrap();
|
||||
}
|
||||
}
|
||||
draw_score_bar(cr, &board, &rd.borrow().game, current_player);
|
||||
draw_score_bar(cr, &board, rd.borrow().game(), current_player);
|
||||
});
|
||||
}
|
||||
let gesture = gtk::GestureClick::new();
|
||||
@@ -408,7 +431,7 @@ fn create_game_window(
|
||||
let window = window.clone();
|
||||
gesture.connect_pressed(move |gesture, _, x, y| {
|
||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||
if let Some(winner) = rd.borrow().game.winner() {
|
||||
if let Some(winner) = rd.borrow().game().winner() {
|
||||
MainContext::default()
|
||||
.spawn_local(final_dialog::create_dialog(window.clone(), winner));
|
||||
} else {
|
||||
@@ -432,32 +455,38 @@ fn create_game_window(
|
||||
(8.0 - p.x() / SQUARE_SIZE) as u8,
|
||||
),
|
||||
};
|
||||
// println!("Selected position: {:?}", position);
|
||||
println!("Selected position: {:?}", position);
|
||||
let piece = {
|
||||
let draughts_game = &rd.borrow().game;
|
||||
draughts_game.piece_at(position)
|
||||
let rd = rd.borrow();
|
||||
let draughts_game = rd.game();
|
||||
position
|
||||
.clone()
|
||||
.map_or(Piece::NoPiece, |it| draughts_game.piece_at(it))
|
||||
// println!("Selected piece: {:?}", piece);
|
||||
};
|
||||
let am = available_moves.replace(Vec::new());
|
||||
let mut move_applied = false;
|
||||
if !am.is_empty() {
|
||||
for mv in am.into_iter() {
|
||||
if mv.get_end_position() == position {
|
||||
let mut rd_app = rd.borrow_mut();
|
||||
println!("Applied move: {:?}", mv);
|
||||
rd_app.apply_move(mv).unwrap();
|
||||
let game_copy = rd_app.game.clone();
|
||||
thread::spawn(move || {
|
||||
if let (Some(mv), analyzed_moves) = game_copy.get_best_move(10)
|
||||
{
|
||||
println!(
|
||||
"Next best move: {:?}, analyzed moves: {}",
|
||||
mv, analyzed_moves
|
||||
);
|
||||
}
|
||||
});
|
||||
move_applied = true;
|
||||
break;
|
||||
if let Ok(pos) = position {
|
||||
for mv in am.into_iter() {
|
||||
if mv.get_end_position() == pos {
|
||||
let mut rd_app = rd.borrow_mut();
|
||||
println!("Applied move: {:?}", mv);
|
||||
rd_app.apply_move(mv).unwrap();
|
||||
// let game_copy = rd_app.game().clone();
|
||||
// thread::spawn(move || {
|
||||
// if let (Some(mv), analyzed_moves) =
|
||||
// game_copy.get_best_move(10)
|
||||
// {
|
||||
// println!(
|
||||
// "Next best move: {:?}, analyzed moves: {}",
|
||||
// mv, analyzed_moves
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
move_applied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if move_applied {
|
||||
@@ -465,18 +494,21 @@ fn create_game_window(
|
||||
}
|
||||
}
|
||||
if !move_applied {
|
||||
let position = position.ok();
|
||||
match piece.player() {
|
||||
Some(Player::Red) => selected_piece.set(Some(position)),
|
||||
Some(Player::White) => selected_piece.set(Some(position)),
|
||||
Some(Player::Red) => selected_piece.set(position),
|
||||
Some(Player::White) => selected_piece.set(position),
|
||||
None => selected_piece.set(None),
|
||||
}
|
||||
if piece.player().is_none() {
|
||||
selected_piece.set(None)
|
||||
} else {
|
||||
let mut am = available_moves.borrow_mut();
|
||||
selected_piece.set(Some(position));
|
||||
for mv in rd.borrow().game.moves_for_piece(position) {
|
||||
am.push(mv);
|
||||
selected_piece.set(position);
|
||||
if let Some(position) = position {
|
||||
for mv in rd.borrow().game().moves_for_piece(position) {
|
||||
am.push(mv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,12 +523,6 @@ fn create_game_window(
|
||||
drawing_area.add_controller(gesture);
|
||||
window.present();
|
||||
}
|
||||
struct RDraughtApplication {
|
||||
initial_state: DraughtsGame,
|
||||
game: DraughtsGame,
|
||||
moves: Vec<Move>,
|
||||
cursor: usize,
|
||||
}
|
||||
|
||||
fn on_activate(application: &Application, game: DraughtsGame) {
|
||||
// Initialize GTK before using any GTK functions.
|
||||
@@ -515,53 +541,6 @@ fn on_activate(application: &Application, game: DraughtsGame) {
|
||||
});
|
||||
}
|
||||
|
||||
impl RDraughtApplication {
|
||||
fn new(game: DraughtsGame) -> RDraughtApplication {
|
||||
RDraughtApplication {
|
||||
initial_state: game.clone(),
|
||||
game,
|
||||
moves: Vec::<Move>::new(),
|
||||
cursor: 0usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn undo(&mut self) -> Result<(), Error> {
|
||||
let mut new_state = self.initial_state.clone();
|
||||
if self.cursor > 0 && !self.moves.is_empty() {
|
||||
self.cursor -= 1;
|
||||
for mv in &self.moves[0..self.cursor] {
|
||||
new_state.apply_move(mv)?;
|
||||
}
|
||||
self.game = new_state;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidMove)
|
||||
}
|
||||
}
|
||||
|
||||
fn redo(&mut self) -> Result<(), Error> {
|
||||
let mut new_state = self.initial_state.clone();
|
||||
if self.cursor < self.moves.len() {
|
||||
for mv in &self.moves[0..self.cursor] {
|
||||
new_state.apply_move(mv)?;
|
||||
}
|
||||
self.game = new_state;
|
||||
self.cursor += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidMove)
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_move(&mut self, mv: Move) -> Result<(), Error> {
|
||||
self.game.apply_move(&mv)?;
|
||||
self.moves.truncate(self.cursor);
|
||||
self.moves.push(mv);
|
||||
self.cursor += 1;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(game: DraughtsGame) -> ExitCode {
|
||||
// Create a new application with the builder pattern
|
||||
let app = Application::builder()
|
||||
|
Reference in New Issue
Block a user