use crate::game::component::*;

use std::marker::PhantomData;
use std::sync::{Arc, atomic::{AtomicU32, Ordering}, Mutex};
use std::{borrow::BorrowMut, collections::{HashSet, LinkedList, HashMap}};
use std::path::Path;
use std::fs;

use futures::SinkExt;
use rocksdb::{self, ColumnFamilyDescriptor, DBWithThreadMode, DB, DBCommon, MultiThreaded, SingleThreaded, IteratorMode, Options, BlockBasedOptions, Cache, WriteBatch};
use rayon::iter::{IntoParallelRefIterator, IntoParallelIterator, IndexedParallelIterator, ParallelIterator, IntoParallelRefMutIterator, ParallelBridge};

pub struct BigamePrwiShrinklast<T>// T:1234, T0:123, T1:124
{
    winning_nrx_iso2distid2dist_n_weight_tables: HashMap<usize, (Vec<u32>, Vec<[i64; 3]>, Vec<u32>)>,
    winning_prxf1_iso2traceid2trace_n_weight_tables: HashMap<usize, (Vec<u32>, Vec<Vec<u32>>, Vec<u32>)>,
    _marker: PhantomData<T>,
}

impl<T> BigamePrwiShrinklast<T>
    where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static,
{
    pub fn new()-> Self{
        assert!(T::NUM_STREET > 1);
        let db = Self::load_db();

        let mut winning_nrx_iso2distid2dist_n_weight_tables = HashMap::<usize, (Vec<u32>, Vec<[i64; 3]>, Vec<u32>)>::new();;
        let mut winning_prxf1_iso2traceid2trace_n_weight_tables = HashMap::<usize, (Vec<u32>, Vec<Vec<u32>>, Vec<u32>)>::new();
        for st in 0..T::NUM_STREET as usize {
            let winning_nrx_iso2distid2dist_n_weight_street = Self::handle_winning_dist_street_nrx(&db, st);

            let winning_prxf1_iso2traceid2trace_n_weight_street = if st == 0 {
                None
            } else if st == T::NUM_STREET as usize  - 1 {
                Some(Self::handle_winning_trace_last_street_prxf1(&db))
            }
            else {
                Some(Self::handle_winning_trace_nonlast_street_prxf1(&db, st))
            };

            winning_nrx_iso2distid2dist_n_weight_tables.insert(st, winning_nrx_iso2distid2dist_n_weight_street);
            if let Some(winning_prxf1_iso2traceid2trace_n_weight_street) = winning_prxf1_iso2traceid2trace_n_weight_street{
                winning_prxf1_iso2traceid2trace_n_weight_tables.insert(st, winning_prxf1_iso2traceid2trace_n_weight_street);
            }
        }
        Self {
            winning_nrx_iso2distid2dist_n_weight_tables,
            winning_prxf1_iso2traceid2trace_n_weight_tables,
            _marker: PhantomData
        }
        //////////////////////////////////////////////////////////////////////
        // let db = Self::load_db();
        // let mut winning_nrx_iso2distid2dist_tables = vec![];
        // let mut winning_prxf1_iso2traceid2trace_tables = vec![];
        // let mut winning_trace_prxf1_traceid2weight_tables = vec![];
        // for st in 0..T::NUM_STREET {
        //     winning_nrx_iso2distid2dist_tables.push(Self::handle_last_street_nrx(&db, st as usize));
        //     let winning_prxf1_iso2traceid2trace_street = if st < T::NUM_STREET - 1 {
        //         Self::handle_last_street_prxf1(&db)
        //     }
        //     else {
        //         Self::handle_street_prxf1(&db, st as usize)
        //     };
        //     let winning_trace_prxf1_traceid2weight_street = Self::handle_street_weight(&winning_prxf1_iso2traceid2trace_street, st as usize);
        //     winning_prxf1_iso2traceid2trace_tables.push(winning_prxf1_iso2traceid2trace_street);
        //     winning_trace_prxf1_traceid2weight_tables.push(winning_trace_prxf1_traceid2weight_street);
        // }
        // Self {
        //     winning_nrx_iso2distid2dist_tables,
        //     winning_prxf1_iso2traceid2trace_tables,
        //     winning_trace_prxf1_traceid2weight_tables,
        //     _marker: PhantomData
        // }
    }

    fn handle_winning_dist_street_nrx(db: &DB, street: usize) -> (Vec<u32>, Vec<[i64; 3]>, Vec<u32>){
        
        let (original_nriso2wdistid, original_nrid2wdist) = Self::load_winning_nrx_iso2distid2dist(db, street);
        let  (original_nriso_size, wdistid_size) = (original_nriso2wdistid.len()-1, original_nrid2wdist.len());
        let mut original_nriso2wdistid = original_nriso2wdistid;
        
        // 统计weight
        let mut start = std::time::Instant::now();
        let original_nrid2weight: Vec<AtomicU32> = (0..wdistid_size).into_par_iter().map(|_| AtomicU32::new(0)).collect();
        original_nriso2wdistid
            .par_iter().enumerate().for_each(|(nriso, &wdistid)|{
                let addr = T::instance().hand_index_volumn(nriso, street, street) as u32;
                original_nrid2weight[wdistid as usize].fetch_add(addr, Ordering::Relaxed);
                if nriso % 1000003 == 0 { // 质数
                    println!("完成nriso2weight打点 部分{},  {:?}", nriso / 1000003, start.elapsed());
                }
            });
        println!("统计第{}街nrid2weight打点，用时{:?}", street, start.elapsed()); start = std::time::Instant::now();
        let original_nrid2weight: Vec<u32> = original_nrid2weight
            .par_iter()
            .map(|x| x.load(Ordering::Relaxed))
            .collect();
        println!("nrid2weight从atomicU32改成u32，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let checksum = original_nrid2weight.par_iter().map(|&x| x as u64).sum::<u64>();
        println!("nrid2weight的校验和值为{}, 用时{:?}", checksum, start.elapsed()); start = std::time::Instant::now();

        original_nriso2wdistid.push(wdistid_size as u32);
        (original_nriso2wdistid, original_nrid2wdist, original_nrid2weight)
    }


    fn handle_winning_trace_last_street_prxf1(db: &DB) -> (Vec<u32>, Vec<Vec<u32>>, Vec<u32>){
        
        let mut street = T::NUM_STREET as usize -1;
        let (original_priso2traceid, original_prid2trace) = Self::load_winning_prxf1_iso2traceid2trace(db, street);
        let  (original_priso_size, traceid_size) = (original_priso2traceid.len()-1, original_prid2trace.len());
        
        println!("这是最后一街，先shrink");
        let mut start = std::time::Instant::now();
        let original_prid2shrinked_trace: Vec<Vec<u32>> = original_prid2trace
            .par_iter().map(|original_trace| {
                original_trace.iter().enumerate()
                    .filter_map(|(index, &value)| if index != 1 { Some(value) } else { None })
                    .collect()
            })
            .collect();
        println!("构造original_prid2shrinked_trace，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let shrinked_prid2trace: Vec<Vec<u32>> = {
            let shrinked_trace_set: HashSet<_> = original_prid2shrinked_trace.par_iter().cloned().collect();
            shrinked_trace_set.into_par_iter().collect()
        };
        println!("构造shrinked_prid2trace，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let shrinked_trace2prid =  {
            let mut shrinked_trace2prid = HashMap::<Vec<u32>, u32>::new();
            let shrinked_trace2prid_pairs = shrinked_prid2trace
                .par_iter().enumerate().map(|(idx, trace)| (trace.clone(), idx as u32)).collect::<Vec<_>>();
            shrinked_trace2prid.extend(shrinked_trace2prid_pairs.into_iter());
            shrinked_trace2prid
        };
        println!("构造shrinked_trace2prid，用时{:?}", start.elapsed()); start = std::time::Instant::now();

        let shrinked_num_street = T::NUM_STREET as usize - 1;
        let shrinked_last_waugh = {
            let mut shrinked_deal_hole: Vec<usize> = T::DEAL_HOLE_STREET[..shrinked_num_street]
                .iter().map(|deal| *deal as usize).collect();
            *shrinked_deal_hole.last_mut().unwrap() += T::DEAL_HOLE_STREET[shrinked_num_street] as usize;
            let mut shrinked_deal_board: Vec<usize> = T::DEAL_BOARD_STREET[..shrinked_num_street]
                .iter().map(|deal| *deal as usize).collect();
            *shrinked_deal_board.last_mut().unwrap() += T::DEAL_BOARD_STREET[shrinked_num_street] as usize;
            hand_indexer::init_hand_indexer(T::SUITS, T::RANKS, shrinked_deal_hole, shrinked_deal_board)
        };

        let shrinked_last_street = shrinked_num_street-1;
        let original_last_street = T::NUM_STREET as usize - 1;
        let shrinked_priso_size: usize = shrinked_last_waugh.iso_size_street(/*last street */ shrinked_last_street);
        let mut shrinked_priso2traceid: Vec<u32> = (0..shrinked_priso_size)
            .into_par_iter().map(|shrinked_priso| {
                let hand_spilt = shrinked_last_waugh.reduction(shrinked_priso, shrinked_last_street);
                let hand = hand_spilt.into_iter().flatten().collect::<Vec<u8>>();
                let original_priso = T::instance().hand_indexify(&hand, original_last_street, 0);
                let original_traceid = original_priso2traceid[original_priso];
                let shrinked_trace = &original_prid2shrinked_trace[original_traceid as usize];
                let shrinked_traceid = shrinked_trace2prid.get(shrinked_trace).unwrap();
                *shrinked_traceid
            }).collect();
        println!("构造shrinked_priso2traceid，用时{:?}", start.elapsed()); start = std::time::Instant::now();

        // 统计weight
        let shrinked_prid2weight: Vec<AtomicU32> = (0..traceid_size).into_par_iter().map(|_| AtomicU32::new(0)).collect();
        shrinked_priso2traceid
            .par_iter().enumerate().for_each(|(priso, &traceid)|{
                let addr = shrinked_last_waugh.reduction_class_num(priso, shrinked_last_street) as u32;
                shrinked_prid2weight[traceid as usize].fetch_add(addr, Ordering::Relaxed);
                if priso % 1000003 == 0 { // 质数
                    println!("完成priso2weight打点 部分{},  {:?}", priso / 1000003, start.elapsed());
                }
            });
        println!("统计最后街prid2weight打点，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let shrinked_prid2weight: Vec<u32> = shrinked_prid2weight
            .par_iter()
            .map(|x| x.load(Ordering::Relaxed))
            .collect();
        println!("prid2weight从atomicU32改成u32，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let checksum = shrinked_prid2weight.par_iter().map(|&x| x as u64).sum::<u64>();
        println!("prid2weight的校验和值为{}, 用时{:?}", checksum, start.elapsed()); start = std::time::Instant::now();

        /////////////////////////////////////////////////////////////////////////////
        shrinked_priso2traceid.push(shrinked_prid2trace.len() as u32);
        (shrinked_priso2traceid, shrinked_prid2trace, shrinked_prid2weight)

        // let time = std::time::Instant::now();
        // let recall_from = 0;
        // let result1 = Self::load_wtdistid_with_kriso_single(street as usize, recall_from);
        // println!("single cache cost: {:?}", time.elapsed());

        // let time = std::time::Instant::now();
        // let result2 = Self::load_wtdistid_with_kriso_back(street as usize, recall_from);
        // println!("single thread cost: {:?}", time.elapsed());

        // let time = std::time::Instant::now();
        // assert!(result1.0.par_iter().zip(result2.0.par_iter()).all(|(&a, &b)| a == b as u32), "The vectors are not equal!");
        // println!("assert result1 == result2 : {:?}", time.elapsed());

    }

    fn handle_winning_trace_nonlast_street_prxf1(db: &DB, street: usize) -> (Vec<u32>, Vec<Vec<u32>>, Vec<u32>){
        assert!(street < T::NUM_STREET as usize -1); 
        let (original_priso2traceid, original_prid2trace) = Self::load_winning_prxf1_iso2traceid2trace(db, street);
        let  (original_priso_size, traceid_size) = (original_priso2traceid.len()-1, original_prid2trace.len());
        let mut original_priso2traceid = original_priso2traceid;
        
        // 统计weight
        let mut start = std::time::Instant::now();
        let original_prid2weight: Vec<AtomicU32> = (0..traceid_size).into_par_iter().map(|_| AtomicU32::new(0)).collect();
        original_priso2traceid
            .par_iter().enumerate().for_each(|(priso, &traceid)|{
                let addr = T::instance().hand_index_volumn(priso, street, 0) as u32;
                original_prid2weight[traceid as usize].fetch_add(addr, Ordering::Relaxed);
                if priso % 1000003 == 0 { // 质数
                    println!("完成kriso2weight打点 部分{},  {:?}", priso / 1000003, start.elapsed());
                }
            });
        println!("统计第{}街prid2weight打点，用时{:?}", street, start.elapsed()); start = std::time::Instant::now();
        let original_prid2weight: Vec<u32> = original_prid2weight
            .par_iter()
            .map(|x| x.load(Ordering::Relaxed))
            .collect();
        println!("prid2weight从atomicU32改成u32，用时{:?}", start.elapsed()); start = std::time::Instant::now();
        let checksum = original_prid2weight.par_iter().map(|&x| x as u64).sum::<u64>();
        println!("prid2weight的校验和值为{}, 用时{:?}", checksum, start.elapsed()); start = std::time::Instant::now();

        original_priso2traceid.push(traceid_size as u32);
        (original_priso2traceid, original_prid2trace, original_prid2weight)
    }

    fn load_db() -> DB
        where T: Singleton + Hand + WaughTrait + ShowdownRanker + 'static
    {
        let mut start = std::time::Instant::now();
        // 确定数据库、列族，以及打开数据库
        let path = std::format!("data/{}", T::GAME_NAME);
        let options = {
            let mut options = Options::default();
            options.create_if_missing(false);
            options
        };
        let cf_names = DB::list_cf(&Options::default(), &path).unwrap();
        println!("S1: {:?}", start.elapsed());
        let cf_descriptors: Vec<_> = cf_names
            .iter()
            .map(|cf_name| {
                let mut cf_opt = Options::default();
                cf_opt.create_if_missing(false);
                ColumnFamilyDescriptor::new(cf_name.as_str(), cf_opt)
            })
            .collect();
        println!("打开数据库的前置工作，感觉用不了多少时间{:?}", start.elapsed()); start = std::time::Instant::now();
        let db = DBCommon::<SingleThreaded,_>::open_cf_descriptors_read_only(&options, &path , cf_descriptors, false).expect(&format!("打不开这个数据库{}的列族{:?}", path, cf_names));
        println!("打开数据库用时{:?}", start.elapsed()); start = std::time::Instant::now();
        db
    }

    fn load_winning_nrx_iso2distid2dist(db: &DB, street: usize)->(Vec<u32>, Vec<[i64; 3]>) {
        let mut start = std::time::Instant::now();
        let nriso2wdistid_table_name = format!("{}_nriso_{}_to_winning_distribution_id", T::GAME_NAME, street+1);
        let cf_handle = db.cf_handle(&nriso2wdistid_table_name).expect(&format!("没有这个列族:{}", nriso2wdistid_table_name));
        println!("打开列族{}, 用时{:?}", nriso2wdistid_table_name, start.elapsed()); start = std::time::Instant::now();

        // 读street中的最后一位数据，代表的是distsize
        let isosize = T::instance().hand_isomorphism_size_street(street, street);
        let distsize = db.get_cf(&cf_handle, (isosize as u32).to_be_bytes()).expect(&format!("isosize/key:{}在{}街的值为None", isosize, street)).unwrap();
        let distsize = u32::from_be_bytes((*distsize).try_into().unwrap()) as usize;

        // 把所有distid读出来，并且校验（校验的逻辑是最后一位是否是distsize，把所有数据去重之后长度是否为distsize）
        let mut dbcf_iter = db.iterator_cf(cf_handle, IteratorMode::Start);
        let mut kriso2wdistid = vec![distsize as u32 +1; isosize+1];
        for item in dbcf_iter {
            let (keybytes, valuebytes) = item.unwrap();
            assert!(keybytes.len() == 4 && valuebytes.len() == 4);
            let iso = u32::from_be_bytes((*keybytes).try_into().unwrap()) as usize;
            let wdistid = u32::from_be_bytes((*valuebytes).try_into().unwrap());
            kriso2wdistid[iso] = wdistid;
        }
        println!("完成读列族{}数据，用时{:?}", nriso2wdistid_table_name, start.elapsed()); start = std::time::Instant::now();
        assert_eq!(kriso2wdistid.pop().unwrap(), distsize as u32);
        let unique: HashSet<_> = kriso2wdistid.par_iter().cloned().collect();
        assert_eq!(unique.len(), distsize);
        println!("对nrsio2wdistid去重,验证wdist的个数为{}, 用时{:?}", distsize, start.elapsed()); start = std::time::Instant::now();
///////////////////////////////////////////////////////////////////////////////////////
        let nrid2wdist_table_name = format!("{}_nrid_{}_to_winning_distribution", T::GAME_NAME, street+1);

        // 读取wtdist
        let cf_handle = db.cf_handle(&nrid2wdist_table_name).expect(&format!("没有这个列族:{}", nrid2wdist_table_name));
        println!("打开列族{}, 用时{:?}", nrid2wdist_table_name, start.elapsed()); start = std::time::Instant::now();
        // 把所有distid读出来，并且校验（校验的逻辑是最后一位是否是distsize，把所有数据去重之后长度是否为distsize）
        let mut dbcf_iter = db.iterator_cf(cf_handle, IteratorMode::Start);
        let mut krid2wdist: Vec<[i64; 3]> = Vec::with_capacity(distsize);
        for item in dbcf_iter {
            let (keybytes, valuebytes) = item.unwrap();
            assert!(keybytes.len() == 4);
            let distid = u32::from_be_bytes((*keybytes).try_into().unwrap()) as usize;
            let wdist: [i64; 3] = bincode::deserialize(&valuebytes).unwrap();
            krid2wdist.push(wdist);
            assert_eq!(distid, krid2wdist.len()-1);
        }
        println!("完成读列族{}数据，用时{:?}", nrid2wdist_table_name, start.elapsed()); start = std::time::Instant::now();
////////////////////////////////////////////////////////////
        // 返回结果
        (kriso2wdistid, krid2wdist)
    }

    fn load_winning_prxf1_iso2traceid2trace(db: &DB, street: usize)->(Vec<u32>, Vec<Vec<u32>>) {
        let mut start = std::time::Instant::now();
        let priso2traceid_table_name = format!("{}_priso_{}_from_1_to_winning_trace_distribution_id", T::GAME_NAME, street+1);
        let cf_handle = db.cf_handle(&priso2traceid_table_name).expect(&format!("没有这个列族:{}", priso2traceid_table_name));
        println!("打开列族{}, 用时{:?}", priso2traceid_table_name, start.elapsed()); start = std::time::Instant::now();

        // 读street中的最后一位数据，代表的是distsize
        let isosize = T::instance().hand_isomorphism_size_street(street, 0);
        let distsize = db.get_cf(&cf_handle, (isosize as u32).to_be_bytes()).expect(&format!("isosize/key:{}在{}街的值为None", isosize, street)).unwrap();
        let distsize = u32::from_be_bytes((*distsize).try_into().unwrap()) as usize;

        // 把所有distid读出来，并且校验（校验的逻辑是最后一位是否是distsize，把所有数据去重之后长度是否为distsize）
        let mut dbcf_iter = db.iterator_cf(cf_handle, IteratorMode::Start);
        let mut kriso2wtdistid = vec![distsize as u32 +1; isosize+1];
        for item in dbcf_iter {
            let (keybytes, valuebytes) = item.unwrap();
            assert!(keybytes.len() == 4 && valuebytes.len() == 4);
            let iso = u32::from_be_bytes((*keybytes).try_into().unwrap()) as usize;
            let wtdistid = u32::from_be_bytes((*valuebytes).try_into().unwrap());
            kriso2wtdistid[iso] = wtdistid;
        }
        println!("完成读列族{}数据，用时{:?}", priso2traceid_table_name, start.elapsed()); start = std::time::Instant::now();
        assert_eq!(kriso2wtdistid.pop().unwrap(), distsize as u32);
        let unique: HashSet<_> = kriso2wtdistid.par_iter().cloned().collect();
        assert_eq!(unique.len(), distsize);
        println!("对prsio2wdistid去重,验证wdist的个数为{}, 用时{:?}", distsize, start.elapsed()); start = std::time::Instant::now();
///////////////////////////////////////////////////////////////////////////////////////
        let prid2trace_table_name = format!("{}_prid_{}_from_1_to_winning_trace_distribution", T::GAME_NAME, street+1);

        // 读取wtdist
        let cf_handle = db.cf_handle(&prid2trace_table_name).expect(&format!("没有这个列族:{}", prid2trace_table_name));
        println!("打开列族{}, 用时{:?}", prid2trace_table_name, start.elapsed()); start = std::time::Instant::now();
        // 把所有distid读出来，并且校验（校验的逻辑是最后一位是否是distsize，把所有数据去重之后长度是否为distsize）
        let mut dbcf_iter = db.iterator_cf(cf_handle, IteratorMode::Start);
        let mut krid2wtdist: Vec<Vec<u32>> = Vec::with_capacity(distsize);
        for item in dbcf_iter {
            let (keybytes, valuebytes) = item.unwrap();
            assert!(keybytes.len() == 4);
            let distid = u32::from_be_bytes((*keybytes).try_into().unwrap()) as usize;
            let dist: Vec<u32> = bincode::deserialize(&valuebytes).unwrap();
            krid2wtdist.push(dist);
            assert_eq!(distid, krid2wtdist.len()-1);
        }
        println!("完成读列族{}数据，用时{:?}", prid2trace_table_name, start.elapsed()); start = std::time::Instant::now();
////////////////////////////////////////////////////////////
        // 返回结果
        (kriso2wtdistid, krid2wtdist)
    }

    pub fn save(&self){
        let street_num = T::NUM_STREET as usize - 1;
        fn truncate_last_char(input: &str) -> String {
            if input.is_empty() {
                return String::new(); // 如果输入为空字符串，返回空字符串
            }
        
            let mut chars = input.chars(); // 创建一个字符迭代器
            chars.next_back(); // 移除最后一个字符
        
            chars.collect() // 收集剩下的字符形成新的字符串
        }
        let game1 = truncate_last_char(T::GAME_NAME);
        self.save_db(&game1, &(0..street_num).into_iter().collect::<Vec<_>>());

        fn truncate_and_add(input: &str) -> String {
            if input.len() < 2 {
                return input.to_string(); // 如果字符串长度小于2，直接返回
            }
        
            let mut chars: Vec<char> = input.chars().collect(); // 将字符串转换为字符向量
            let last_char = chars.pop().unwrap(); // 移除并获取最后一个字符
            let second_last_char = chars.pop().unwrap(); // 移除并获取倒数第二个字符
        
            // 将字符转换为数字并相加
            let last_digit = last_char.to_digit(10).unwrap();
            let second_last_digit = second_last_char.to_digit(10).unwrap();
            let new_digit = last_digit + second_last_digit;
        
            // 将新数字分解为字符并添加回字符向量
            if new_digit >= 10 {
                chars.push(std::char::from_digit(new_digit / 10, 10).unwrap());
                chars.push(std::char::from_digit(new_digit % 10, 10).unwrap());
            } else {
                chars.push(std::char::from_digit(new_digit, 10).unwrap());
            }
        
            chars.into_iter().collect() // 将字符向量重新组合成字符串
        }

        let game2 = truncate_and_add(T::GAME_NAME);
        let mut streets: Vec<usize> = (0..{street_num-1}).into_iter().collect(); streets.push(street_num);
        self.save_db(&game2, &streets);
    }
    
    fn save_db(&self, db_name: &str, streets: &[usize]){
        let street_num = streets.len();
        let path_str = std::format!("data/{}", db_name);
        let path = Path::new(path_str.as_str());
        if path.exists() {
            fs::remove_dir_all(path).unwrap();
        }
        fs::create_dir_all(path).unwrap();

        // 创建一个选项对象
        let mut opts = Options::default();
        // 设置数据库如果不存在则创建
        opts.create_if_missing(true);
        let mut db = DB::open(&opts, path).unwrap();
        for (street, &original_street) in streets.iter().enumerate() {
            self.save_winning_nrx_iso2distid2dist_n_weight(&mut db, db_name, street, original_street);
            if street > 0 {
                self.save_winning_prxf1_iso2distid2dist_n_weight(&mut db, db_name, street, original_street);
            }
        }
    }

    fn save_winning_nrx_iso2distid2dist_n_weight(&self, db: &mut DB, game_name: &str, street: usize, original_street: usize) {
        let (nriso2wdistid, nrid2wdist, nrid2weight) = self.winning_nrx_iso2distid2dist_n_weight_tables.get(&original_street).unwrap();

        let mut start = std::time::Instant::now();
        let cf_name_iso2distid = format!("{}_nriso_{}_to_winning_distribution_id", game_name, street+1);
        if db.cf_handle(cf_name_iso2distid.as_str()).is_some() {
            db.drop_cf(cf_name_iso2distid.as_str()).unwrap();
        }
        db.create_cf(cf_name_iso2distid.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_iso2distid.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (kriso, wdistid) in nriso2wdistid.iter().enumerate() {
            let kriso = kriso as u32;
            let wdistid = *wdistid as u32; 
            batch.put_cf(kvcf, kriso.to_be_bytes(), wdistid.to_be_bytes());
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_iso2distid, start.elapsed()); start = std::time::Instant::now();
    
        let cf_name_distid2dist = format!("{}_nrid_{}_to_winning_distribution", game_name, street+1);
        if db.cf_handle(cf_name_distid2dist.as_str()).is_some() {
            db.drop_cf(cf_name_distid2dist.as_str()).unwrap();
        }
        db.create_cf(cf_name_distid2dist.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_distid2dist.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (krid, wdist) in nrid2wdist.iter().enumerate() {
            let krid = krid as u32;
            let wdist = bincode::serialize(&(*wdist)).unwrap(); 
            batch.put_cf(kvcf, krid.to_be_bytes(), wdist);
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_distid2dist, start.elapsed()); start = std::time::Instant::now();

        let cf_name_distid2weight = format!("{}_nrid_{}_to_winning_distribution_weight", game_name, street+1);
        if db.cf_handle(cf_name_distid2weight.as_str()).is_some() {
            db.drop_cf(cf_name_distid2weight.as_str()).unwrap();
        }
        db.create_cf(cf_name_distid2weight.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_distid2weight.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (krid, weight) in nrid2weight.iter().enumerate() {
            let krid = krid as u32;
            let weight = *weight as u32; 
            batch.put_cf(kvcf, krid.to_be_bytes(), weight.to_be_bytes());
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_distid2weight, start.elapsed()); start = std::time::Instant::now();
    }

    fn save_winning_prxf1_iso2distid2dist_n_weight(&self, db: &mut DB, game_name: &str, street: usize, original_street: usize) {
        let (priso2wtdistid, prid2wtdist, prid2weight) = self.winning_prxf1_iso2traceid2trace_n_weight_tables.get(&original_street).unwrap();

        let mut start = std::time::Instant::now();
        let cf_name_iso2distid = format!("{}_priso_{}_from_1_to_winning_trace_distribution_id", game_name, street+1);
        if db.cf_handle(cf_name_iso2distid.as_str()).is_some() {
            db.drop_cf(cf_name_iso2distid.as_str()).unwrap();
        }
        db.create_cf(cf_name_iso2distid.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_iso2distid.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (kriso, wtdistid) in priso2wtdistid.iter().enumerate() {
            let kriso = kriso as u32;
            let wtdistid = *wtdistid as u32; 
            batch.put_cf(kvcf, kriso.to_be_bytes(), wtdistid.to_be_bytes());
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_iso2distid, start.elapsed()); start = std::time::Instant::now();
    
        let cf_name_distid2dist = format!("{}_prid_{}_from_1_to_winning_trace_distribution", game_name, street+1);
        if db.cf_handle(cf_name_distid2dist.as_str()).is_some() {
            db.drop_cf(cf_name_distid2dist.as_str()).unwrap();
        }
        db.create_cf(cf_name_distid2dist.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_distid2dist.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (krid, wtdist) in prid2wtdist.iter().enumerate() {
            let krid = krid as u32;
            let wtdist = bincode::serialize(&(*wtdist)).unwrap(); 
            batch.put_cf(kvcf, krid.to_be_bytes(), wtdist);
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_distid2dist, start.elapsed()); start = std::time::Instant::now();

        let cf_name_distid2weight = format!("{}_prid_{}_from_1_to_winning_distribution_weight", game_name, street+1);
        if db.cf_handle(cf_name_distid2weight.as_str()).is_some() {
            db.drop_cf(cf_name_distid2weight.as_str()).unwrap();
        }
        db.create_cf(cf_name_distid2weight.as_str(), &Options::default()).unwrap();
        let kvcf = db.cf_handle(cf_name_distid2weight.as_str()).unwrap();
        let mut batch = WriteBatch::default();
        for (krid, weight) in prid2weight.iter().enumerate() {
            let krid = krid as u32;
            let weight = *weight as u32; 
            batch.put_cf(kvcf, krid.to_be_bytes(), weight.to_be_bytes());
        }
        db.write(batch).expect("写入失败");
        println!("写入{}数据库{}列族，用时{:?}", game_name, cf_name_distid2weight, start.elapsed()); start = std::time::Instant::now();
    }
}