mirror of
https://github.com/Noratrieb/minmax.git
synced 2026-01-14 15:25:08 +01:00
wrap
This commit is contained in:
parent
5bfabd3cec
commit
6b5347b196
5 changed files with 89 additions and 20 deletions
|
|
@ -27,6 +27,10 @@ impl Connect4 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_pos(&mut self, position: usize, value: Position) {
|
||||
self.positions[position] = value;
|
||||
}
|
||||
|
||||
pub fn result(&self) -> State {
|
||||
match self.check_board() {
|
||||
State::Winner(winner) => State::Winner(winner),
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ impl Score {
|
|||
Self(int)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn randomize(self) -> Self {
|
||||
let score = self.0 as f32;
|
||||
let rand = rand::thread_rng();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ impl<G: Game> PerfectPlayer<G> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn best_move(&self) -> G::Move {
|
||||
self.best_move.expect("no move made yet")
|
||||
}
|
||||
|
||||
fn minmax(&mut self, board: &mut G, player: Player, depth: usize) -> Score {
|
||||
if let Some(max_depth) = self.max_depth && depth >= max_depth {
|
||||
return board.rate(player);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ extern "C" {
|
|||
/*
|
||||
* Class: ch_bbw_m411_connect4_RustPlayer
|
||||
* Method: rustPlay
|
||||
* Signature: (B[Lch/bbw/m411/connect4/Connect4ArenaMain/Stone;)I
|
||||
* Signature: (B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_ch_bbw_m411_connect4_RustPlayer_rustPlay
|
||||
(JNIEnv *, jobject, jbyte, jobjectArray);
|
||||
(JNIEnv *, jclass, jbyte, jbyteArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,81 @@
|
|||
// This is the interface to the JVM that we'll call the majority of our
|
||||
// methods on.
|
||||
use jni::JNIEnv;
|
||||
|
||||
// These objects are what you should use as arguments to your native
|
||||
// function. They carry extra lifetime information to prevent them escaping
|
||||
// this context and getting used after being GC'd.
|
||||
use jni::objects::{JClass, JObject};
|
||||
|
||||
// This is just a pointer. We'll be returning it from our function. We
|
||||
// can't return one of the objects with lifetime information because the
|
||||
// lifetime checker won't let us.
|
||||
use jni::objects::{JClass, JObject, ReleaseMode};
|
||||
use jni::sys::{jbyte, jint};
|
||||
use jni::JNIEnv;
|
||||
use minmax::{connect4::board::Connect4, GamePlayer};
|
||||
use minmax::{PerfectPlayer, Player};
|
||||
|
||||
// 0 -> X
|
||||
// 1 -> O
|
||||
pub fn wrap_player<P: GamePlayer<Connect4>>(current_player: i8, board: ()) -> i32 {
|
||||
0
|
||||
/// We need to map the board.
|
||||
/// Rust:
|
||||
/// ```text
|
||||
/// 0 1 2 3 4 5 6
|
||||
/// 7 8 9 10 11 12 13
|
||||
/// 14 15 16 17 18 19 20
|
||||
/// 21 22 23 24 25 26 27
|
||||
/// ```
|
||||
/// Java:
|
||||
/// ```text
|
||||
/// 21 22 23 24 25 26 27
|
||||
/// 14 15 16 17 18 19 20
|
||||
/// 7 8 9 10 11 12 13
|
||||
/// 0 1 2 3 4 5 6
|
||||
/// ```
|
||||
fn map_idx(i: usize) -> usize {
|
||||
match () {
|
||||
() if i < 7 => i + 21,
|
||||
() if i < 15 => i + 7,
|
||||
() if i < 21 => i - 7,
|
||||
() => i - 21,
|
||||
}
|
||||
}
|
||||
|
||||
fn crate_board(java_board: &[i8]) -> Connect4 {
|
||||
let mut board = Connect4::new();
|
||||
|
||||
for i in 0..28 {
|
||||
let java_int = java_board[i];
|
||||
let rust_value = match java_int {
|
||||
0 => Some(Player::X),
|
||||
1 => Some(Player::O),
|
||||
2 => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let rust_index = map_idx(i);
|
||||
|
||||
board.set_pos(rust_index, rust_value);
|
||||
}
|
||||
|
||||
board
|
||||
}
|
||||
|
||||
// 0 -> BLUE -> X
|
||||
// 1 -> RED -> O
|
||||
// 2 -> empty
|
||||
pub fn wrap_player(env: JNIEnv<'_>, current_player: i8, board: JObject<'_>) -> i32 {
|
||||
let board_size = env.get_array_length(board.into_raw()).unwrap();
|
||||
assert_eq!(board_size, 28);
|
||||
|
||||
let byte_array = env
|
||||
.get_byte_array_elements(board.into_raw(), ReleaseMode::NoCopyBack)
|
||||
.unwrap();
|
||||
|
||||
let slice = unsafe { std::slice::from_raw_parts(byte_array.as_ptr() as *const _, 28) };
|
||||
|
||||
let mut board = crate_board(slice);
|
||||
|
||||
let mut player = PerfectPlayer::new(false);
|
||||
|
||||
let current_player_rust = match current_player {
|
||||
0 => Player::X,
|
||||
1 => Player::O,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
player.next_move(&mut board, current_player_rust);
|
||||
|
||||
let result_move = player.best_move();
|
||||
|
||||
map_idx(result_move) as i32
|
||||
}
|
||||
|
||||
// This keeps Rust from "mangling" the name and making it unique for this
|
||||
|
|
@ -27,9 +86,10 @@ pub extern "system" fn Java_ch_bbw_m411_connect4_RustPlayer_rustPlay(
|
|||
// This is the class that owns our static method. It's not going to be used,
|
||||
// but still must be present to match the expected signature of a static
|
||||
// native method.
|
||||
class: JClass<'_>,
|
||||
_: JClass<'_>,
|
||||
player: jbyte,
|
||||
board: JObject<'_>,
|
||||
) -> jint {
|
||||
0
|
||||
std::panic::catch_unwind(|| wrap_player(env, player, board))
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue