简体   繁体   English

代表给定范围内所有数字的最佳方法是什么? (一些限制)

[英]What is the best way to represent all numbers in a given range? (some restrictions)

Background: Creating a game similar to Mastermind but on steroids. 背景:制作类似于Mastermind的游戏,但使用类固醇。 Currently trying to optimize AI and also increase my limits. 目前正在尝试优化AI并增加我的极限。 Let me explain: 让我解释:

For my AI algorithm I need to produce some sort of data structure that can represent all possible numbers given 0 - a limit. 对于我的AI算法,我需要生成某种数据结构,该数据结构可以表示给定0(限制)的所有可能数字。 I also need to remove numbers from such structure to reflect possible numbers. 我还需要从这种结构中删除数字以反映可能的数字。

Right now in my game I use List to represent a number per se. 现在,在我的游戏中,我使用列表来表示数字本身。 That way I can resemble any base and depending on events in game I can add a digit to such number. 这样,我可以类似于任何基础,并根据游戏中的事件,可以向该数字添加一个数字。 I know it isn't the best way to go about this but regarding game only the AI is where all the heavy work is being done. 我知道这不是解决问题的最佳方法,但是就游戏而言,只有AI才能完成所有繁重的工作。

I created a way to have an ArrayList> but the problem is when the limit becomes bigger than Integer.MAX_VALUE I run into a lot of problems with causing the program to freeze and such and also leads to huge memory issues. 我创建了一个拥有ArrayList>的方法,但是问题是当限制变得大于Integer.MAX_VALUE时,我遇到了很多导致程序冻结的问题,并导致大量内存问题。 I pulled some code showing how I am currently generating all sequences. 我提取了一些代码,显示了我当前如何生成所有序列。 I also just implemented shitty job of multithreading so you guys don't have to wait long when running the code: 我也只是实现了多线程的卑鄙工作,所以你们在运行代码时不必等待很长时间:

public class Recursive {

    private static List<List<Integer>> allSeqL = new ArrayList<List<Integer>>();
    private static final Object addPossibleSequenceLock = new Object();
    public static void main(String[] args){

        //Create Digits
        List<Integer> digits = new ArrayList<Integer>();
        int index = 0;
        while(10 > index){
            digits.add(index);
            index++;
        }
        System.out.println(digits.size()+"SIZE OF DIGITS");

        //Get Amount of Threads to run at once
        int recommendedAmountWT = Runtime.getRuntime().availableProcessors()*3/4;

        //Create Working List
        List<Thread> workTL = new ArrayList<Thread>();
        for(Integer number : digits){
            Thread t = new Thread(new Runnable(){
                private int number;
                private List<Integer> digits;
                public void run(){
                    int sizeOfSequence = 10;
                    boolean dupAllowed = true;
                    Integer[] sequence = new Integer[sizeOfSequence];
                    sequence[0] = number;
                    if(dupAllowed){
                        Recursive.recursiveAllPossible(new ArrayList<Integer>(digits), sequence, 1, dupAllowed);
                    }   else{
                        digits.remove(new Integer(number));
                        Recursive.recursiveAllPossible(digits, sequence, 1, dupAllowed);
                    }
                }
                public Runnable init(int number, List<Integer> digits){
                    this.number = number;
                    this.digits = digits;
                    return this;
                }
            }.init(number, new ArrayList<Integer>(digits)));
            workTL.add(t);
        }


        System.out.println(workTL.size()+"SIZE WORKTL");

        //Run only Recommended amount of work threads at once
        List<Thread> tempTL = new ArrayList<Thread>();
        while(workTL.size() != 0){
            int startThread = 0;
            while(workTL.size() != 0 && recommendedAmountWT > startThread){
                Thread t1 = workTL.get(0);
                tempTL.add(t1);
                workTL.remove(t1);
                startThread++;
                t1.start();
            }
            System.out.println(startThread);
            System.out.println(tempTL.size());
            System.out.println("##########################");
            for(Thread t : tempTL){
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            tempTL.clear();
        }
        System.out.println("TOTAL ALLSEQL: "+Recursive.allSeqL.size());
    }


    private static void recursiveAllPossible(List<Integer> digits, Integer[] sequence, int index, boolean dupAllowed){
        for(Integer number : digits){
            sequence[index] = number;
            if(sequence.length-1 > index){
                List<Integer> newPositionL = new ArrayList<Integer>(digits);
                if(!dupAllowed){
                    newPositionL.remove(number);
                }
                Recursive.recursiveAllPossible(newPositionL, sequence, new Integer(index+1), dupAllowed);
            }   else{
                Recursive.addToL(Arrays.asList(sequence));
            }
        }
    }

    /**
     * Method : Add to all sequence List
     * @param sequence : Sequence being added
     * Reason this has a lock is because when creating this list there are multiple threads
     */
    public static void addToL(List<Integer> sequence){
        synchronized(Recursive.addPossibleSequenceLock){
            Recursive.allSeqL.add(sequence);
            System.out.println(sequence);
        }
    }
}

Basically this works by setting number in digits to index of sequence array, cycles until it can't set any more, then it adds it to the all sequence list. 基本上,这是通过将数字设置为序列数组的索引来工作的,循环直到不再设置为止,然后将其添加到所有序列列表中。 Then it loops back to the previous and sees if there is another digit to add. 然后,它循环回到上一个,并查看是否还有要添加的数字。 Adds and repeats. 添加并重复。

The AI really doesn't have to follow List format compared to the rest of the game. 与游戏的其余部分相比,AI确实不必遵循列表格式。 However, to compare numbers I would have to convert whatever to List or rewrite my Result class but I would rather not. 但是,要比较数字,我必须将任何内容转换为List或重写Result类,但我宁愿不这样做。

So any tips of what I should do to solve this problem would be appreciated. 因此,我应该采取的解决该问题的任何技巧将不胜感激。 My solutions I came up with is implement some sort of Tree. 我想出的解决方案是实现某种Tree。 To be honest though I don't know much about Trees and don't feel to confident regarding this. 老实说,尽管我对树木了解不多,对此也没有信心。 Another solution was to create a new ArrayList when it reaches the Integer.MAX_VALUE with new sequences but that just seems like I'll be sweeping the problem under the rug. 另一个解决方案是在到达带有新序列的Integer.MAX_VALUE时创建一个新的ArrayList,但这似乎让我想尽办法了。

Third solution was use LinkedList but still shits out so to speak (I have tried this one). 第三种解决方案是使用LinkedList,但是可以这么说(我已经尝试过了)。

Given the size of the problem, have you considered using Sparse Matrixes? 考虑到问题的严重性,您是否考虑过使用稀疏矩阵?

I think maybe you can represent a disjoint list of non-consecutive numbers as simply a list of ranges: 我认为也许您可以将不连续的数字的不相交列表表示为简单的范围列表:

my_ranges = [(0,10),(12,1500),(1502,25000000)]

and this way, when you need to remove a number you can (some pythonic pseudocode): 这样,当您需要删除数字时,您可以(一些pythonic伪代码):

insert():
for subrange in my_ranges:
   if 27 in my_ranges:
       # do nothing
   else:
       # build intermediate ranges with 27 included
return new_ranges

delete():
for subrange in my_ranges:
   if 27 in my_ranges:
       # split this range into two ranges, before and after 27
return new_ranges


exists():
for subrange in my_ranges:
   if 27 in my_ranges:
       return 1
return return 0

This way you can solve the "representing a lot of numbers, with some exceptions, without actually running out of memory. 这样,您可以解决“表示很多数字,但有一些例外,而实际上不会用完内存”。

alternatively, you can use sparse matrixes :). 或者,您可以使用稀疏矩阵:)。

