Skip to content

Commit b72fd67

Browse files
committed
wip: SatSolver
1 parent d217413 commit b72fd67

File tree

1 file changed

+107
-2
lines changed

1 file changed

+107
-2
lines changed

src/main/scala/ru/org/codingteam/icfpc_2025/SatSolver.scala

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,110 @@ import java.nio.file.{Files, Path}
77

88
object SatSolver:
99
def solve(problem: ProblemDefinition): Unit =
10-
println("Don't wanna play anymore.")
11-
return
10+
println(s"Solving problem ${problem.name}.")
11+
Ædificium.select(problem.name)
12+
println(s"${problem.name} has been selected.")
13+
14+
var knowledge = KnowledgeHolder(Vector.empty, Vector.empty)
15+
while true do
16+
println("Determining next step...")
17+
val step = nextStep(problem, knowledge)
18+
println(s"Next step is ${step.getClass.getSimpleName}")
19+
step match
20+
case Step.ExploreStep(plans) =>
21+
knowledge = explore(problem, knowledge, plans)
22+
case Step.GuessStep(solution) =>
23+
println("Trying to commit the solution.")
24+
val correct = Ædificium.guess(solution)
25+
if correct then
26+
println(s"The solution for problem ${problem.name} is correct.")
27+
return
28+
else
29+
println(s"The solution for problem ${problem.name} is not correct!")
30+
throw new Exception("Incorrect solution! Analyze results in \"path\".")
31+
case Step.StopGuessing() =>
32+
println("Don't wanna play anymore.")
33+
return
34+
35+
private def nextStep(problem: ProblemDefinition, knowledge: KnowledgeHolder): Step =
36+
var exploredConnections = Seq.empty[(Int, Int, Int)]
37+
38+
for j <- knowledge.visitedRoutes.indices do
39+
val plan = knowledge.visitedRoutes(j)
40+
val rooms = knowledge.visitedRooms(j)
41+
42+
for i <- plan.indices do
43+
val door = plan(i)
44+
val enter = rooms(i)
45+
val exit = rooms(i + 1)
46+
47+
exploredConnections = exploredConnections :+ (enter, exit, door)
48+
49+
println(s"explored conntection: ${exploredConnections}")
50+
51+
val folder = Files.createTempDirectory(s"icfpc.sat.${problem.name}")
52+
println(s"Temp directory: ${folder}")
53+
54+
val sb = new StringBuilder()
55+
val roomLabelVariablesCount = problem.size*4
56+
val roomLabelClausesCount = problem.size
57+
58+
val connectionVariablesCount = problem.size*problem.size*6 + problem.size*6
59+
val connectionClausesCount = problem.size*6 + problem.size*problem.size*6
60+
61+
val variablesCount = roomLabelVariablesCount + connectionVariablesCount
62+
val clausesCount = roomLabelClausesCount + connectionClausesCount
63+
sb ++= s"p cnf ${variablesCount} 9999\n"
64+
65+
// rooms has one of {0, 1, 2, 3} labels
66+
for i <- 0 to problem.size - 1 do
67+
for l <- 0 to 3 do
68+
sb ++= s"${roomLabelVariableIndex(i, l)} "
69+
sb ++= "0\n"
70+
71+
// for door d should exist at least one connection
72+
for i <- 0 to problem.size - 1 do
73+
for d <- 0 to 5 do
74+
for j <- 0 to problem.size - 1 do
75+
sb ++= s"${roomLabelVariablesCount + connectionVariableIndex(problem.size, i, j, d)} "
76+
sb ++= "0\n"
77+
78+
// but no more than one
79+
for i <- 0 to problem.size - 1 do
80+
for d <- 0 to 5 do
81+
for k <- 0 to problem.size - 1 do
82+
for l <- 0 to problem.size - 1 do
83+
if k < l then
84+
sb ++= s"-${roomLabelVariablesCount + connectionVariableIndex(problem.size, i, k, d)} "
85+
sb ++= s"-${roomLabelVariablesCount + connectionVariableIndex(problem.size, i, l, d)} "
86+
sb ++= "0\n"
87+
88+
// no isolated rooms
89+
for i <- 0 to problem.size - 1 do
90+
for d <- 0 to 5 do
91+
sb ++= s"-${roomLabelVariablesCount + connectionVariableIndex(problem.size, i, i, d)} "
92+
sb ++= "0\n"
93+
94+
// there is should be at least one back connection OR forward connection should not exist
95+
for i <- 0 to problem.size - 1 do
96+
for j <- 0 to problem.size - 1 do
97+
for d <- 0 to 5 do
98+
sb ++= s"-${roomLabelVariablesCount + connectionVariableIndex(problem.size, i, j, d)} "
99+
for k <- 0 to 5 do
100+
sb ++= s"${roomLabelVariablesCount + connectionVariableIndex(problem.size, j, i, k)} "
101+
sb ++= "0\n"
102+
103+
104+
Files.writeString(folder.resolve("step1.dimacs"), sb.toString)
105+
throw new Exception("Incorrect solution! Analyze results in \"path\".")
106+
107+
if knowledge.visitedRoutes.size > 0 then
108+
return Step.StopGuessing()
109+
else
110+
val plan = Seq(Lanternarius.lanternarius(problem.maxRouteLength))
111+
return Step.ExploreStep(plan)
112+
113+
private def roomLabelVariableIndex(room: Int, label: Int): Int = room*4 + label + 1
114+
115+
private def connectionVariableIndex(roomsCount: Int, enterRoom: Int, exitRoom: Int, door: Int) =
116+
enterRoom*roomsCount*6 + exitRoom*6 + door + 1

0 commit comments

Comments
 (0)