背景:创建一个类似于Mastermind但类固醇的游戏。目前正在尝试优化AI并增加我的极限。让我解释一下:
对于我的AI算法,我需要生成某种数据结构,它可以表示给定0的所有可能数字 - 一个限制。我还需要从这种结构中删除数字以反映可能的数字。
现在在我的游戏中我使用List代表一个数字本身。这样我可以像任何基地一样,根据游戏中的事件,我可以为这样的数字添加一个数字。我知道这不是解决这个问题的最佳方式,但对于游戏而言,人工智能是完成所有繁重工作的地方。
我创建了一种方法来获得ArrayList>但问题是当限制变得大于Integer.MAX_VALUE时,我遇到很多问题导致程序冻结等等,并且还会导致巨大的内存问题。 我提取了一些代码,显示我当前是如何生成所有序列的。我也刚刚实现了多线程的糟糕工作,所以你们不必在运行代码时等待很长时间:
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);
}
}
}
基本上这可以通过将数字的数字设置为序列数组的索引,循环直到它不能再设置,然后将它添加到所有序列列表。然后它循环回到前一个并查看是否有另一个要添加的数字。添加和重复。
与其他游戏相比,AI真的不必遵循List格式。但是,为了比较数字,我必须将任何内容转换为List或重写我的Result类,但我宁愿不这样做。
所以我应该感谢你应该做些什么来解决这个问题。 我想出的解决方案是实现某种树。说实话,虽然我对树木了解不多,但对此并不自信。 另一种解决方案是在使用新序列到达Integer.MAX_VALUE时创建一个新的ArrayList,但这看起来好像我将在地毯下扫描问题。
第三个解决方案是使用LinkedList,但仍然可以说(我试过这个)。
答案 0 :(得分:1)
考虑到问题的大小,您是否考虑过使用稀疏矩阵?
我想也许你可以代表一个不相连的非连续数字列表 只是一个范围列表:
my_ranges = [(0,10),(12,1500),(1502,25000000)]
这样,当你需要删除一个数字时你可以(某些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
通过这种方式,您可以解决代表大量数字的问题,但有一些例外情况,而不会实际耗尽内存。
或者,您可以使用稀疏矩阵:)。
答案 1 :(得分:1)
我曾经做过一个可能对你的问题感兴趣的收藏课。
它充当Set<Long>
,但它使用非常有效的内部表示,具有良好的空间/时间权衡。
关键的想法是存储连续的范围,更准确地说是存储功能&#34;包含的数字&#34;改变价值。在最坏的情况下,大小与元素的数量成比例,当元素代表棋盘(1,3,5,7,9等)时会发生,但即使在这种情况下,它仍然只是N.空并且全集具有恒定大小1.范围10000-30000的大小为2而不是20000等。否则,在添加/删除值时,会动态合并和分割范围。
该类支持标准集操作,例如intesection,union等。根据我的经验,它工作得很好,但我可能没有你那么多的要求。在实践中,&#34; delta点的数量&#34;仍然受到java Integer.MAX_VALUE
的限制,但将其扩展到Long.MAX_VALUE
甚至BigInteger
是相当简单的。
要解决您的问题,您应该观察数据中的模式。模式是否随机?这些值是否已本地化?等等。不同的用法需要不同的数据结构和算法,具有不同的权衡。如果您刚刚开始,请查看Google Guava项目中的HashSet
,TreeSet
或馆藏以帮助您前进,然后查找数据中的模式。还有一些概率结构,例如您可能觉得有用的Bloom过滤器。最终,您在实际数据中观察到的模式将为您提供最佳答案。