handy 1 місяць тому
батько
коміт
7a90e88d92
1 змінених файлів з 185 додано та 188 видалено
  1. 185 188
      src/components/warehouse-layout-enhancers.ts

+ 185 - 188
src/components/warehouse-layout-enhancers.ts

@@ -45,15 +45,6 @@ interface GlobalColumnAisleRule {
   excludeRowRange?: RowRange
 }
 
-interface WarehouseLayoutRuleSet {
-  rowAisleBreakpoints: readonly number[]
-  globalColumnAisles: readonly GlobalColumnAisleRule[]
-  localColumnAisles: readonly LocalColumnAisleRule[]
-  localColumnShifts: readonly LocalColumnShiftRule[]
-  verticalWallBreaks?: readonly VerticalWallBreakRule[]
-  elevatorAreas?: readonly ElevatorAreaRule[]
-}
-
 interface VerticalWallBreakRule {
   column: number
   betweenRows: readonly [number, number]
@@ -67,130 +58,153 @@ interface ElevatorAreaRule {
   label: string
 }
 
-interface WarehouseLayoutEnhancer {
-  supports: (level: number) => boolean
-  apply: (
-    currentPosition: WarehouseLayoutPosition,
-    parsedLocation: WarehouseLayoutParsedLocation
-  ) => WarehouseLayoutPosition
+interface WarehouseLayoutRuleSet {
+  rowAisleBreakpoints: readonly number[]
+  globalColumnAisles: readonly GlobalColumnAisleRule[]
+  localColumnAisles: readonly LocalColumnAisleRule[]
+  localColumnShifts: readonly LocalColumnShiftRule[]
+  verticalWallBreaks: readonly VerticalWallBreakRule[]
+  elevatorAreas: readonly ElevatorAreaRule[]
 }
 
+const scopedRows = <T extends object>(rows: readonly number[], rule: T): T & Pick<RowScopedRule, 'rows'> => ({
+  ...rule,
+  rows
+})
+
+const scopedRowRange = <T extends object>(
+  start: number,
+  end: number,
+  rule: T
+): T & Pick<RowScopedRule, 'rowRange'> => ({
+  ...rule,
+  rowRange: [start, end]
+})
+
+const globalColumnAisle = (
+  breakpoint: number,
+  options: Omit<GlobalColumnAisleRule, 'breakpoint'> = {}
+): GlobalColumnAisleRule => ({
+  breakpoint,
+  ...options
+})
+
+const verticalWallBreak = (
+  column: number,
+  upperRow: number,
+  lowerRow: number
+): VerticalWallBreakRule => ({
+  column,
+  betweenRows: [upperRow, lowerRow]
+})
+
+const elevatorArea = (
+  leftColumn: number,
+  rightColumn: number,
+  upperRow: number,
+  lowerRow: number,
+  label: string
+): ElevatorAreaRule => ({
+  leftColumn,
+  rightColumn,
+  upperRow,
+  lowerRow,
+  label
+})
+
+const FIRST_FLOOR_ROW_AISLE_BREAKPOINTS = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] as const
+
+const FIRST_FLOOR_GLOBAL_COLUMN_AISLES = [
+  globalColumnAisle(1),
+  globalColumnAisle(19, {
+    excludeRows: [8, 9, 10, 11]
+  }),
+  globalColumnAisle(26, {
+    excludeRows: [8, 11]
+  })
+] as const
+
+const FIRST_FLOOR_LOCAL_COLUMN_AISLES = [
+  scopedRowRange(0, 7, {
+    afterColumn: 7,
+    gapCols: 1
+  }),
+  scopedRowRange(12, 22, {
+    afterColumn: 7,
+    gapCols: 1
+  }),
+  scopedRows([9, 10], {
+    afterColumn: 6,
+    gapCols: 3
+  }),
+  scopedRows([9, 10], {
+    afterColumn: 10,
+    gapCols: 1
+  }),
+  scopedRows([8, 11], {
+    afterColumn: 13,
+    gapCols: 1
+  }),
+  scopedRows([9, 10], {
+    afterColumn: 20,
+    gapCols: 1
+  }),
+  scopedRows([8, 11], {
+    afterColumn: 26,
+    gapCols: 1
+  }),
+  scopedRows([9, 10], {
+    afterColumn: 14,
+    gapCols: 3
+  })
+] as const
+
+const FIRST_FLOOR_LOCAL_COLUMN_SHIFTS = [
+  scopedRows([6, 13], {
+    startColumn: 0,
+    shiftCols: 1
+  }),
+  scopedRows([6, 13], {
+    startColumn: 5,
+    shiftCols: 1
+  }),
+  scopedRows([6, 13], {
+    startColumn: 11,
+    shiftCols: 1
+  }),
+  scopedRows([6, 13], {
+    startColumn: 17,
+    shiftCols: 1
+  }),
+  scopedRows([7], {
+    startColumn: 20,
+    shiftCols: 1
+  })
+] as const
+
+const FIRST_FLOOR_VERTICAL_WALL_BREAKS = [
+  verticalWallBreak(0, 19, 20),
+  verticalWallBreak(6, 19, 20),
+  verticalWallBreak(13, 19, 20),
+  verticalWallBreak(20, 19, 20)
+] as const
+
+const FIRST_FLOOR_ELEVATOR_AREAS = [
+  elevatorArea(7, 9, 8, 11, '提升机'),
+  elevatorArea(18, 20, 8, 11, '提升机')
+] as const
+
 const FIRST_FLOOR_RULE_SET: WarehouseLayoutRuleSet = {
-  rowAisleBreakpoints: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22],
-  globalColumnAisles: [
-    { breakpoint: 1 },
-    {
-      breakpoint: 19,
-      excludeRows: [8, 9, 10, 11]
-    },
-    {
-      breakpoint: 26,
-      excludeRows: [8, 11]
-    }
-  ],
-  localColumnAisles: [
-    {
-      rowRange: [0, 7],
-      afterColumn: 7,
-      gapCols: 1
-    },
-    {
-      rowRange: [12, 22],
-      afterColumn: 7,
-      gapCols: 1
-    },
-    {
-      rows: [9, 10],
-      afterColumn: 6,
-      gapCols: 3
-    },
-    {
-      rows: [9, 10],
-      afterColumn: 10,
-      gapCols: 1
-    },
-    {
-      rows: [8, 11],
-      afterColumn: 13,
-      gapCols: 1
-    },
-    {
-      rows: [9, 10],
-      afterColumn: 20,
-      gapCols: 1
-    },
-    {
-      rows: [8, 11],
-      afterColumn: 26,
-      gapCols: 1
-    },
-    {
-      rows: [9, 10],
-      afterColumn: 14,
-      gapCols: 3
-    }
-  ],
-  localColumnShifts: [
-    {
-      rows: [6, 13],
-      startColumn: 0,
-      shiftCols: 1
-    },
-    {
-      rows: [6, 13],
-      startColumn: 5,
-      shiftCols: 1
-    },
-    {
-      rows: [6, 13],
-      startColumn: 11,
-      shiftCols: 1
-    },
-    {
-      rows: [6, 13],
-      startColumn: 17,
-      shiftCols: 1
-    },
-    {
-      rows: [7],
-      startColumn: 20,
-      shiftCols: 1
-    }
-  ],
-  verticalWallBreaks: [
-    {
-      column: 0,
-      betweenRows: [19, 20]
-    },
-    {
-      column: 6,
-      betweenRows: [19, 20]
-    },
-    {
-      column: 13,
-      betweenRows: [19, 20]
-    },
-    {
-      column: 20,
-      betweenRows: [19, 20]
-    }
-  ],
-  elevatorAreas: [
-    {
-      leftColumn: 7,
-      rightColumn: 9,
-      upperRow: 8,
-      lowerRow: 11,
-      label: '提升机'
-    },
-    {
-      leftColumn: 18,
-      rightColumn: 20,
-      upperRow: 8,
-      lowerRow: 11,
-      label: '提升机'
-    }
-  ]
+  rowAisleBreakpoints: FIRST_FLOOR_ROW_AISLE_BREAKPOINTS,
+  globalColumnAisles: FIRST_FLOOR_GLOBAL_COLUMN_AISLES,
+  localColumnAisles: FIRST_FLOOR_LOCAL_COLUMN_AISLES,
+  localColumnShifts: FIRST_FLOOR_LOCAL_COLUMN_SHIFTS,
+  verticalWallBreaks: FIRST_FLOOR_VERTICAL_WALL_BREAKS,
+  elevatorAreas: FIRST_FLOOR_ELEVATOR_AREAS
+}
+
+const RULE_SETS_BY_LEVEL: Readonly<Record<number, WarehouseLayoutRuleSet>> = {
+  1: FIRST_FLOOR_RULE_SET
 }
 
 const matchesRowScope = (row: number, rule: RowScopedRule) => {
@@ -250,7 +264,7 @@ const sumLocalColumnShiftOffsets = (
     return total
   }, 0)
 
