mill_game/src/board.rs

560 lines
18 KiB
Rust
Raw Normal View History

2023-05-10 18:05:12 +00:00
use std::sync::{Arc, Mutex};
2023-05-08 18:56:50 +00:00
use anyhow::Result;
use engine::prelude::{
2023-05-09 14:39:53 +00:00
cgmath::{vec2, vec3, Vector2, Vector3},
2023-05-08 18:56:50 +00:00
*,
};
2023-05-09 14:39:53 +00:00
use crate::{game::MillGame, objects::Objects};
2023-05-10 18:05:12 +00:00
#[derive(Debug)]
2023-05-09 14:39:53 +00:00
pub struct BoardSlot {
2023-05-10 08:22:46 +00:00
pub x: usize,
pub y: usize,
pub z: usize,
2023-05-11 12:00:24 +00:00
state: Mutex<BoardSlotState>,
2023-05-09 14:39:53 +00:00
pub position: Vector2<f32>,
pub slot_marker: Option<Entity>,
}
impl BoardSlot {
pub const SLOT_MARKER_SIZE: f32 = 1.5;
2023-05-10 08:22:46 +00:00
pub fn new(
x: usize,
y: usize,
z: usize,
position: Vector2<f32>,
2025-03-25 11:07:45 +00:00
world: &mut World,
2023-05-10 08:22:46 +00:00
) -> Result<Self> {
2025-03-25 11:07:45 +00:00
let mut marker = AssetHandler::create(world).empty_entity();
2023-05-09 14:39:53 +00:00
2025-03-25 11:07:45 +00:00
let meshes = vec![Self::create_mesh(
world.resources.get::<Context>().device(),
world.resources.get::<EngineSettings>(),
Color::Black,
)?];
2023-05-09 14:39:53 +00:00
let draw = Draw::new(meshes);
marker.insert_component(draw);
let mut location = Location::from_entity(&mut marker);
location.set_position(position.extend(MillGame::OFFSET_TO_BOARD));
marker.insert_component(location);
Ok(Self {
2023-05-10 08:22:46 +00:00
x,
y,
z,
2023-05-10 18:05:12 +00:00
state: Mutex::new(BoardSlotState::default()),
2023-05-09 14:39:53 +00:00
position,
2025-03-25 11:07:45 +00:00
slot_marker: Some(world.add_entity(marker)?),
2023-05-09 14:39:53 +00:00
})
}
2023-05-10 08:22:46 +00:00
pub fn invalid(x: usize, y: usize, z: usize) -> Self {
2023-05-09 14:39:53 +00:00
Self {
2023-05-10 08:22:46 +00:00
x,
y,
z,
2023-05-10 18:05:12 +00:00
state: Mutex::new(BoardSlotState::Invalid),
2023-05-09 14:39:53 +00:00
position: vec2(0.0, 0.0),
slot_marker: None,
}
}
2025-03-25 11:07:45 +00:00
fn create_mesh(
device: &Arc<Device>,
engine_settings: &EngineSettings,
color: Color,
) -> Result<AssetMesh> {
let mut mesh = AssetMesh::new(device, engine_settings.graphics_info()?.render_type)?;
2023-05-09 14:39:53 +00:00
let vertex_buffer = Buffer::builder()
.set_data(&Objects::create_flat_quad([
vec2(-Self::SLOT_MARKER_SIZE * 0.5, -Self::SLOT_MARKER_SIZE * 0.5),
vec2(Self::SLOT_MARKER_SIZE * 0.5, -Self::SLOT_MARKER_SIZE * 0.5),
vec2(Self::SLOT_MARKER_SIZE * 0.5, Self::SLOT_MARKER_SIZE * 0.5),
vec2(-Self::SLOT_MARKER_SIZE * 0.5, Self::SLOT_MARKER_SIZE * 0.5),
]))
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
2025-03-25 11:07:45 +00:00
.build(device.clone())?;
2023-05-09 14:39:53 +00:00
let a: [f32; 3] = color.into();
mesh.add_primitive(
vertex_buffer,
None,
None,
PrimitiveMaterial {
color: [a[0], a[1], a[2], 1.0],
metallic_factor: 0.2,
emissive_factor: [0.2, 0.2, 0.2],
roughness_factor: 0.8,
alpha_mode: AlphaMode::Opaque,
alpha_cut_off: 0.5,
},
true,
)?;
Ok(mesh)
}
2023-05-10 05:47:10 +00:00
2023-05-11 12:00:24 +00:00
pub fn state(&self) -> BoardSlotState {
*self.state.lock().unwrap()
}
pub fn set_state(&self, state: BoardSlotState) {
*self.state.lock().unwrap() = state;
}
2023-05-10 05:47:10 +00:00
pub fn valid(&self) -> bool {
2023-05-10 18:05:12 +00:00
*self.state.lock().unwrap() != BoardSlotState::Invalid
2023-05-10 05:47:10 +00:00
}
2023-05-11 12:00:24 +00:00
pub fn is_empty(&self) -> bool {
*self.state.lock().unwrap() == BoardSlotState::Empty
}
2023-05-10 05:47:10 +00:00
pub fn white(&self) -> bool {
2023-05-10 18:05:12 +00:00
match *self.state.lock().unwrap() {
2023-05-10 05:47:10 +00:00
BoardSlotState::White(_) => true,
_ => false,
}
}
pub fn black(&self) -> bool {
2023-05-10 18:05:12 +00:00
match *self.state.lock().unwrap() {
2023-05-10 05:47:10 +00:00
BoardSlotState::Black(_) => true,
_ => false,
}
}
2023-05-09 14:39:53 +00:00
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BoardSlotState {
Invalid,
Empty,
Black(Entity),
White(Entity),
}
impl Default for BoardSlotState {
fn default() -> Self {
Self::Empty
}
}
2023-05-08 18:56:50 +00:00
pub struct Board {
2023-05-09 16:58:07 +00:00
_board: Entity,
2023-05-09 14:39:53 +00:00
center: Vector3<f32>,
2023-05-09 16:58:07 +00:00
_connection_lines: Vec<Entity>,
2023-05-09 14:39:53 +00:00
slots: [[[BoardSlot; 3]; 3]; 3],
white_start_slots: [Vector2<f32>; 9],
black_start_slots: [Vector2<f32>; 9],
2023-05-08 18:56:50 +00:00
}
impl Board {
2025-03-25 11:07:45 +00:00
pub fn new(world: &mut World) -> Result<Self> {
let mut board_entity = AssetHandler::create(world).empty_entity();
2023-05-08 18:56:50 +00:00
2025-03-25 11:07:45 +00:00
let meshes = vec![Self::create_board_base(&world)?];
2023-05-08 18:56:50 +00:00
let draw = Draw::new(meshes);
board_entity.insert_component(draw);
let location = Location::from_entity(&mut board_entity);
board_entity.insert_component(location);
2025-03-25 11:07:45 +00:00
let board = world.add_entity(board_entity)?;
2023-05-08 18:56:50 +00:00
2025-03-25 11:07:45 +00:00
let slots = [
[
2023-05-09 14:39:53 +00:00
[
2025-03-25 11:07:45 +00:00
BoardSlot::new(0, 0, 0, vec2(-15.0, -15.0), world)?, // 0 0 0
BoardSlot::new(0, 0, 1, vec2(-10.0, -10.0), world)?, // 0 0 1
BoardSlot::new(0, 0, 2, vec2(-5.0, -5.0), world)?, // 0 0 2
2023-05-09 14:39:53 +00:00
],
[
2025-03-25 11:07:45 +00:00
BoardSlot::new(0, 1, 0, vec2(-15.0, 0.0), world)?, // 0 1 0
BoardSlot::new(0, 1, 1, vec2(-10.0, 0.0), world)?, // 0 1 1
BoardSlot::new(0, 1, 2, vec2(-5.0, 0.0), world)?, // 0 1 2
2023-05-09 14:39:53 +00:00
],
[
2025-03-25 11:07:45 +00:00
BoardSlot::new(0, 2, 0, vec2(-15.0, 15.0), world)?, // 0 2 0
BoardSlot::new(0, 2, 1, vec2(-10.0, 10.0), world)?, // 0 2 1
BoardSlot::new(0, 2, 2, vec2(-5.0, 5.0), world)?, // 0 2 2
2023-05-09 14:39:53 +00:00
],
2025-03-25 11:07:45 +00:00
],
[
[
BoardSlot::new(1, 0, 0, vec2(0.0, -15.0), world)?, // 1 0 0
BoardSlot::new(1, 0, 1, vec2(0.0, -10.0), world)?, // 1 0 1
BoardSlot::new(1, 0, 2, vec2(0.0, -5.0), world)?, // 1 0 2
],
[
BoardSlot::invalid(1, 1, 0), // 1 1 0
BoardSlot::invalid(1, 1, 1), // 1 1 1
BoardSlot::invalid(1, 1, 2), // 1 1 2
],
[
BoardSlot::new(1, 2, 0, vec2(0.0, 15.0), world)?, // 1 2 0
BoardSlot::new(1, 2, 1, vec2(0.0, 10.0), world)?, // 1 2 1
BoardSlot::new(1, 2, 2, vec2(0.0, 5.0), world)?, // 1 2 2
],
],
[
[
BoardSlot::new(2, 0, 0, vec2(15.0, -15.0), world)?, // 2 0 0
BoardSlot::new(2, 0, 1, vec2(10.0, -10.0), world)?, // 2 0 1
BoardSlot::new(2, 0, 2, vec2(5.0, -5.0), world)?, // 2 0 2
],
[
BoardSlot::new(2, 1, 0, vec2(15.0, 0.0), world)?, // 2 1 0
BoardSlot::new(2, 1, 1, vec2(10.0, 0.0), world)?, // 2 1 1
BoardSlot::new(2, 1, 2, vec2(5.0, 0.0), world)?, // 2 1 2
],
[
BoardSlot::new(2, 2, 0, vec2(15.0, 15.0), world)?, // 2 2 0
BoardSlot::new(2, 2, 1, vec2(10.0, 10.0), world)?, // 2 2 1
BoardSlot::new(2, 2, 2, vec2(5.0, 5.0), world)?, // 2 2 2
],
],
];
2023-05-08 18:56:50 +00:00
2023-05-09 14:39:53 +00:00
let distance = 20.0;
2025-03-25 11:07:45 +00:00
let white_start_slots = (16..=16)
.step_by(4)
.map(|x| vec2(x as f32, distance))
.collect()
.try_into()
.unwrap();
2023-05-09 14:39:53 +00:00
2025-03-25 11:07:45 +00:00
let black_start_slots = (16..=16)
.step_by(4)
.map(|x| vec2(x as f32, -distance))
.collect()
.try_into()
.unwrap();
2023-05-09 14:39:53 +00:00
2023-05-09 16:58:07 +00:00
Ok(Self {
2025-03-25 11:07:45 +00:00
_board: board,
2023-05-09 14:39:53 +00:00
center: vec3(0.0, 0.0, 0.0),
2025-03-25 11:07:45 +00:00
_connection_lines: Self::create_connection_lines(world, Color::Black)?,
2023-05-09 14:39:53 +00:00
2025-03-25 11:07:45 +00:00
slots,
2023-05-09 14:39:53 +00:00
white_start_slots,
black_start_slots,
2023-05-09 16:58:07 +00:00
})
2023-05-08 18:56:50 +00:00
}
2023-05-09 14:39:53 +00:00
pub fn center(&self) -> Vector3<f32> {
self.center
}
pub fn white_start_slots(&self) -> &[Vector2<f32>; 9] {
&self.white_start_slots
}
pub fn black_start_slots(&self) -> &[Vector2<f32>; 9] {
&self.black_start_slots
}
2025-03-25 11:39:50 +00:00
pub fn slots(&self) -> &[[[BoardSlot; 3]; 3]; 3] {
&self.slots
}
pub fn slots_mut(&mut self) -> &mut [[[BoardSlot; 3]; 3]; 3] {
2023-05-09 16:58:07 +00:00
&mut self.slots
}
pub fn close_to_marker(&mut self, position: Vector2<f32>) -> Option<&mut BoardSlot> {
2023-05-09 14:39:53 +00:00
const DISTANCE: f32 = 1.25;
2023-05-09 16:58:07 +00:00
for outer in self.slots.iter_mut() {
for inner in outer.iter_mut() {
for slot in inner.iter_mut() {
2023-05-10 18:05:12 +00:00
if *slot.state.lock().unwrap() != BoardSlotState::Invalid {
2023-05-09 14:39:53 +00:00
if (slot.position - position).magnitude() <= DISTANCE {
2023-05-09 16:58:07 +00:00
return Some(slot);
2023-05-09 14:39:53 +00:00
}
}
}
}
}
2023-05-09 16:58:07 +00:00
None
2023-05-09 14:39:53 +00:00
}
2023-05-11 12:00:24 +00:00
pub fn get_neighbours<'a>(
slot: &BoardSlot,
board: &'a [[[BoardSlot; 3]; 3]; 3],
) -> Vec<&'a BoardSlot> {
let mut neighbours = Vec::new();
for i in 0..6 {
// find free neighbour field
if let Some(neighbour) = match i {
0 => {
if slot.x > 0 {
Some(&board[slot.x - 1][slot.y][slot.z])
} else {
None
}
}
1 => {
if slot.x < 2 {
Some(&board[slot.x + 1][slot.y][slot.z])
} else {
None
}
}
2 => {
if slot.y > 0 {
Some(&board[slot.x][slot.y - 1][slot.z])
} else {
None
}
}
3 => {
if slot.y < 2 {
Some(&board[slot.x][slot.y + 1][slot.z])
} else {
None
}
}
4 => {
if slot.z > 0 {
Some(&board[slot.x][slot.y][slot.z - 1])
} else {
None
}
}
5 => {
if slot.z < 2 {
Some(&board[slot.x][slot.y][slot.z + 1])
} else {
None
}
}
_ => unreachable!(),
} {
let neighbour_state = neighbour.state.lock().unwrap();
match *neighbour_state {
BoardSlotState::Empty => {
neighbours.push(neighbour);
}
_ => (),
}
}
}
neighbours
}
2023-05-09 14:39:53 +00:00
}
impl Board {
2025-03-25 11:07:45 +00:00
fn create_board_base(world: &World) -> Result<AssetMesh> {
2023-05-08 18:56:50 +00:00
let mut board_base = AssetMesh::new(
2025-03-25 11:07:45 +00:00
world.resources.get::<Context>().device(),
world
.resources
.get::<EngineSettings>()
.graphics_info()?
.render_type,
2023-05-08 18:56:50 +00:00
)?;
let vertex_buffer = Buffer::builder()
2023-05-09 14:39:53 +00:00
.set_data(&Objects::create_cuboid(
vec3(-22.5, -25.0, -2.0),
vec3(45.0, 50.0, 2.0),
2023-05-08 18:56:50 +00:00
))
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
2025-03-25 11:07:45 +00:00
.build(world.resources.get::<Context>().device().clone())?;
2023-05-08 18:56:50 +00:00
let color = Color::try_from("#b77b2b")?;
let a: [f32; 3] = color.into();
board_base.add_primitive(
vertex_buffer,
None,
None,
PrimitiveMaterial {
color: [a[0], a[1], a[2], 1.0],
metallic_factor: 0.2,
2023-05-09 14:39:53 +00:00
emissive_factor: [0.5, 0.5, 0.5],
2023-05-08 18:56:50 +00:00
roughness_factor: 0.8,
alpha_mode: AlphaMode::Opaque,
alpha_cut_off: 0.5,
},
true,
)?;
Ok(board_base)
}
2025-03-25 11:07:45 +00:00
fn create_connection_lines(world: &mut World, color: Color) -> Result<Vec<Entity>> {
2023-05-09 14:39:53 +00:00
let mut entities = Vec::new();
2025-03-25 11:07:45 +00:00
let mut lines = AssetHandler::create(world).empty_entity();
let draw = Draw::new(vec![{
let mut mesh = AssetMesh::new(
world.resources.get::<Context>().device(),
world
.resources
.get::<EngineSettings>()
.graphics_info()?
.render_type,
)?;
let vertex_buffer = Buffer::builder()
.set_data(
&[
Objects::create_flat_quad([
vec2(-15.25, -15.25),
vec2(15.25, -15.25),
vec2(15.25, -14.75),
vec2(-15.25, -14.75),
]),
Objects::create_flat_quad([
vec2(-10.25, -10.25),
vec2(10.25, -10.25),
vec2(10.25, -9.75),
vec2(-10.25, -9.75),
]),
Objects::create_flat_quad([
vec2(-5.25, -5.25),
vec2(5.25, -5.25),
vec2(5.25, -4.75),
vec2(-5.25, -4.75),
]),
Objects::create_flat_quad([
vec2(-15.25, 14.75),
vec2(15.25, 14.75),
vec2(15.25, 15.25),
vec2(-15.25, 15.25),
]),
Objects::create_flat_quad([
vec2(-10.25, 9.75),
vec2(10.25, 9.75),
vec2(10.25, 10.25),
vec2(-10.25, 10.25),
]),
Objects::create_flat_quad([
vec2(-5.25, 4.75),
vec2(5.25, 4.75),
vec2(5.25, 5.25),
vec2(-5.25, 5.25),
]),
Objects::create_flat_quad([
vec2(-14.75, -15.25),
vec2(-14.75, 15.25),
vec2(-15.25, 15.25),
vec2(-15.25, -15.25),
]),
Objects::create_flat_quad([
vec2(-9.75, -10.25),
vec2(-9.75, 10.25),
vec2(-10.25, 10.25),
vec2(-10.25, -10.25),
]),
Objects::create_flat_quad([
vec2(-4.75, -5.25),
vec2(-4.75, 5.25),
vec2(-5.25, 5.25),
vec2(-5.25, -5.25),
]),
Objects::create_flat_quad([
vec2(15.25, -15.25),
vec2(15.25, 15.25),
vec2(14.75, 15.25),
vec2(14.75, -15.25),
]),
Objects::create_flat_quad([
vec2(10.25, -10.25),
vec2(10.25, 10.25),
vec2(9.75, 10.25),
vec2(9.75, -10.25),
]),
Objects::create_flat_quad([
vec2(5.25, -5.25),
vec2(5.25, 5.25),
vec2(4.75, 5.25),
vec2(4.75, -5.25),
]),
Objects::create_flat_quad([
vec2(0.25, -15.25),
vec2(0.25, -4.75),
vec2(-0.25, -4.75),
vec2(-0.25, -15.25),
]),
Objects::create_flat_quad([
vec2(-0.25, 15.25),
vec2(-0.25, 4.75),
vec2(0.25, 4.75),
vec2(0.25, 15.25),
]),
Objects::create_flat_quad([
vec2(-15.25, -0.25),
vec2(-4.75, -0.25),
vec2(-4.75, 0.25),
vec2(-15.25, 0.25),
]),
Objects::create_flat_quad([
vec2(15.25, 0.25),
vec2(4.75, 0.25),
vec2(4.75, -0.25),
vec2(15.25, -0.25),
]),
]
.concat(),
)
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
.build(world.resources.get::<Context>().device().clone())?;
let a: [f32; 3] = color.into();
mesh.add_primitive(
vertex_buffer,
None,
None,
PrimitiveMaterial {
color: [a[0], a[1], a[2], 1.0],
metallic_factor: 0.2,
emissive_factor: [0.2, 0.2, 0.2],
roughness_factor: 0.8,
alpha_mode: AlphaMode::Opaque,
alpha_cut_off: 0.5,
},
true,
)?;
mesh
}]);
lines.insert_component(draw);
let mut location = Location::from_entity(&mut lines);
location.set_offset(vec3(0.0, 0.0, MillGame::OFFSET_TO_BOARD));
lines.insert_component(location);
entities.push(world.add_entity(lines)?);
2023-05-09 14:39:53 +00:00
Ok(entities)
2023-05-08 18:56:50 +00:00
}
}