diff --git a/examples/EightQueue.php b/examples/EightQueue.php new file mode 100644 index 00000000..22872c26 --- /dev/null +++ b/examples/EightQueue.php @@ -0,0 +1,123 @@ +n = $n; + $this->cols = array_fill(0, $n, -1); + } + + /** + * 检查在 (row, col) 位置放置皇后是否安全 + */ + private function isSafe($row, $col) + { + for ($i = 0; $i < $row; $i++) { + // 检查列冲突和对角线冲突 + if ($this->cols[$i] == $col || + abs($this->cols[$i] - $col) == abs($i - $row)) { + return false; + } + } + return true; + } + + /** + * 回溯求解 + */ + private function solve($row) + { + if ($row == $this->n) { + $this->solutions[] = array_slice($this->cols, 0); + return; + } + + for ($col = 0; $col < $this->n; $col++) { + if ($this->isSafe($row, $col)) { + $this->cols[$row] = $col; + $this->solve($row + 1); + $this->cols[$row] = -1; + } + } + } + + /** + * 获取所有解决方案 + */ + public function getSolutions() + { + $this->solutions = []; + $this->solve(0); + return $this->solutions; + } + + /** + * 打印解决方案 + */ + public function printSolution($solution) + { + echo str_repeat('-', $this->n * 4 + 1) . "\n"; + for ($row = 0; $row < $this->n; $row++) { + echo '| '; + for ($col = 0; $col < $this->n; $col++) { + echo ($solution[$row] == $col ? 'Q' : '.') . ' | '; + } + echo "\n" . str_repeat('-', $this->n * 4 + 1) . "\n"; + } + } + + /** + * 打印所有解决方案 + */ + public function printAllSolutions() + { + $solutions = $this->getSolutions(); + echo "找到 " . count($solutions) . " 个解决方案\n\n"; + + foreach ($solutions as $index => $solution) { + echo "解决方案 #" . ($index + 1) . ": [" . + implode(', ', $solution) . "]\n"; + $this->printSolution($solution); + echo "\n"; + } + } + + /** + * 只统计解的数量(不保存所有解) + */ + public function countSolutions() + { + return count($this->getSolutions()); + } +} + +function main() +{ + // 使用示例 + echo "=== 8 皇后问题 ===\n\n"; + $queens = new EightQueensOptimized(8); + + // 只显示前3个解决方案 + $solutions = $queens->getSolutions(); + echo "总共找到 " . count($solutions) . " 个解决方案\n\n"; + + for ($i = 0; $i < min(3, count($solutions)); $i++) { + echo "解决方案 #" . ($i + 1) . ":\n"; + $queens->printSolution($solutions[$i]); + echo "\n"; + } + +// 测试不同规模 + echo "\n=== 不同规模的皇后问题 ===\n"; + for ($n = 4; $n <= 10; $n++) { + $q = new EightQueensOptimized($n); + $count = $q->countSolutions(); + echo "{$n} 皇后问题有 {$count} 个解\n"; + } +} diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index a74741b9..e0b22f73 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -429,6 +429,7 @@ class CompilerBase extends \PhpAot\Core\Translator $class = $v->getType(); $this->beforeStmtLines = []; $this->afterStmtLines = []; + $result = ''; $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class); $lines[] = $this->getComment($v, $class); @@ -483,7 +484,6 @@ class CompilerBase extends \PhpAot\Core\Translator $result = $this->parseContinue($v); break; case 'Stmt_Nop': - $result = ''; break; case 'Stmt_Global': $result = $this->parseGlobal($v); @@ -505,9 +505,13 @@ class CompilerBase extends \PhpAot\Core\Translator } $lines = array_merge($lines, $this->beforeStmtLines); $this->beforeStmtLines = []; - $lines[] = $result; - $lines = array_merge($lines, $this->afterStmtLines); - $this->afterStmtLines = []; + if ($result) { + $lines[] = $result; + } + if ($this->afterStmtLines) { + $lines = array_merge($lines, $this->afterStmtLines); + $this->afterStmtLines = []; + } } $code = ''; @@ -694,6 +698,20 @@ class CompilerBase extends \PhpAot\Core\Translator } } + private function parseAssignPropertyArrayDim(Node $left, Node $right): string + { + $obj = $this->parseIdentifier($left->var->var); + $propName = $this->identifierToStr($left->var->name); + $code = ''; + $value = $this->trimBrackets($this->parseExpr($right)); + if ($left->dim === null) { + return $code . "$obj.appendArrayProperty($propName, $value)"; + } else { + $dim = $this->trimBrackets($this->parseIdentifier($left->dim)); + return $code . "$obj.updateArrayProperty($propName, $dim, $value)"; + } + } + protected function parseAssign(Node $v): string { $left = $v->var; @@ -707,6 +725,11 @@ class CompilerBase extends \PhpAot\Core\Translator $this->addLocalVar($array, self::TYPE_ARRAY); } + // 这是属性赋值操作 + if ($this->isPropertyFetch($left->var)) { + return $this->parseAssignPropertyArrayDim($left, $right); + } + $value = $this->trimBrackets($this->parseExpr($right)); if ($left->dim === null) { return $code . "$array.offsetSet(php::null, $value)"; @@ -1291,6 +1314,13 @@ class CompilerBase extends \PhpAot\Core\Translator exit(255); } + protected function dump(NodeAbstract $v): void + { + if ($this->debugLine == $v->getStartLine()) { + var_dump($v); + } + } + protected function parseArrayDimFetch($node): string { $var = $this->parseIdentifier($node->var); diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index ae554aab..970d8139 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -103,6 +103,7 @@ class Preprocessor extends CompilerBase $this->prepareNamespaceDef($v); break; case 'Stmt_Class': + case 'Stmt_Trait': $this->prepareClass($v); break; case 'Stmt_Function': @@ -146,7 +147,7 @@ class Preprocessor extends CompilerBase } - protected function prepareClass(Node\Stmt\Class_ $class): string + protected function prepareClass(Node\Stmt\Class_|Node\Stmt\Trait_ $class): string { $this->class = $this->parseIdentifier($class->name); $code = ''; @@ -156,6 +157,7 @@ class Preprocessor extends CompilerBase case 'Stmt_ClassConst': case 'Stmt_Property': case 'Stmt_Nop': + case 'Stmt_TraitUse': break; case 'Stmt_ClassMethod': $code .= $this->prepareFunction($v) . PHP_EOL; diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 49a7b877..c9ddf173 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -218,6 +218,7 @@ class Translator extends Preprocessor $cppCode .= $this->parseNamespace($v); break; case 'Stmt_Class': + case 'Stmt_Trait': $cppCode .= $this->parseClass($v); break; case 'Stmt_Use': @@ -494,7 +495,7 @@ class Translator extends Preprocessor return $code; } - protected function genClassStubFile(Node\Stmt\Class_ $class, string $file): void + protected function genClassStubFile(Node\Stmt\Class_|Node\Stmt\Trait_ $class, string $file): void { $genStubCmd = PHP_BINARY. ' ' . $this->rootPath . '/bin/gen_stub.php --gen-class-info -f ' . $file; $output = shell_exec($genStubCmd); @@ -509,7 +510,7 @@ class Translator extends Preprocessor $this->stubFileIncluded = true; } - protected function parseClass(Node\Stmt\Class_ $class): string + protected function parseClass(Node\Stmt\Class_|Node\Stmt\Trait_ $class): string { $this->class = $this->parseIdentifier($class->name); if (!$this->stubFileIncluded) {