Skip to content

Commit adfa322

Browse files
authored
Add base Decode game logic classes (#22)
- add Artifact interface with PurpleArtifact and GreenArtifact - add Motif for artifact collection patterns using AprilTag IDs 21-23 - add circular indexing for motif sequences - add Obelisk to detect correct motif from AprilTag detections - filter detections by alliance color and position - add AllianceColor enum for RED and BLUE - add extra motif methods - lint decode/ directory
1 parent 765bfcc commit adfa322

4 files changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package pioneer.decode
2+
3+
import org.firstinspires.ftc.vision.opencv.ColorRange
4+
import org.firstinspires.ftc.vision.opencv.PredominantColorProcessor
5+
6+
interface Artifact {
7+
val name: String
8+
val color: ColorRange
9+
val swatch: PredominantColorProcessor.Swatch
10+
}
11+
12+
class PurpleArtifact : Artifact {
13+
override val name: String = "Purple"
14+
override val color: ColorRange = ColorRange.ARTIFACT_PURPLE
15+
override val swatch: PredominantColorProcessor.Swatch = PredominantColorProcessor.Swatch.ARTIFACT_PURPLE
16+
}
17+
18+
class GreenArtifact : Artifact {
19+
override val name: String = "Green"
20+
override val color: ColorRange = ColorRange.ARTIFACT_GREEN
21+
override val swatch: PredominantColorProcessor.Swatch = PredominantColorProcessor.Swatch.ARTIFACT_GREEN
22+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package pioneer.decode
2+
3+
class Motif(
4+
val aprilTagId: Int,
5+
) {
6+
private val artifacts: List<Artifact>?
7+
private var currentIndex: Int = 0
8+
9+
init {
10+
artifacts =
11+
when (aprilTagId) {
12+
21 -> listOf(GreenArtifact(), PurpleArtifact(), PurpleArtifact())
13+
22 -> listOf(PurpleArtifact(), GreenArtifact(), PurpleArtifact())
14+
23 -> listOf(PurpleArtifact(), PurpleArtifact(), GreenArtifact())
15+
else -> null
16+
}
17+
}
18+
19+
// Returns the next artifact in the motif's sequence, cycling back to the start if needed
20+
fun getNextArtifact(): Artifact? {
21+
if (artifacts == null || artifacts.isEmpty()) return null
22+
23+
val artifact = artifacts[currentIndex]
24+
currentIndex = (currentIndex + 1) % artifacts.size
25+
return artifact
26+
}
27+
28+
// Returns the current artifact without advancing the index
29+
fun currentArtifact(): Artifact? {
30+
if (artifacts == null || artifacts.isEmpty()) return null
31+
return artifacts[currentIndex]
32+
}
33+
34+
// Returns the artifact at a specific position in the pattern (0-indexed)
35+
fun getArtifactAt(index: Int): Artifact? {
36+
if (artifacts == null || artifacts.isEmpty() || index < 0 || index >= artifacts.size) return null
37+
return artifacts[index]
38+
}
39+
40+
// Returns the current position in the pattern (0-indexed)
41+
fun getCurrentIndex(): Int = currentIndex
42+
43+
// Returns true if this is a valid motif with artifacts
44+
fun isValid(): Boolean = artifacts != null && artifacts.isNotEmpty()
45+
46+
// Returns the complete artifact sequence for this motif
47+
fun getPattern(): List<Artifact>? = artifacts?.toList()
48+
49+
fun reset() {
50+
currentIndex = 0
51+
}
52+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package pioneer.decode
2+
3+
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection
4+
import pioneer.general.AllianceColor
5+
6+
class Obelisk {
7+
companion object {
8+
private val validMotifTagIds = setOf(21, 22, 23)
9+
10+
fun isValidMotifTag(aprilTagId: Int): Boolean = aprilTagId in validMotifTagIds
11+
12+
/**
13+
* Filters the AprilTag detections to find the correct motif tag based on alliance color.
14+
* If Blue alliance, look for right most valid tag (largest x in ftcPose)
15+
* If Red alliance, look for left most valid tag (smallest x in ftcPose)
16+
* Will work on close or far starting positions
17+
*/
18+
fun detectMotif(
19+
detections: List<AprilTagDetection>,
20+
alliance: AllianceColor,
21+
): Motif? {
22+
val validTags = detections.filter { it.ftcPose != null && isValidMotifTag(it.id) }
23+
val motifTagId =
24+
when (alliance) {
25+
AllianceColor.BLUE -> validTags.maxByOrNull { it.ftcPose.x }?.id
26+
AllianceColor.RED -> validTags.minByOrNull { it.ftcPose.x }?.id
27+
}
28+
return motifTagId?.let { Motif(it) }
29+
}
30+
}
31+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package pioneer.general
2+
3+
enum class AllianceColor {
4+
RED,
5+
BLUE
6+
}

0 commit comments

Comments
 (0)