parent
954a9118cd
commit
a03ed4c2d6
@ -0,0 +1,4 @@
|
|||||||
|
build
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
input
|
@ -1,100 +0,0 @@
|
|||||||
56583
|
|
||||||
83363
|
|
||||||
127502
|
|
||||||
138143
|
|
||||||
113987
|
|
||||||
147407
|
|
||||||
111181
|
|
||||||
92655
|
|
||||||
79802
|
|
||||||
64636
|
|
||||||
108805
|
|
||||||
148885
|
|
||||||
51022
|
|
||||||
120002
|
|
||||||
52283
|
|
||||||
53573
|
|
||||||
142374
|
|
||||||
143523
|
|
||||||
121158
|
|
||||||
63332
|
|
||||||
63203
|
|
||||||
142400
|
|
||||||
105515
|
|
||||||
140150
|
|
||||||
89910
|
|
||||||
93081
|
|
||||||
129752
|
|
||||||
86731
|
|
||||||
128755
|
|
||||||
134756
|
|
||||||
131066
|
|
||||||
77990
|
|
||||||
77081
|
|
||||||
85779
|
|
||||||
137271
|
|
||||||
72889
|
|
||||||
117608
|
|
||||||
132442
|
|
||||||
115294
|
|
||||||
59414
|
|
||||||
75495
|
|
||||||
79459
|
|
||||||
107669
|
|
||||||
81496
|
|
||||||
144432
|
|
||||||
69138
|
|
||||||
53410
|
|
||||||
71199
|
|
||||||
141799
|
|
||||||
63964
|
|
||||||
110945
|
|
||||||
102174
|
|
||||||
87697
|
|
||||||
88838
|
|
||||||
93552
|
|
||||||
145531
|
|
||||||
54602
|
|
||||||
65080
|
|
||||||
66865
|
|
||||||
139693
|
|
||||||
98048
|
|
||||||
60409
|
|
||||||
88384
|
|
||||||
138807
|
|
||||||
130854
|
|
||||||
75997
|
|
||||||
130900
|
|
||||||
125974
|
|
||||||
129123
|
|
||||||
93480
|
|
||||||
86042
|
|
||||||
128187
|
|
||||||
74981
|
|
||||||
88144
|
|
||||||
96629
|
|
||||||
148836
|
|
||||||
124473
|
|
||||||
57616
|
|
||||||
93477
|
|
||||||
104174
|
|
||||||
97407
|
|
||||||
123017
|
|
||||||
85408
|
|
||||||
64862
|
|
||||||
85298
|
|
||||||
88142
|
|
||||||
62182
|
|
||||||
128983
|
|
||||||
62981
|
|
||||||
124580
|
|
||||||
56339
|
|
||||||
94335
|
|
||||||
125521
|
|
||||||
121373
|
|
||||||
78777
|
|
||||||
125132
|
|
||||||
94411
|
|
||||||
57789
|
|
||||||
97384
|
|
||||||
79900
|
|
@ -1,100 +0,0 @@
|
|||||||
56583
|
|
||||||
83363
|
|
||||||
127502
|
|
||||||
138143
|
|
||||||
113987
|
|
||||||
147407
|
|
||||||
111181
|
|
||||||
92655
|
|
||||||
79802
|
|
||||||
64636
|
|
||||||
108805
|
|
||||||
148885
|
|
||||||
51022
|
|
||||||
120002
|
|
||||||
52283
|
|
||||||
53573
|
|
||||||
142374
|
|
||||||
143523
|
|
||||||
121158
|
|
||||||
63332
|
|
||||||
63203
|
|
||||||
142400
|
|
||||||
105515
|
|
||||||
140150
|
|
||||||
89910
|
|
||||||
93081
|
|
||||||
129752
|
|
||||||
86731
|
|
||||||
128755
|
|
||||||
134756
|
|
||||||
131066
|
|
||||||
77990
|
|
||||||
77081
|
|
||||||
85779
|
|
||||||
137271
|
|
||||||
72889
|
|
||||||
117608
|
|
||||||
132442
|
|
||||||
115294
|
|
||||||
59414
|
|
||||||
75495
|
|
||||||
79459
|
|
||||||
107669
|
|
||||||
81496
|
|
||||||
144432
|
|
||||||
69138
|
|
||||||
53410
|
|
||||||
71199
|
|
||||||
141799
|
|
||||||
63964
|
|
||||||
110945
|
|
||||||
102174
|
|
||||||
87697
|
|
||||||
88838
|
|
||||||
93552
|
|
||||||
145531
|
|
||||||
54602
|
|
||||||
65080
|
|
||||||
66865
|
|
||||||
139693
|
|
||||||
98048
|
|
||||||
60409
|
|
||||||
88384
|
|
||||||
138807
|
|
||||||
130854
|
|
||||||
75997
|
|
||||||
130900
|
|
||||||
125974
|
|
||||||
129123
|
|
||||||
93480
|
|
||||||
86042
|
|
||||||
128187
|
|
||||||
74981
|
|
||||||
88144
|
|
||||||
96629
|
|
||||||
148836
|
|
||||||
124473
|
|
||||||
57616
|
|
||||||
93477
|
|
||||||
104174
|
|
||||||
97407
|
|
||||||
123017
|
|
||||||
85408
|
|
||||||
64862
|
|
||||||
85298
|
|
||||||
88142
|
|
||||||
62182
|
|
||||||
128983
|
|
||||||
62981
|
|
||||||
124580
|
|
||||||
56339
|
|
||||||
94335
|
|
||||||
125521
|
|
||||||
121373
|
|
||||||
78777
|
|
||||||
125132
|
|
||||||
94411
|
|
||||||
57789
|
|
||||||
97384
|
|
||||||
79900
|
|
@ -1 +0,0 @@
|
|||||||
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,10,19,1,6,19,23,1,13,23,27,1,6,27,31,1,31,10,35,1,35,6,39,1,39,13,43,2,10,43,47,1,47,6,51,2,6,51,55,1,5,55,59,2,13,59,63,2,63,9,67,1,5,67,71,2,13,71,75,1,75,5,79,1,10,79,83,2,6,83,87,2,13,87,91,1,9,91,95,1,9,95,99,2,99,9,103,1,5,103,107,2,9,107,111,1,5,111,115,1,115,2,119,1,9,119,0,99,2,0,14,0
|
|
@ -0,0 +1,28 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.3.61'
|
||||||
|
}
|
||||||
|
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
kotlin {
|
||||||
|
srcDirs 'src'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
|
}
|
||||||
|
|
||||||
|
compileKotlin {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
compileTestKotlin {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
Binary file not shown.
@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
@ -0,0 +1,84 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
@ -0,0 +1,2 @@
|
|||||||
|
rootProject.name = 'day-3'
|
||||||
|
|
@ -0,0 +1,185 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val coll = loadLines(File("./input").readText())
|
||||||
|
|
||||||
|
val intersections = coll.intersections();
|
||||||
|
// Get shorted manhattan path
|
||||||
|
println("Shortest manhattan distance: ")
|
||||||
|
println(intersections.map { abs(it.x) + abs(it.y) }.sorted().first())
|
||||||
|
println("Shortest wire distance: ")
|
||||||
|
println(intersections.map { it.segmentA.getDistance(it) + it.segmentB.getDistance(it) }.sorted().first())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Really dirty line reader that makes a LineCollection from input
|
||||||
|
*/
|
||||||
|
fun loadLines(input: String): LineCollection {
|
||||||
|
return LineCollection(
|
||||||
|
input
|
||||||
|
.trim()
|
||||||
|
// Split lines
|
||||||
|
.lines()
|
||||||
|
.map {
|
||||||
|
// This records the current point in the line
|
||||||
|
var current = Point(0, 0)
|
||||||
|
Line(
|
||||||
|
it
|
||||||
|
.trim()
|
||||||
|
// Segments are split with ,
|
||||||
|
.split(',')
|
||||||
|
.map {
|
||||||
|
// First character is the direction
|
||||||
|
var d = it[0];
|
||||||
|
// Rest is distance/length
|
||||||
|
var distance = it.substring(1).toInt()
|
||||||
|
|
||||||
|
// Down and Left are basically Up and Right but inverted.
|
||||||
|
if (d == 'D' || d == 'L') {
|
||||||
|
d = if (d == 'D') 'U' else 'R'
|
||||||
|
distance = -distance
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d == 'U') {
|
||||||
|
// if direction is up, line is over the Y axis
|
||||||
|
Segment(Axis.Y, current.y, current.y + distance, current.x).also {
|
||||||
|
// Set the new current point
|
||||||
|
current = Point(current.x, current.y + distance);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If direction is anything else it's Right, so it runs over the X axis
|
||||||
|
Segment(Axis.X, current.x, current.x + distance, current.y).also {
|
||||||
|
// Set the new current point
|
||||||
|
current = Point(current.x + distance, current.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class indicating a point (x, y) coordinates
|
||||||
|
data class Point(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
// Class that holds all lines known
|
||||||
|
data class LineCollection(val lines: List<Line>) {
|
||||||
|
fun intersections(): List<Intersection> {
|
||||||
|
val items = mutableListOf<Intersection>()
|
||||||
|
for (i in 0 until lines.count() - 1) {
|
||||||
|
for (j in (i + 1) until lines.count()) {
|
||||||
|
items.addAll(lines[i].intersections(lines[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class that holds a segment and it's corresponding line
|
||||||
|
data class LineSegment(val line: Line, val segment: Segment) {
|
||||||
|
// Get distance to point in line.
|
||||||
|
// It is assumed that the point is part of the [segment]
|
||||||
|
fun getDistance(it: Point): Int {
|
||||||
|
// Since point intersects, use the point coordinate instead of [Segment.end]
|
||||||
|
val lastEnd = if (segment.axis == Axis.X) it.y else it.x
|
||||||
|
// Distance traveled
|
||||||
|
var cost = 0
|
||||||
|
for (sgm in line.segments) {
|
||||||
|
// If we found the same segment as we're holding we can stop
|
||||||
|
if (sgm === segment) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add length of segment to cost
|
||||||
|
cost += sgm.high - sgm.low
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get length to point from last segment start
|
||||||
|
return cost + (max(lastEnd, segment.start) - min(lastEnd, segment.start))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDistance(it: Intersection) = getDistance(Point(it.x, it.y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Holds an intersection, it's point and the 2 LineSegments intersecting
|
||||||
|
data class Intersection(val x: Int, val y: Int, val segmentA: LineSegment, val segmentB: LineSegment)
|
||||||
|
|
||||||
|
// Line is a collection of Segments
|
||||||
|
data class Line(val segments: List<Segment>) {
|
||||||
|
// Find all intersections between this and given line
|
||||||
|
fun intersections(rhs: Line): List<Intersection> {
|
||||||
|
// flatMap will allow use to return an array
|
||||||
|
// and will concat all returned arrays
|
||||||
|
return segments.flatMap { seg ->
|
||||||
|
// map but it ignores all null returns
|
||||||
|
rhs.segments.mapNotNull { otherSeg ->
|
||||||
|
// Find intersection ( ?. indicates only access .let if result is not null )
|
||||||
|
otherSeg.intersection(seg)?.let {
|
||||||
|
// Create intersection object
|
||||||
|
Intersection(it.x, it.y, LineSegment(this, seg), LineSegment(rhs, otherSeg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick helper function to make a range between 2 ints
|
||||||
|
infix fun Int.between(rhs: Int) = (this + 1) until rhs
|
||||||
|
|
||||||
|
// Enum with known Axis'es
|
||||||
|
enum class Axis {
|
||||||
|
X,
|
||||||
|
Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for a segment in a line, a segment is basically a single direction stroke
|
||||||
|
//
|
||||||
|
// if [axis] is X, [start] and [end] are on the X axis, and [other] is on the Y axis
|
||||||
|
// if [axis] is Y, [start] and [end] are on the Y axis, and [other] is on the X axis
|
||||||
|
data class Segment(val axis: Axis, val start: Int, val end: Int, val other: Int) {
|
||||||
|
// Get the lowest value from start or end
|
||||||
|
// helpful for intersection calculation
|
||||||
|
val low by lazy { min(start, end) }
|
||||||
|
|
||||||
|
// Get the highest value from start or end
|
||||||
|
// helpful for intersection calculation
|
||||||
|
val high by lazy { max(start, end) }
|
||||||
|
|
||||||
|
// Find intersection between 2 segments
|
||||||
|
fun intersection(rhs: Segment): Point? {
|
||||||
|
// If 2 lines are on a different axis,
|
||||||
|
// the calculations are different from them being on the same axis
|
||||||
|
return if (axis != rhs.axis) {
|
||||||
|
// If on different axis, check if [other] is between each others [low] and [high]
|
||||||
|
if (rhs.other in low between high && other in rhs.low between rhs.high) {
|
||||||
|
if (rhs.axis == Axis.Y) {
|
||||||
|
Point(other, rhs.other)
|
||||||
|
} else {
|
||||||
|
Point(rhs.other, other)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If lines are on the same axis, [which is an edge case that never happens :)]
|
||||||
|
// [other] should be the same for both to intersect
|
||||||
|
if (other != rhs.other) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
// only intersect if our [high] is higher than their [low] and vice versa
|
||||||
|
if (low < rhs.high && rhs.low < high) {
|
||||||
|
val first = min(rhs.high, high)
|
||||||
|
Point(if (axis == Axis.Y) other else first, if (axis == Axis.Y) first else other)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue