use {
    crate::dqn,
    crate::config::*,
};

use rand::*;
use anyhow::*;

#[derive(Clone, Copy)]
struct maze{
    data: [u32;WIDTH*HEIGHT],
}

impl dqn::Simulation for maze{
    fn reward(&self, a: usize) -> Result<FLOAT>{
        match self.data[a]{
            TRAILCOLOR | ROBOCOLOR => Ok(FEAR),
            WALLCOLOR  => Err(anyhow!("Agent hit a wall at {}", a)),
            _ => Ok(0.0),
        }
    }
}

impl maze{
    pub fn action_index(&self, a: (usize, usize), i: usize) -> u32{
        if i == a.0{
            return TRAILCOLOR
        }
        if i == a.1{
            return if self.data[a.1] == WALLCOLOR{
                WALLCOLOR
            }else{
                ROBOCOLOR
            }
        }
        self.data[i]
    }

    pub fn new() -> [u32;WIDTH*HEIGHT]{
        let mut buffer  = [BGCOLOR;WIDTH*HEIGHT];
        for n in 0..buffer.len(){
            if n < WIDTH{
                buffer[n] = WALLCOLOR;
                continue
            }
            if n % WIDTH == 0{
                buffer[n] = WALLCOLOR;
                continue
            }
            if n > WIDTH*(HEIGHT-1){
                buffer[n] = WALLCOLOR;
                continue
            }
            if n % WIDTH == WIDTH-1{
                buffer[n] = WALLCOLOR;
                continue
            }
            if n % (WIDTH + 1) == 0 || n % (WIDTH + 1) == 1{
                continue
            }

            if random::<f32>() < ( 4 - DIRS.iter().map(|dir|{
                if buffer[dir(n)] == WALLCOLOR{
                    return 1
                }
                0
            }).sum::<u8>()) as f32 * 0.1{
                buffer[n] = WALLCOLOR
            }else if random::<f32>() < 0.01{
                buffer[n] = POINTCOLOR;
            }
        }
        buffer
    }
}
