OispaHallaAnticheat / src / bot.rs
bot.rs
Raw

use std::fs::File;
use std::io::Write;

use crate::board;
use crate::board::Board;
use crate::direction::Direction;
use crate::recording::Recording;
use crate::board::create_tiles;
use crate::board::is_move_possible;
use crate::board::print_board;

use read_input::prelude::*;

pub fn hack(max_stack_size: usize, max_score: usize, board_size: usize, scoring_function: usize){
    println!("Starting bot with the parameters {:#?}...", (max_stack_size, max_score, board_size, scoring_function));
    let mut stack: Vec<( [[Option<board::tile::Tile>; board::MAX_WIDTH]; board::MAX_HEIGHT], Direction, Recording, usize )> = vec!(); // Where usize is the score
    let mut visited: Vec<( [[Option<board::tile::Tile>; board::MAX_WIDTH]; board::MAX_HEIGHT], Direction )> = vec!();
    let mut b = create_tiles(board_size, board_size);
    b[0][0] = Some( board::tile::Tile::new(0, 0, 2, false) );
    b[1][1] = Some( board::tile::Tile::new(1, 1, 2, false) );
    stack.push( (b, Direction::UP, Recording{history: vec![],width: board_size,height: board_size}, 0) );
    stack.push( (b, Direction::RIGHT, Recording{history: vec![],width: board_size,height: board_size}, 0) );
    stack.push( (b, Direction::DOWN, Recording{history: vec![],width: board_size,height: board_size}, 0) );
    stack.push( (b, Direction::LEFT, Recording{history: vec![],width: board_size,height: board_size}, 0) );

    //let mut actual_stack_size_addition: usize = 0;
    let mut best_score = usize::MIN;
    let mut best_history = Recording{history: vec![],width: board_size,height: board_size};

    let mut last_result: ([[Option<board::tile::Tile>; board::MAX_WIDTH]; board::MAX_HEIGHT], bool, usize ) = ([[None; board::MAX_WIDTH]; board::MAX_HEIGHT], false, 42069);

    loop{
        //let max_stack_size: usize = 1000;
        if stack.len() > max_stack_size{
            stack.remove(0);
            //actual_stack_size_addition += 1;
        }
        if best_score >= max_score{
            break;
        }
        if stack.len() > 0 {
            let data = stack.pop();
            let d = data.unwrap();
            let mut history = d.2.history;
            if !visited.contains( &(d.0, d.1) ) || false {
                let boarddata = d.0;
                let dir = d.1;
                let current_score = d.3;

                let board = Board{tiles: boarddata, width: d.2.width, height: d.2.height};
                let next = is_move_possible(board, dir);
                let score_addition = next.2;

                //visited.push( (d.0, d.1) );

                if next.1 {
                    visited.push( (boarddata, dir) );

                    let non_occupied = Board{tiles: next.0, width: d.2.width, height: d.2.height}.get_non_occupied_tiles();
                    let mut addition: Option<board::tile::Tile> = None;
                    if non_occupied.len() > 0{
                        let mut t = non_occupied[0];
                        t.value = 4;
                        addition = Some(t);
                    }

                    history.push( (boarddata, dir, addition) );
                    let r = Recording{history, width: d.2.width, height: d.2.height};
                    let mut score = current_score + score_addition;//board.get_total_value(); //stack.len() + actual_stack_size_addition;
                    if scoring_function == 1 {
                        score = board.get_total_value();
                    }
                    if score > best_score {
                        best_score = score;
                        best_history = r.clone();
                    }
                    let mut next_board = next.0;
                    match addition{
                        None => {},
                        Some(t) => {next_board[t.y][t.x] = Some(t)}
                    }
                    stack.push( (next_board, Direction::UP, r.clone(), current_score + score_addition) );
                    stack.push( (next_board, Direction::RIGHT, r.clone(), current_score + score_addition) );
                    stack.push( (next_board, Direction::DOWN, r.clone(), current_score + score_addition) );
                    stack.push( (next_board, Direction::LEFT, r.clone(), current_score + score_addition) );
                }
                else {
                    if stack.len() > 20 {
                        last_result = next;
                    }
                }
            }
            else{
                //println!("Visited already contains {:?}", (d.0, d.1));
            }
        }
        else{
            break;
        }
        //print!("Best score:         Stack size:             \r");
        print!("Best score: {}        Stack size: {}          \r", best_score, stack.len());
    }
    println!("");
    println!("Done!");
    println!("Best score: {}", best_score);
    let index = best_history.history.len() - 1;
    let i = best_history.history[index];
    println!("History at index {}:", index);
    print_board(i.0, board_size, board_size);
    println!("move to direction {:?} and add {:?}", i.1, i.2);
    println!("---------------------------------------------");
    println!("Last failed result:");
    println!("{:?}", last_result);
    println!("---------------------------------------------");
    println!("Gimme the code? (true/false)");
    let analyze = true; //input::<bool>().get();
    if analyze{
        println!("Choose: ");
        println!("\t0: Exit");
        println!("\t1: HAC validation url");
        println!("\t2: HAC history");
        println!("\t3: both");
        let thisorthat = input::<usize>().get();
        if thisorthat == 0{
            println!("Bye!");
        }
        if thisorthat == 1{
            //println!("https://hac.oispahalla.com:8000/HAC/validate/{}", best_history.to_string());
            let mut file = File::create("hac_url.txt").unwrap();
            let result = file.write_all( format!("https://hac.oispahalla.com:8000/HAC/validate/{}x{}S{}", best_history.width, best_history.height, best_history.to_string()).as_bytes() );
            println!("Result of writing to hac_url.txt: {:?}", result);
        }
        if thisorthat == 2{
            println!();
            let b = Board{tiles: best_history.history[best_history.history.len() - 1].0, width: best_history.width, height: best_history.height};

            let mut file1 = File::create("gameState.txt").unwrap();
            let mut file2 = File::create("HAC_history.txt").unwrap();

            let result1 = file1.write_all( b.oispahalla_serialize().as_str().replace("\\", "").replace("SCOREHERE", &best_score.to_string()).as_bytes() );
            println!("Result of writing to gameState.txt: {:?}", result1);

            let result2 = file2.write_all( format!("{:?}", best_history.to_string().split(":").collect::<Vec<&str>>()).as_bytes() );
            println!("Result of writing to HAC_history.txt: {:?}", result2);
        }
        if thisorthat == 3{
            // HAC validation url
            let mut file = File::create("hac_url.txt").unwrap();
            let result = file.write_all( format!("https://hac.oispahalla.com:8000/HAC/validate/{}x{}S{}", best_history.width, best_history.height, best_history.to_string()).as_bytes() );
            println!("Result of writing to hac_url.txt: {:?}", result);
            // Game data
            println!();
            let b = Board{tiles: best_history.history[best_history.history.len() - 1].0, width: best_history.width, height: best_history.height};

            let mut file1 = File::create("gameState.txt").unwrap();
            let mut file2 = File::create("HAC_history.txt").unwrap();

            let result1 = file1.write_all( b.oispahalla_serialize().as_str().replace("\\", "").replace("SCOREHERE", &best_score.to_string()).as_bytes() );
            println!("Result of writing to gameState.txt: {:?}", result1);

            let result2 = file2.write_all( format!("{:?}", best_history.to_string().split(":").collect::<Vec<&str>>()).as_bytes() );
            println!("Result of writing to HAC_history.txt: {:?}", result2);
        }
    }
}