-const applyConfiguredRuleSet = (
+const applyRuleSet = (
   currentPosition: WarehouseLayoutPosition,
   parsedLocation: WarehouseLayoutParsedLocation,
   ruleSet: WarehouseLayoutRuleSet
@@ -273,82 +287,47 @@ const applyConfiguredRuleSet = (
   }
 }
 
-const createConfiguredEnhancer = (
-  level: number,
-  ruleSet: WarehouseLayoutRuleSet
-): WarehouseLayoutEnhancer => ({
-  supports: (currentLevel) => currentLevel === level,
-  apply: (currentPosition, parsedLocation) =>
-    applyConfiguredRuleSet(currentPosition, parsedLocation, ruleSet)
-})
-
-const CONFIGURED_RULE_SETS: Record<number, WarehouseLayoutRuleSet> = {
-  1: FIRST_FLOOR_RULE_SET
+const getRuleSet = (level: number) => {
+  return RULE_SETS_BY_LEVEL[level]
 }
 
-const LAYOUT_ENHANCERS: WarehouseLayoutEnhancer[] = Object.entries(CONFIGURED_RULE_SETS).map(
-  ([level, ruleSet]) => createConfiguredEnhancer(Number(level), ruleSet)
-)
-
-export const applyWarehouseLayoutEnhancement = (
+const createSyntheticLocation = (
   level: number,
-  parsedLocation: WarehouseLayoutParsedLocation,
-  basePosition: WarehouseLayoutPosition
-) => {
-  return LAYOUT_ENHANCERS
-    .filter((enhancer) => enhancer.supports(level))
-    .reduce(
-      (currentPosition, enhancer) => enhancer.apply(currentPosition, parsedLocation),
-      basePosition
-    )
-}
-
-export const getWarehouseLayoutWallCells = (level: number): WarehouseLayoutWallCell[] => {
-  return getWarehouseLayoutSpecialCells(level)
-    .filter((cell): cell is WarehouseLayoutSpecialCell & { type: 'wall' } => cell.type === 'wall')
-    .map((cell) => ({
-      gridRow: cell.gridRow,
-      gridCol: cell.gridCol
-    }))
-}
+  column: number,
+  row: number
+): WarehouseLayoutParsedLocation => ({
+  floor: level,
+  x: column,
+  y: row,
+  depth: 1
+})
 
 const getEnhancedBasePosition = (
   level: number,
   ruleSet: WarehouseLayoutRuleSet,
   column: number,
   row: number
-) => {
-  return applyConfiguredRuleSet(
+) =>
+  applyRuleSet(
     {
       gridRow: row,
       gridCol: column
     },
-    {
-      floor: level,
-      x: column,
-      y: row,
-      depth: 1
-    },
+    createSyntheticLocation(level, column, row),
     ruleSet
   )
-}
 
 const buildWallCells = (
   level: number,
   ruleSet: WarehouseLayoutRuleSet
 ): WarehouseLayoutSpecialCell[] => {
-  if (!ruleSet?.verticalWallBreaks?.length) {
-    return []
-  }
-
   return ruleSet.verticalWallBreaks.map((rule) => {
-    const upperRow = rule.betweenRows[0]
-    const upperCellPosition = getEnhancedBasePosition(level, ruleSet, rule.column, upperRow)
+    const upperRowPosition = getEnhancedBasePosition(level, ruleSet, rule.column, rule.betweenRows[0])
 
     return {
       type: 'wall',
-      gridRow: upperCellPosition.gridRow + 1,
-      gridCol: upperCellPosition.gridCol,
+      gridRow: upperRowPosition.gridRow + 1,
+      gridCol: upperRowPosition.gridCol,
       label: '墙'
     }
   })
@@ -358,10 +337,6 @@ const buildElevatorAreaCells = (
   level: number,
   ruleSet: WarehouseLayoutRuleSet
 ): WarehouseLayoutSpecialCell[] => {
-  if (!ruleSet.elevatorAreas?.length) {
-    return []
-  }
-
   return ruleSet.elevatorAreas.flatMap((rule) => {
     const upperLeft = getEnhancedBasePosition(level, ruleSet, rule.leftColumn, rule.upperRow)
     const upperRight = getEnhancedBasePosition(level, ruleSet, rule.rightColumn, rule.upperRow)
@@ -389,11 +364,33 @@ const buildElevatorAreaCells = (
   })
 }
 
+export const applyWarehouseLayoutEnhancement = (
+  level: number,
+  parsedLocation: WarehouseLayoutParsedLocation,
+  basePosition: WarehouseLayoutPosition
+) => {
+  const ruleSet = getRuleSet(level)
+  if (!ruleSet) {
+    return basePosition
+  }
+
+  return applyRuleSet(basePosition, parsedLocation, ruleSet)
+}
+
 export const getWarehouseLayoutSpecialCells = (level: number): WarehouseLayoutSpecialCell[] => {
-  const ruleSet = CONFIGURED_RULE_SETS[level]
+  const ruleSet = getRuleSet(level)
   if (!ruleSet) {
     return []
   }
 
   return [...buildWallCells(level, ruleSet), ...buildElevatorAreaCells(level, ruleSet)]
 }
+
+export const getWarehouseLayoutWallCells = (level: number): WarehouseLayoutWallCell[] => {
+  return getWarehouseLayoutSpecialCells(level)
+    .filter((cell): cell is WarehouseLayoutSpecialCell & { type: 'wall' } => cell.type === 'wall')
+    .map((cell) => ({
+      gridRow: cell.gridRow,
+      gridCol: cell.gridCol
+    }))
+}