|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import { arrayLast, arrayRemoveOnce } from '../Common/ArrayExt';
|
|
|
|
|
import { arrayLast, arrayPushArray, arrayRemoveOnce } from '../Common/ArrayExt';
|
|
|
|
|
import { NestFiler } from "../Common/Filer";
|
|
|
|
|
import { RandomIndex } from "../Common/Random";
|
|
|
|
|
import { Container } from "./Container";
|
|
|
|
@ -21,7 +21,13 @@ import { PlaceType } from "./PlaceType";
|
|
|
|
|
*/
|
|
|
|
|
export class Individual
|
|
|
|
|
{
|
|
|
|
|
constructor(public Parts?: Part[], public mutationRate = 0.5, private bin?: Path, private OddmentsBins: Path[] = [], private ComparePointKeys: string[] = DefaultComparePointKeys) { }
|
|
|
|
|
constructor(public Parts?: Part[],
|
|
|
|
|
public PreParts?: Part[],
|
|
|
|
|
public mutationRate = 0.5,
|
|
|
|
|
private bin?: Path,
|
|
|
|
|
private OddmentsBins: Path[] = [],
|
|
|
|
|
private ComparePointKeys: string[] = DefaultComparePointKeys)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
Fitness: number; //(评估健康) 大板个数-1 + 最后一块板的利用率
|
|
|
|
|
Containers: Container[]; //大板列表(已排
|
|
|
|
@ -41,8 +47,16 @@ export class Individual
|
|
|
|
|
this.OddmentsContainers = this.OddmentsBins.map(path => new Container(path, type ?? RandomIndex(3), this.ComparePointKeys[RandomIndex(2)]));
|
|
|
|
|
this.InitHoleContainers();
|
|
|
|
|
|
|
|
|
|
let parts = this.PreParts.concat(this.Parts);
|
|
|
|
|
//网洞优先
|
|
|
|
|
let parts = this.Parts.filter(p => !this.HoleContainers.some(hole => hole.PutPart(p)));
|
|
|
|
|
parts = this.Parts.filter(p => !this.HoleContainers.some(hole =>
|
|
|
|
|
{
|
|
|
|
|
//如果零件是提前放置的,但是网洞却不是,就先不给他放了(这可能会损失利用率 但是达到了提前放置的需求)
|
|
|
|
|
if (p.IsPrePlace && !hole.IsPrePlace)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
hole.PutPart(p);
|
|
|
|
|
}));
|
|
|
|
|
//之后是余料
|
|
|
|
|
parts = parts.filter(p => !this.OddmentsContainers.some(odd => odd.PutPart(p)));
|
|
|
|
|
|
|
|
|
@ -106,7 +120,7 @@ export class Individual
|
|
|
|
|
|
|
|
|
|
this.Containers = [];
|
|
|
|
|
this.HoleContainers = [];
|
|
|
|
|
let parts = this.Parts.concat();
|
|
|
|
|
let parts = this.PreParts.concat(this.Parts);
|
|
|
|
|
while (parts.length > 0)
|
|
|
|
|
{
|
|
|
|
|
if (this.Containers.length > Math.max(0, bestCount))//提前结束,已经超过最佳用板量
|
|
|
|
@ -223,6 +237,9 @@ export class Individual
|
|
|
|
|
container.ParentId = part.Id;
|
|
|
|
|
container.ChildrenIndex = i;
|
|
|
|
|
container.ParentM = GNestConfig.RotateHole ? hole.MinPoint : hole.OrigionMinPoint;
|
|
|
|
|
|
|
|
|
|
container.IsPrePlace = part.IsPrePlace;
|
|
|
|
|
|
|
|
|
|
this.HoleContainers.push(container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -230,7 +247,7 @@ export class Individual
|
|
|
|
|
|
|
|
|
|
Clone()
|
|
|
|
|
{
|
|
|
|
|
let p = new Individual(this.Parts.map(p => p.Clone()), this.mutationRate, this.bin, this.OddmentsBins, this.ComparePointKeys);
|
|
|
|
|
let p = new Individual(this.Parts.map(p => p.Clone()), this.PreParts.map(p => p.Clone()), this.mutationRate, this.bin, this.OddmentsBins, this.ComparePointKeys);
|
|
|
|
|
p.Mutate();
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
@ -242,20 +259,28 @@ export class Individual
|
|
|
|
|
* 在变异率较低的情况下,会只调换一次牌,并进行状态突变
|
|
|
|
|
*/
|
|
|
|
|
Mutate()
|
|
|
|
|
{
|
|
|
|
|
this.MutateParts(this.Parts);
|
|
|
|
|
if (this.PreParts.length)
|
|
|
|
|
this.MutateParts(this.PreParts);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MutateParts(parts: Part[])
|
|
|
|
|
{
|
|
|
|
|
if (this.mutationRate > 0.5)
|
|
|
|
|
for (let i = 0; i < this.Parts.length; i++)
|
|
|
|
|
for (let i = 0; i < parts.length; i++)
|
|
|
|
|
{
|
|
|
|
|
let rand = Math.random();
|
|
|
|
|
if (rand < this.mutationRate * 0.5)
|
|
|
|
|
{
|
|
|
|
|
//和下一个调换顺序
|
|
|
|
|
let j = i + 1;
|
|
|
|
|
if (j < this.Parts.length)
|
|
|
|
|
[this.Parts[i], this.Parts[j]] = [this.Parts[j], this.Parts[i]];
|
|
|
|
|
if (j < parts.length)
|
|
|
|
|
[parts[i], parts[j]] = [parts[j], parts[i]];
|
|
|
|
|
}
|
|
|
|
|
if (rand < this.mutationRate)
|
|
|
|
|
this.Parts[i].Mutate();
|
|
|
|
|
parts[i].Mutate();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -263,19 +288,18 @@ export class Individual
|
|
|
|
|
let rand = Math.random();
|
|
|
|
|
if (rand < 0.5)
|
|
|
|
|
{
|
|
|
|
|
let index = RandomIndex(this.Parts.length - 2);
|
|
|
|
|
let count = Math.ceil(RandomIndex(this.Parts.length - 2 - index) * this.mutationRate * 2) || 1;
|
|
|
|
|
let parts = this.Parts.splice(index, count);
|
|
|
|
|
this.Parts.push(...parts);
|
|
|
|
|
this.Parts[index].Mutate();
|
|
|
|
|
let index = RandomIndex(parts.length - 2);
|
|
|
|
|
let count = Math.ceil(RandomIndex(parts.length - 2 - index) * this.mutationRate * 2) || 1;
|
|
|
|
|
arrayPushArray(parts, parts.splice(index, count));
|
|
|
|
|
parts[index].Mutate();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
for (let i = 0; i < this.Parts.length; i++)
|
|
|
|
|
for (let i = 0; i < parts.length; i++)
|
|
|
|
|
{
|
|
|
|
|
let rand = Math.random();
|
|
|
|
|
if (rand < this.mutationRate)
|
|
|
|
|
{
|
|
|
|
|
this.Parts[i].Mutate();
|
|
|
|
|
parts[i].Mutate();
|
|
|
|
|
i += 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -299,6 +323,14 @@ export class Individual
|
|
|
|
|
[this.Parts[i], this.Parts[j]] = [this.Parts[j], this.Parts[i]];
|
|
|
|
|
this.Parts[i].Mutate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.PreParts.length)
|
|
|
|
|
for (let i = this.PreParts.length - 1; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
|
[this.PreParts[i], this.PreParts[j]] = [this.PreParts[j], this.PreParts[i]];
|
|
|
|
|
this.PreParts[i].Mutate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#region -------------------------File-------------------------
|
|
|
|
|