I once made a collection class that might be of interest to your problem. 我曾经做过一个收集类,您的问题可能对此感兴趣。

It acts as Set<Long> , but it uses a very efficient internal representation with a good space/time tradeoff. 它充当Set<Long> ,但它使用了非常有效的内部表示形式,并具有良好的时空权衡。

The key idea is to store consecutive ranges, more preceisely, the numbers where the function "contains" changes value. 关键思想是存储连续范围,更准确地说,是存储函数“包含”值的数字。 In the worst case the size is proportional to number of elements, which happens when elements represent a checkerboard (1, 3, 5, 7, 9 etc.), but even in that case, it's still just N. Empty and full set have constant size 1. Range 10000-30000 has a size of 2 instead of 20000, etc. Otherwise, ranges are merged and splitted dynamically when adding/removing values. 在最坏的情况下,大小与元素数量成正比,这在元素代表棋盘格(1、3、5、7、9等)时发生,但即使在那种情况下,它仍然仅为N。恒定大小1。范围10000-30000的大小为2,而不是20000,依此类推。否则,在添加/删除值时,范围会动态合并和拆分。

The class supports standard set operations such as intesection, union etc. In my experience it has worked great, but I probably didn't have as much requirements as you do. 该类支持标准集合操作,例如整形,联合等。以我的经验,它很好用,但是我可能没有您所需要的那么多。 In practice, the number of "delta points" is still limited by java's Integer.MAX_VALUE , but it's reasonably straightforward to extend it to Long.MAX_VALUE or even BigInteger . 实际上,“增量点”的数量仍受Java的Integer.MAX_VALUE限制,但是将其扩展到Long.MAX_VALUE甚至BigInteger相当简单。

To address your problem, you should observe the patterns in your data. 为了解决您的问题,您应该观察数据中的模式。 Is the pattern random or not? 模式是否随机? Are the values localized? 值是否已本地化? Etc. Different usages call for different data structures and algorithms with different trade-offs. 等等。不同的用法要求具有不同权衡的不同数据结构和算法。 If you're just starting, take a look at HashSet , TreeSet or collections in Google Guava project to get you going, then look for the patterns in your data. 如果您只是开始,请看一下Google Guava项目中的HashSetTreeSet或collections,然后在数据中查找模式。 There are also some probabilistic structures such as Bloom filters that you might find useful. 您还可能会发现一些概率结构,例如布隆过滤器。 Ultimately, the patterns you observe in your actual data will give you the best answer. 最终,您在实际数据中观察到的模式将为您提供最佳答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM