separate optimization levels
This commit is contained in:
		
							
								
								
									
										2
									
								
								wasm/o-x-rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								wasm/o-x-rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -25,7 +25,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "o-x-rust" | name = "o-x-rust" | ||||||
| version = "0.0.7" | version = "0.0.8" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
| ] | ] | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ description = "Noughts and crosses WASM algorithms" | |||||||
| repository = "https://git.koval.net/cyclane/game-algorithms/src/branch/main/wasm/o-x-rust" | repository = "https://git.koval.net/cyclane/game-algorithms/src/branch/main/wasm/o-x-rust" | ||||||
| license = "GNU GPLv3" | license = "GNU GPLv3" | ||||||
| readme = "README.md" | readme = "README.md" | ||||||
| version = "0.0.7" | version = "0.0.8" | ||||||
| edition = "2021" | edition = "2021" | ||||||
|  |  | ||||||
| [lib] | [lib] | ||||||
|   | |||||||
| @@ -35,20 +35,53 @@ pub fn get_turn(me: u8, other: u8, first: bool, empty: usize) -> u8 { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[wasm_bindgen] | #[wasm_bindgen] | ||||||
| pub fn get_score(me: u8, other: u8, first: bool, board: &[u8]) -> f64 { | pub fn o0_get_score(me: u8, other: u8, first: bool, board: &[u8]) -> f64 { | ||||||
| 	let (outcomes, score) = sub_get_score(me, other, first, board); | 	let winner = find_winner(board); | ||||||
|  | 	if winner != 0 { | ||||||
|  | 		return if winner == me { 1.0 } else { -1.0 }; | ||||||
|  | 	} | ||||||
|  | 	let empty = count_empty(board); | ||||||
|  | 	if empty == 0 { | ||||||
|  | 		return 0.0; | ||||||
|  | 	} | ||||||
|  | 	let mut score = 0.0; | ||||||
|  | 	for i in 0..9 { | ||||||
|  | 		if board[i] != 0 { | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		let copy = &mut [0u8; 9]; | ||||||
|  | 		copy.copy_from_slice(board); | ||||||
|  | 		copy[i] = get_turn(me, other, first, empty); | ||||||
|  | 		score += o0_get_score(me, other, first, copy); | ||||||
|  | 	} | ||||||
|  | 	score | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[wasm_bindgen] | ||||||
|  | pub fn o1d_get_score(me: u8, other: u8, first: bool, board: &[u8]) -> f64 { | ||||||
|  | 	let (outcomes, score) = o1_sub_get_score(me, other, first, board, 2, 2, 1); | ||||||
|  | 	score as f64 / outcomes as f64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[wasm_bindgen] | ||||||
|  | pub fn o1nd_get_score(me: u8, other: u8, first: bool, board: &[u8]) -> f64 { | ||||||
|  | 	let (outcomes, score) = o1_sub_get_score(me, other, first, board, 1, 1, 0); | ||||||
| 	score as f64 / outcomes as f64 | 	score as f64 / outcomes as f64 | ||||||
| } | } | ||||||
|  |  | ||||||
| // outcomes, winning outcomes | // outcomes, winning outcomes | ||||||
| pub fn sub_get_score(me: u8, other: u8, first: bool, board: &[u8]) -> (i32, i32) { | // m: Total outcomes multiplier | ||||||
|  | // w: Win winning outcome score | ||||||
|  | // d: Draw winning outcome score | ||||||
|  | // (loose = 0) | ||||||
|  | pub fn o1_sub_get_score(me: u8, other: u8, first: bool, board: &[u8], m: i32, w: i32, d: i32) -> (i32, i32) { | ||||||
| 	let winner = find_winner(board); | 	let winner = find_winner(board); | ||||||
| 	if winner != 0 { | 	if winner != 0 { | ||||||
| 		return if winner == me { (1, 1) } else { (1, 0) }; | 		return if winner == me { (m, w) } else { (m, 0) }; | ||||||
| 	} | 	} | ||||||
| 	let empty = count_empty(board); | 	let empty = count_empty(board); | ||||||
| 	if empty == 0 { | 	if empty == 0 { | ||||||
| 		return (1, 0); | 		return (m, d); | ||||||
| 	} | 	} | ||||||
| 	let mut score = 0; | 	let mut score = 0; | ||||||
| 	let mut outcomes = 0; | 	let mut outcomes = 0; | ||||||
| @@ -59,15 +92,33 @@ pub fn sub_get_score(me: u8, other: u8, first: bool, board: &[u8]) -> (i32, i32) | |||||||
| 		let copy = &mut [0u8; 9]; | 		let copy = &mut [0u8; 9]; | ||||||
| 		copy.copy_from_slice(board); | 		copy.copy_from_slice(board); | ||||||
| 		copy[i] = get_turn(me, other, first, empty); | 		copy[i] = get_turn(me, other, first, empty); | ||||||
| 		let (sub_outcomes, sub_score) = sub_get_score(me, other, first, copy); | 		let (sub_outcomes, sub_score) = o1_sub_get_score(me, other, first, copy, m, w, d); | ||||||
| 		outcomes += sub_outcomes; | 		outcomes += sub_outcomes; | ||||||
| 		score += sub_score; | 		score += sub_score; | ||||||
| 	} | 	} | ||||||
| 	(outcomes, score) | 	(outcomes, score) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Optimization levels: o0, o1d, o1nd, o2 | ||||||
|  | // o0: minmax without optimizations | ||||||
|  | // o1d: minmax with ratio optimization including draws | ||||||
|  | // o1nd: minmax with ratio optimization excluding draws (draw = loose) | ||||||
| #[wasm_bindgen] | #[wasm_bindgen] | ||||||
| pub fn predict(me: u8, other: u8, first: bool, board: &[u8]) -> usize { | pub fn get_score(me: u8, other: u8, first: bool, board: &[u8], optimization_level: &str) -> f64 { | ||||||
|  | 	match optimization_level { | ||||||
|  | 		"o0" => o0_get_score(me, other, first, board), | ||||||
|  | 		"o1d" => o1d_get_score(me, other, first, board), | ||||||
|  | 		"o1nd" => o1nd_get_score(me, other, first, board), | ||||||
|  | 		_ => 0.0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Optimization levels: o0, o1d, o1nd, o2 | ||||||
|  | // o0: minmax without optimizations | ||||||
|  | // o1d: minmax with ratio optimization including draws | ||||||
|  | // o1nd: minmax with ratio optimization excluding draws (draw = loose) | ||||||
|  | #[wasm_bindgen] | ||||||
|  | pub fn predict(me: u8, other: u8, first: bool, board: &[u8], optimization_level: &str) -> usize { | ||||||
| 	let (mut max_p, mut max_s) = (0, f64::MIN); | 	let (mut max_p, mut max_s) = (0, f64::MIN); | ||||||
| 	let empty = count_empty(board); | 	let empty = count_empty(board); | ||||||
| 	if empty == 0 { | 	if empty == 0 { | ||||||
| @@ -80,7 +131,7 @@ pub fn predict(me: u8, other: u8, first: bool, board: &[u8]) -> usize { | |||||||
| 		let copy = &mut [0u8; 9]; | 		let copy = &mut [0u8; 9]; | ||||||
| 		copy.copy_from_slice(board); | 		copy.copy_from_slice(board); | ||||||
| 		copy[i] = get_turn(me, other, first, empty); | 		copy[i] = get_turn(me, other, first, empty); | ||||||
| 		let score = get_score(me, other, first, copy); | 		let score = get_score(me, other, first, copy, optimization_level); | ||||||
| 		if score > max_s { | 		if score > max_s { | ||||||
| 			(max_p, max_s) = (i, score); | 			(max_p, max_s) = (i, score); | ||||||
| 		} | 		} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user