Gather data
This commit is contained in:
1301
.editorconfig
Normal file
1301
.editorconfig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
"#############",
|
|
||||||
"#############",
|
|
||||||
"####B#PALLET#",
|
|
||||||
"####E#O######",
|
|
||||||
"##D#S#L#T####",
|
|
||||||
"##E#T#I#A####",
|
|
||||||
"##LAAGTANK###",
|
|
||||||
"##F#N#I#K####",
|
|
||||||
"##T#D#E#E####",
|
|
||||||
"########N####",
|
|
||||||
"#############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "LAAGTANK",
|
|
||||||
"clue": "Hoofdonderdeel in beslag genomen",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "LAAGTANK",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "POLITIE",
|
|
||||||
"clue": "Verantwoordelijk bij de inval",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "POLITIE",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BESTAND",
|
|
||||||
"clue": "Samengestelde hoeveelheid",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "BESTAND",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "PALLET",
|
|
||||||
"clue": "Transportmiddel voor de lachgastank",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "PALLET",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TANKEN",
|
|
||||||
"clue": "Vervoort voor de lachgastank",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "TANKEN",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DELFT",
|
|
||||||
"clue": "Stad waar het gebeurde",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DELFT",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 2
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
"###########",
|
|
||||||
"###########",
|
|
||||||
"##EUROPA#N#",
|
|
||||||
"######A##A#",
|
|
||||||
"####VERZET#",
|
|
||||||
"######K##U#",
|
|
||||||
"######I##U#",
|
|
||||||
"###KLANK#R#",
|
|
||||||
"######F##B#",
|
|
||||||
"###########"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "KLANK",
|
|
||||||
"clue": "Stemmen voor een betere toekomst",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "KLANK",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "PARKIN",
|
|
||||||
"clue": "Dergelijke aandoening beïnvloedt beweging",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "PARKIN",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "VERZET",
|
|
||||||
"clue": "Collectief optreden tegen beleid",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "VERZET",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NATUUR",
|
|
||||||
"clue": "Leefgebied voor planten en dieren",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NATUUR",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EUROPA",
|
|
||||||
"clue": "Het politieke blok waarin Nederland deel uitmaakt",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EUROPA",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "PARKINF",
|
|
||||||
"clue": "Afkorting Parkinson",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "PARKINF",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NATUURB",
|
|
||||||
"clue": "Bescherming van natuurgebieden",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NATUURB",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#######L######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#######E##B###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###A#SNUIVEN##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###K###S##S###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###K######T###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##VERSLAAVEND#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###R######D#R#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###H######I#O#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###O#SLOGAN#O#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###F######G#G#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "VERSLAAVEND",
|
|
||||||
"clue": "Overdrijft aantrekkingskracht",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "VERSLAAVEND",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BESTEDING",
|
|
||||||
"clue": "Korting of prijs",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "BESTEDING",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AKKERHOF",
|
|
||||||
"clue": "Naam van de winkel",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "AKKERHOF",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SNUIVEN",
|
|
||||||
"clue": "Korte handeling bij verslaving",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "SNUIVEN",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SLOGAN",
|
|
||||||
"clue": "Marketing tekst",
|
|
||||||
"startRow": 10,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "SLOGAN",
|
|
||||||
"arrowRow": 10,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DROOG",
|
|
||||||
"clue": "Tegenstrijdig fruittype",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 12,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DROOG",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 12
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "LEUS",
|
|
||||||
"clue": "Kortere slogan tekst",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "LEUS",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 7
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"########C#####"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"########E#####"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##DIVUSEN#####"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"########S#####"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"######EQUALIA#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####G###R##J##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###BLOKIER#Z##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####O#O####E##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####O#R####N##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####M#T####K##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####I#E####O##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####T#X#######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "BLOKIER",
|
|
||||||
"clue": "Persoon die accounts blokt.",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "BLOKIER",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "CENSURE",
|
|
||||||
"clue": "Controle over queer‑accounts.",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "CENSURE",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DIVUSEN",
|
|
||||||
"clue": "Verdeel en heers accountblok.",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "DIVUSEN",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EQUALIA",
|
|
||||||
"clue": "Gelijk op abortus.",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EQUALIA",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "GLOOMIT",
|
|
||||||
"clue": "Verstopt sociale media.",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "GLOOMIT",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "IJZENKO",
|
|
||||||
"clue": "Krachtige blokking.",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 11,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "IJZENKO",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "KORTEX",
|
|
||||||
"clue": "Kort maar krachtig.",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "KORTEX",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 6
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
"#############",
|
|
||||||
"#############",
|
|
||||||
"##I#O####D###",
|
|
||||||
"##N#N####O#S#",
|
|
||||||
"##S#D####C#C#",
|
|
||||||
"##T#E#M##U#H#",
|
|
||||||
"##A#R#E##M#A#",
|
|
||||||
"##GEZONDHEID#",
|
|
||||||
"##R#O#T##N#E#",
|
|
||||||
"##A#E#A##T###",
|
|
||||||
"##M#K#A#META#",
|
|
||||||
"######L##N###",
|
|
||||||
"#############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "GEZONDHEID",
|
|
||||||
"clue": "Welzijn",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "GEZONDHEID",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DOCUMENTEN",
|
|
||||||
"clue": "Papieren",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DOCUMENTEN",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "INSTAGRAM",
|
|
||||||
"clue": "Platform",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "INSTAGRAM",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ONDERZOEK",
|
|
||||||
"clue": "Studie",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "ONDERZOEK",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "MENTAAL",
|
|
||||||
"clue": "Geestelijk",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "MENTAAL",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SCHADE",
|
|
||||||
"clue": "Negatief effect",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 11,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "SCHADE",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "META",
|
|
||||||
"clue": "Stopte onderzoek",
|
|
||||||
"startRow": 10,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "META",
|
|
||||||
"arrowRow": 10,
|
|
||||||
"arrowCol": 7
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"########N#####"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"######M#I#R###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###N##E#E#U###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###E##N#U#G#S#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###D##S#W#G#M#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##KEIZERSNEDE#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###R##N#U#N#R#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###L##W#U#P#I#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###A##E#R#R#G#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###N##R###I#E#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"###D##K###K###"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##############"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "KEIZERSNEDE",
|
|
||||||
"clue": "operatie",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "KEIZERSNEDE",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "MENSENWERK",
|
|
||||||
"clue": "arbeid",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "MENSENWERK",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "RUGGENPRIK",
|
|
||||||
"clue": "anesthesie",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "RUGGENPRIK",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NIEUWSUUR",
|
|
||||||
"clue": "media",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NIEUWSUUR",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NEDERLAND",
|
|
||||||
"clue": "land",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NEDERLAND",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SMERIGE",
|
|
||||||
"clue": "complex",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 12,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "SMERIGE",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 12
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
[
|
|
||||||
"#############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#############"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#####F#D##G##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#####B#E##O##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#####I#LEAVE#"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#####W#E##T##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"####BONGI#S##"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"######A######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"##DOWNT######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"######U######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"######R######"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"#############"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "BONGI",
|
|
||||||
"clue": "Ex-podcaster Dan Bongino",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "BONGI",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DELEG",
|
|
||||||
"clue": "Stepped down als FBI‑deputiendirector",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DELEG",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "FBIWO",
|
|
||||||
"clue": "Gaat uit de FBI na een grote stap",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "FBIWO",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "LEAVE",
|
|
||||||
"clue": "Bongino kondigt vertrek aan",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "LEAVE",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NATUR",
|
|
||||||
"clue": "Natuurlijk een carrièreswitch",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NATUR",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DOWNT",
|
|
||||||
"clue": "Terug op televisie en in het bestuur",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "DOWNT",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "GOVTS",
|
|
||||||
"clue": "Nieuwe rol in de Amerikaanse overheid",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "GOVTS",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
{
|
|
||||||
"gridv2": [
|
|
||||||
"############",
|
|
||||||
"############",
|
|
||||||
"#########Q##",
|
|
||||||
"#########U##",
|
|
||||||
"#########E##",
|
|
||||||
"##P##VRAGEN#",
|
|
||||||
"##L##E###R##",
|
|
||||||
"##ABORTUS###",
|
|
||||||
"##A##S######",
|
|
||||||
"##T##L######",
|
|
||||||
"##J##AFMELD#",
|
|
||||||
"##E##G######",
|
|
||||||
"############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "ABORTUS",
|
|
||||||
"clue": "Medische term voor zwangerschap beëindigen",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "ABORTUS",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "VERSLAG",
|
|
||||||
"clue": "Schriftelijke of mondelinge informatie over iets",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "VERSLAG",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "PLAATJE",
|
|
||||||
"clue": "Korte afbeelding die gedeeld wordt",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "PLAATJE",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AFMELD",
|
|
||||||
"clue": "Account weggeven uit het platform",
|
|
||||||
"startRow": 10,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "AFMELD",
|
|
||||||
"arrowRow": 10,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "VRAGEN",
|
|
||||||
"clue": "Inzichten of informatie zoeken",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "VRAGEN",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "QUEER",
|
|
||||||
"clue": "Overkoepelende term voor LGBTQ+ gemeenschap",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "QUEER",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
{
|
|
||||||
"date": "2025-12-19",
|
|
||||||
"theme": "technologie",
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
},
|
|
||||||
"gridv2": [
|
|
||||||
"############",
|
|
||||||
"############",
|
|
||||||
"###KRANSVAT#",
|
|
||||||
"###EIKENMOS#",
|
|
||||||
"###TANKE####",
|
|
||||||
"###STICK#DV#",
|
|
||||||
"###TIRANNEN#",
|
|
||||||
"##EINANO#E##",
|
|
||||||
"##RUUMSTOR##",
|
|
||||||
"########BN##",
|
|
||||||
"############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "KRANSVAT",
|
|
||||||
"clue": "KRANSVAT",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "KRANSVAT",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EIKENMOS",
|
|
||||||
"clue": "EIKENMOS",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EIKENMOS",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TANKE",
|
|
||||||
"clue": "TANKE",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "TANKE",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "VM",
|
|
||||||
"clue": "VM",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "VM",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DEERN",
|
|
||||||
"clue": "DEERN",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DEERN",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TS",
|
|
||||||
"clue": "TS",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "TS",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "STICK",
|
|
||||||
"clue": "STICK",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "STICK",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DV",
|
|
||||||
"clue": "DV",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "DV",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TIRANNEN",
|
|
||||||
"clue": "TIRANNEN",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "TIRANNEN",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EINANO",
|
|
||||||
"clue": "EINANO",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EINANO",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "VN",
|
|
||||||
"clue": "VN",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "VN",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "RUUMSTOR",
|
|
||||||
"clue": "RUUMSTOR",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "RUUMSTOR",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ER",
|
|
||||||
"clue": "ER",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "ER",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "KETSTIU",
|
|
||||||
"clue": "KETSTIU",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "KETSTIU",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "RIATINU",
|
|
||||||
"clue": "RIATINU",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "RIATINU",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AKNIRAM",
|
|
||||||
"clue": "AKNIRAM",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "AKNIRAM",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NEKCANS",
|
|
||||||
"clue": "NEKCANS",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NEKCANS",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SNEKNOT",
|
|
||||||
"clue": "SNEKNOT",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "SNEKNOT",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BN",
|
|
||||||
"clue": "BN",
|
|
||||||
"startRow": 9,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "BN",
|
|
||||||
"arrowRow": 9,
|
|
||||||
"arrowCol": 7
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
{
|
|
||||||
"date": "2025-12-19",
|
|
||||||
"theme": "algemeen",
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
},
|
|
||||||
"gridv2": [
|
|
||||||
"############",
|
|
||||||
"############",
|
|
||||||
"###OBAMA####",
|
|
||||||
"###YEE#ISBN#",
|
|
||||||
"#####L#TOER#",
|
|
||||||
"##EDGINIER##",
|
|
||||||
"##N##LETNI##",
|
|
||||||
"##NEDAREIS##",
|
|
||||||
"##EGIGOLOH##",
|
|
||||||
"###AP###NA##",
|
|
||||||
"############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "OBAMA",
|
|
||||||
"clue": "OBAMA",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "OBAMA",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SOENION",
|
|
||||||
"clue": "SOENION",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "SOENION",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BERISHA",
|
|
||||||
"clue": "BERISHA",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "BERISHA",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NR",
|
|
||||||
"clue": "NR",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NR",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "YEE",
|
|
||||||
"clue": "YEE",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "YEE",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ISBN",
|
|
||||||
"clue": "ISBN",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "ISBN",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ENNE",
|
|
||||||
"clue": "ENNE",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "ENNE",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "OY",
|
|
||||||
"clue": "OY",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "OY",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BE",
|
|
||||||
"clue": "BE",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "BE",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TOER",
|
|
||||||
"clue": "TOER",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "TOER",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EDGINIER",
|
|
||||||
"clue": "EDGINIER",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EDGINIER",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EGA",
|
|
||||||
"clue": "EGA",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "EGA",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DIP",
|
|
||||||
"clue": "DIP",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 4,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DIP",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "LETNI",
|
|
||||||
"clue": "LETNI",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "LETNI",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NEDAREIS",
|
|
||||||
"clue": "NEDAREIS",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "NEDAREIS",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "EGIGOLOH",
|
|
||||||
"clue": "EGIGOLOH",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "EGIGOLOH",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AP",
|
|
||||||
"clue": "AP",
|
|
||||||
"startRow": 9,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "AP",
|
|
||||||
"arrowRow": 9,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AELILAG",
|
|
||||||
"clue": "AELILAG",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "AELILAG",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NERO",
|
|
||||||
"clue": "NERO",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NERO",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AITITEL",
|
|
||||||
"clue": "AITITEL",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "AITITEL",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NA",
|
|
||||||
"clue": "NA",
|
|
||||||
"startRow": 9,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "NA",
|
|
||||||
"arrowRow": 9,
|
|
||||||
"arrowCol": 7
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
{
|
|
||||||
"date": "2025-12-21",
|
|
||||||
"theme": "algemeen",
|
|
||||||
"difficulty": 1,
|
|
||||||
"rewards": {
|
|
||||||
"coins": 50,
|
|
||||||
"stars": 2,
|
|
||||||
"hints": 1
|
|
||||||
},
|
|
||||||
"gridv2": [
|
|
||||||
"############",
|
|
||||||
"############",
|
|
||||||
"##IE####SD##",
|
|
||||||
"##TRAAKTEN##",
|
|
||||||
"#####ADEREN#",
|
|
||||||
"#####REGALE#",
|
|
||||||
"##BK#D#ERIN#",
|
|
||||||
"##AR#V#NEEN#",
|
|
||||||
"###UIL#OLGA#",
|
|
||||||
"###GROEP####",
|
|
||||||
"############"
|
|
||||||
],
|
|
||||||
"words": [
|
|
||||||
{
|
|
||||||
"word": "IE",
|
|
||||||
"clue": "IE",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "IE",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AARDVLO",
|
|
||||||
"clue": "AARDVLO",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "AARDVLO",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "KDE",
|
|
||||||
"clue": "KDE",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 6,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "KDE",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TEGENOP",
|
|
||||||
"clue": "TEGENOP",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "TEGENOP",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SD",
|
|
||||||
"clue": "SD",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "SD",
|
|
||||||
"arrowRow": 2,
|
|
||||||
"arrowCol": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "TRAAKTEN",
|
|
||||||
"clue": "TRAAKTEN",
|
|
||||||
"startRow": 3,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "TRAAKTEN",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "IT",
|
|
||||||
"clue": "IT",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "IT",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ER",
|
|
||||||
"clue": "ER",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "ER",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ADEREN",
|
|
||||||
"clue": "ADEREN",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "ADEREN",
|
|
||||||
"arrowRow": 4,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BA",
|
|
||||||
"clue": "BA",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "BA",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "KRUG",
|
|
||||||
"clue": "KRUG",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "KRUG",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "REGALE",
|
|
||||||
"clue": "REGALE",
|
|
||||||
"startRow": 5,
|
|
||||||
"startCol": 5,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "REGALE",
|
|
||||||
"arrowRow": 5,
|
|
||||||
"arrowCol": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "BK",
|
|
||||||
"clue": "BK",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "BK",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "ERIN",
|
|
||||||
"clue": "ERIN",
|
|
||||||
"startRow": 6,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "ERIN",
|
|
||||||
"arrowRow": 6,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "AR",
|
|
||||||
"clue": "AR",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 2,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "AR",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NEEN",
|
|
||||||
"clue": "NEEN",
|
|
||||||
"startRow": 7,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "NEEN",
|
|
||||||
"arrowRow": 7,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "UIL",
|
|
||||||
"clue": "UIL",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "UIL",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "OLGA",
|
|
||||||
"clue": "OLGA",
|
|
||||||
"startRow": 8,
|
|
||||||
"startCol": 7,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "OLGA",
|
|
||||||
"arrowRow": 8,
|
|
||||||
"arrowCol": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "GROEP",
|
|
||||||
"clue": "GROEP",
|
|
||||||
"startRow": 9,
|
|
||||||
"startCol": 3,
|
|
||||||
"direction": "horizontal",
|
|
||||||
"answer": "GROEP",
|
|
||||||
"arrowRow": 9,
|
|
||||||
"arrowCol": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "SERAREL",
|
|
||||||
"clue": "SERAREL",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 8,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "SERAREL",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "DNELIEG",
|
|
||||||
"clue": "DNELIEG",
|
|
||||||
"startRow": 2,
|
|
||||||
"startCol": 9,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "DNELIEG",
|
|
||||||
"arrowRow": 1,
|
|
||||||
"arrowCol": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": "NENNA",
|
|
||||||
"clue": "NENNA",
|
|
||||||
"startRow": 4,
|
|
||||||
"startCol": 10,
|
|
||||||
"direction": "vertical",
|
|
||||||
"answer": "NENNA",
|
|
||||||
"arrowRow": 3,
|
|
||||||
"arrowCol": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"date": "2025-12-18",
|
|
||||||
"files": [
|
|
||||||
"crossword_2025-12-18_01_duizenden-lachgascilinders-in-beslag-genomen-in-de.json",
|
|
||||||
"crossword_2025-12-18_01_levenslang-voor-40-jarige-duitser-die-in-mannheim-.json",
|
|
||||||
"crossword_2025-12-18_01_parkinsonpati-nten-nederland-moet-zich-in-eu-verze.json",
|
|
||||||
"crossword_2025-12-18_01_slechtste-slogan-van-het-jaar-over-verslavende-dru.json",
|
|
||||||
"crossword_2025-12-18_02_levenslang-voor-40-jarige-duitser-die-in-mannheim-.json",
|
|
||||||
"crossword_2025-12-18_02_meta-blokkeert-tientallen-queer-en-abortus-account.json",
|
|
||||||
"crossword_2025-12-18_02_meta-stopte-onderzoek-dat-schade-van-apps-op-menta.json",
|
|
||||||
"crossword_2025-12-18_03_30-11-in-nieuwsuur-pijn-bij-keizersnede-netanyahu-.json",
|
|
||||||
"crossword_2025-12-18_03_clair-obscur-expedition-33-recordwinnaar-game-awar.json",
|
|
||||||
"crossword_2025-12-18_03_dan-bongino-stepping-down-as-fbi-deputy-director.json",
|
|
||||||
"crossword_2025-12-18_03_meta-blokkeert-tientallen-queer-en-abortus-account.json"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@ public class ClueGenerator {
|
|||||||
|
|
||||||
private static final String OLLAMA_URL = "http://localhost:11434/api/chat";
|
private static final String OLLAMA_URL = "http://localhost:11434/api/chat";
|
||||||
private static final String MODEL = "qwen2.5:14b";
|
private static final String MODEL = "qwen2.5:14b";
|
||||||
private static final String HINTS_FILE = "export_with_hints.csv";
|
private static final String HINTS_FILE = "/data/puzzle/export_with_hints.csv";
|
||||||
private static Map<String, String> prebuiltClues = null;
|
private static Map<String, String> prebuiltClues = null;
|
||||||
|
|
||||||
private static synchronized void ensurePrebuiltCluesLoaded() {
|
private static synchronized void ensurePrebuiltCluesLoaded() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package puzzle;
|
package puzzle;
|
||||||
|
|
||||||
import puzzle.DutchWordScorer.WordScore;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ public class DailyGenerator {
|
|||||||
return "true".equalsIgnoreCase(val) || "1".equals(val);
|
return "true".equalsIgnoreCase(val) || "1".equals(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
static void main(String[] args) {
|
||||||
var outDir = env("OUT_DIR", "/home/mike/dev/puzzle-generator/data/");
|
var outDir = env("OUT_DIR", "/home/mike/dev/puzzle-generator/data/");
|
||||||
var wordsPath = env("WORDS_PATH", "./export_words_only.txt");
|
var wordsPath = env("WORDS_PATH", "/data/puzzle/export_with_hints.csv");
|
||||||
var puzzlesPerDay = envInt("PUZZLES_PER_DAY", 3);
|
var puzzlesPerDay = envInt("PUZZLES_PER_DAY", 3);
|
||||||
var seed = envInt("SEED", (int) System.currentTimeMillis());
|
var seed = envInt("SEED", (int) System.currentTimeMillis());
|
||||||
var themeFilter = envBool("THEME_FILTER", true);
|
var themeFilter = envBool("THEME_FILTER", true);
|
||||||
@@ -49,7 +49,7 @@ public class DailyGenerator {
|
|||||||
|
|
||||||
// Load word list
|
// Load word list
|
||||||
SwedishGenerator.Dict dict;
|
SwedishGenerator.Dict dict;
|
||||||
var llmScores = SwedishGenerator.loadScores();
|
var llmScores = SwedishGenerator.loadScores();
|
||||||
try {
|
try {
|
||||||
dict = SwedishGenerator.loadWords(wordsPath, llmScores);
|
dict = SwedishGenerator.loadWords(wordsPath, llmScores);
|
||||||
System.out.println("Loaded " + dict.words.size() + " words");
|
System.out.println("Loaded " + dict.words.size() + " words");
|
||||||
@@ -82,7 +82,6 @@ public class DailyGenerator {
|
|||||||
// Filter word list by theme
|
// Filter word list by theme
|
||||||
List<String> filteredWords = dict.words;
|
List<String> filteredWords = dict.words;
|
||||||
if (themeFilter && !theme.equals("algemeen")) {
|
if (themeFilter && !theme.equals("algemeen")) {
|
||||||
filteredWords = ThemeGraph.filterByTheme(dict.words, theme, themeMinScore);
|
|
||||||
System.out.println("Filtered to " + filteredWords.size() + " words for theme '" + theme + "'");
|
System.out.println("Filtered to " + filteredWords.size() + " words for theme '" + theme + "'");
|
||||||
|
|
||||||
// If too few words, fall back to general
|
// If too few words, fall back to general
|
||||||
@@ -98,11 +97,11 @@ public class DailyGenerator {
|
|||||||
|
|
||||||
// Generate puzzle
|
// Generate puzzle
|
||||||
var opts = new Main.Opts();
|
var opts = new Main.Opts();
|
||||||
opts.seed = seed + i;
|
opts.seed = seed + i;
|
||||||
opts.pop = 18;
|
opts.pop = 18;
|
||||||
opts.gens = 100;
|
opts.gens = 100;
|
||||||
opts.tries = 50;
|
opts.tries = 50;
|
||||||
opts.wordsPath = wordsPath;
|
opts.wordsPath = wordsPath;
|
||||||
opts.minSimplicity = 0; // default
|
opts.minSimplicity = 0; // default
|
||||||
|
|
||||||
var result = generateWithFilteredDict(opts, themedDict, llmScores);
|
var result = generateWithFilteredDict(opts, themedDict, llmScores);
|
||||||
|
|||||||
@@ -1,229 +0,0 @@
|
|||||||
package puzzle;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.http.HttpClient;
|
|
||||||
import java.net.http.HttpRequest;
|
|
||||||
import java.net.http.HttpResponse;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ollama Dutch Wordlist Scorer
|
|
||||||
* Scores 90k Dutch words on popularity/complexity using local Ollama API
|
|
||||||
*/
|
|
||||||
public class DutchWordScorer {
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
private static final String OLLAMA_ENDPOINT = "http://localhost:11434/api/chat";
|
|
||||||
private static final String MODEL = "qwen2.5:14b"; // or "llama3.1:latest"
|
|
||||||
private static final int BATCH_SIZE = 50; // Words per API call
|
|
||||||
private static final int RATE_LIMIT_DELAY_MS = 500; // Be nice to local Ollama
|
|
||||||
private static final int MAX_RETRIES = 3;
|
|
||||||
|
|
||||||
// Input/output files
|
|
||||||
private static final String INPUT_WORDLIST = "word-list.txt";
|
|
||||||
private static final String OUTPUT_SCORES = "word_scores.csv";
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
System.out.println("Starting Dutch wordlist scoring...");
|
|
||||||
|
|
||||||
// Read all words
|
|
||||||
List<String> words = Files.readAllLines(Paths.get(INPUT_WORDLIST));
|
|
||||||
System.out.printf("Loaded %d words from %s%n", words.size(), INPUT_WORDLIST);
|
|
||||||
|
|
||||||
// Process in batches
|
|
||||||
HttpClient client = HttpClient.newBuilder()
|
|
||||||
.connectTimeout(java.time.Duration.ofSeconds(30))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<WordScore> allScores = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < words.size(); i += BATCH_SIZE) {
|
|
||||||
int end = Math.min(i + BATCH_SIZE, words.size());
|
|
||||||
List<String> batch = words.subList(i, end);
|
|
||||||
|
|
||||||
System.out.printf("Processing batch %d-%d...%n", i + 1, end);
|
|
||||||
|
|
||||||
boolean success = false;
|
|
||||||
int retries = 0;
|
|
||||||
|
|
||||||
while (!success && retries < MAX_RETRIES) {
|
|
||||||
try {
|
|
||||||
List<WordScore> batchScores = processBatch(client, batch);
|
|
||||||
allScores.addAll(batchScores);
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
// Rate limiting
|
|
||||||
if (i + BATCH_SIZE < words.size()) {
|
|
||||||
Thread.sleep(RATE_LIMIT_DELAY_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
retries++;
|
|
||||||
System.err.printf("Batch %d-%d failed (attempt %d/%d): %s%n",
|
|
||||||
i + 1, end, retries, MAX_RETRIES, e.getMessage());
|
|
||||||
|
|
||||||
if (retries >= MAX_RETRIES) {
|
|
||||||
System.err.println("Max retries reached, skipping batch");
|
|
||||||
// Add null scores for failed batch to maintain alignment
|
|
||||||
batch.forEach(w -> allScores.add(new WordScore(w, -1, "FAILED")));
|
|
||||||
} else {
|
|
||||||
Thread.sleep(2000 * retries); // Exponential backoff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write results
|
|
||||||
writeScoresToCsv(allScores);
|
|
||||||
System.out.printf("Completed! Scored %d words. Results saved to %s%n",
|
|
||||||
allScores.size(), OUTPUT_SCORES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<WordScore> processBatch(HttpClient client, List<String> batch) throws Exception {
|
|
||||||
String prompt = createScoringPrompt(batch);
|
|
||||||
|
|
||||||
// Build JSON request
|
|
||||||
String jsonRequest = buildChatRequestJson(prompt);
|
|
||||||
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(OLLAMA_ENDPOINT))
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(jsonRequest))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
HttpResponse<String> response = client.send(request,
|
|
||||||
HttpResponse.BodyHandlers.ofString());
|
|
||||||
|
|
||||||
if (response.statusCode() != 200) {
|
|
||||||
throw new RuntimeException("HTTP " + response.statusCode() + ": " + response.body());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse response
|
|
||||||
String responseBody = response.body();
|
|
||||||
String assistantReply = extractMessageContent(responseBody);
|
|
||||||
|
|
||||||
return parseScoresFromReply(batch, assistantReply);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String createScoringPrompt(List<String> words) {
|
|
||||||
return """
|
|
||||||
Je bent een Nederlandse taalexpert. Geef elk woord een populariteitsscore van 1-10.
|
|
||||||
|
|
||||||
Score criteria:
|
|
||||||
- 1 = Zeer zeldzaam, archaïsch, of extreem specifiek vakjargon
|
|
||||||
- 10 = Zeer algemeen, dagelijks gebruikt door iedereen
|
|
||||||
|
|
||||||
Geef ALLEEN een lijst in dit exacte formaat, niets anders:
|
|
||||||
woord1:score
|
|
||||||
woord2:score
|
|
||||||
enz.
|
|
||||||
|
|
||||||
Woorden om te scoren:
|
|
||||||
""" + String.join("\n", words);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildChatRequestJson(String prompt) {
|
|
||||||
// Simple JSON building (in production use a library like Jackson)
|
|
||||||
return String.format("""
|
|
||||||
{
|
|
||||||
"model": "%s",
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "%s"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stream": false,
|
|
||||||
"temperature": 0.1
|
|
||||||
}
|
|
||||||
""", MODEL, escapeJson(prompt));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String escapeJson(String str) {
|
|
||||||
return str.replace("\\", "\\\\")
|
|
||||||
.replace("\"", "\\\"")
|
|
||||||
.replace("\n", "\\n")
|
|
||||||
.replace("\r", "\\r")
|
|
||||||
.replace("\t", "\\t");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String extractMessageContent(String responseBody) {
|
|
||||||
// Parse: "message":{"role":"assistant","content":"..."}
|
|
||||||
int contentStart = responseBody.indexOf("\"content\":\"") + 11;
|
|
||||||
int contentEnd = responseBody.indexOf("\"", contentStart);
|
|
||||||
return responseBody.substring(contentStart, contentEnd)
|
|
||||||
.replace("\\n", "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<WordScore> parseScoresFromReply(List<String> expectedWords, String reply) {
|
|
||||||
Map<String, Integer> wordScoreMap = new HashMap<>();
|
|
||||||
String[] lines = reply.split("\n");
|
|
||||||
|
|
||||||
for (String line : lines) {
|
|
||||||
line = line.trim();
|
|
||||||
if (line.contains(":")) {
|
|
||||||
String[] parts = line.split(":", 2);
|
|
||||||
if (parts.length == 2) {
|
|
||||||
String word = parts[0].trim().toLowerCase();
|
|
||||||
try {
|
|
||||||
int score = Integer.parseInt(parts[1].trim());
|
|
||||||
wordScoreMap.put(word, Math.max(1, Math.min(10, score)));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// Skip invalid lines
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match scores to original words (maintaining order)
|
|
||||||
List<WordScore> results = new ArrayList<>();
|
|
||||||
for (String word : expectedWords) {
|
|
||||||
Integer score = wordScoreMap.get(word.toLowerCase());
|
|
||||||
if (score != null) {
|
|
||||||
results.add(new WordScore(word, score, "OK"));
|
|
||||||
} else {
|
|
||||||
System.err.printf("Warning: No score found for '%s'%n", word);
|
|
||||||
results.add(new WordScore(word, -1, "MISSING"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeScoresToCsv(List<WordScore> scores) throws Exception {
|
|
||||||
List<String> lines = new ArrayList<>();
|
|
||||||
lines.add("word,score,status");
|
|
||||||
|
|
||||||
for (WordScore ws : scores) {
|
|
||||||
lines.add(String.format("%s,%d,%s", ws.word, ws.score, ws.status));
|
|
||||||
}
|
|
||||||
|
|
||||||
Files.write(Paths.get(OUTPUT_SCORES), lines);
|
|
||||||
}
|
|
||||||
// ===== DATA CLASS =====
|
|
||||||
static class WordScore {
|
|
||||||
|
|
||||||
String word;
|
|
||||||
int score;
|
|
||||||
String status;
|
|
||||||
String endpoint;
|
|
||||||
int batchId;
|
|
||||||
|
|
||||||
WordScore(String word, int score, String status, String endpoint, int batchId) {
|
|
||||||
this.word = word;
|
|
||||||
this.score = score;
|
|
||||||
this.status = status;
|
|
||||||
this.endpoint = endpoint;
|
|
||||||
this.batchId = batchId;
|
|
||||||
}
|
|
||||||
WordScore(String word, int score, String status) {
|
|
||||||
this.word = word;
|
|
||||||
this.score = score;
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
package puzzle;
|
package puzzle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -7,10 +8,7 @@ import java.nio.file.Paths;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
// ---------------- CLI ----------------
|
// ---------------- CLI ----------------
|
||||||
@@ -18,9 +16,9 @@ public class Main {
|
|||||||
public static class Opts {
|
public static class Opts {
|
||||||
public int seed = 1;
|
public int seed = 1;
|
||||||
public int pop = 18;
|
public int pop = 18;
|
||||||
public int gens = 1000;
|
public int gens = 500;
|
||||||
public int tries = 5;
|
public int tries = 5;
|
||||||
public String wordsPath = "./out/pool.txt";
|
public String wordsPath = "/data/puzzle/pool.txt";
|
||||||
public double minSimplicity = 0; // 0 means no limit
|
public double minSimplicity = 0; // 0 means no limit
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +32,7 @@ public class Main {
|
|||||||
--pop 18
|
--pop 18
|
||||||
--gens 100
|
--gens 100
|
||||||
--tries 50
|
--tries 50
|
||||||
--words ./out/pool.txt
|
--words /data/pool.txt
|
||||||
--min-simplicity 0 (no limit)
|
--min-simplicity 0 (no limit)
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,18 +153,18 @@ public class SwedishGenerator {
|
|||||||
static Map<String, Integer> loadScores() {
|
static Map<String, Integer> loadScores() {
|
||||||
var scores = new HashMap<String, Integer>();
|
var scores = new HashMap<String, Integer>();
|
||||||
try {
|
try {
|
||||||
var lines = Files.readAllLines(Path.of("export_words.csv"), StandardCharsets.UTF_8);
|
var lines = Files.readAllLines(Path.of("/data/puzzle/export_with_hints.csv"), StandardCharsets.UTF_8);
|
||||||
var first = true;
|
var first = true;
|
||||||
for (var line : lines) {
|
for (var line : lines) {
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var parts = line.split(",");
|
var parts = line.split(",",3);
|
||||||
if (parts.length >= 2) {
|
if (parts.length >= 2) {
|
||||||
try {
|
try {
|
||||||
var word = parts[0].trim().toUpperCase(Locale.ROOT);
|
var word = parts[0].trim().toUpperCase(Locale.ROOT);
|
||||||
var score = Integer.parseInt(parts[1].trim());
|
var score = 10-Integer.parseInt(parts[1].trim());
|
||||||
scores.put(word, score);
|
scores.put(word, score);
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
System.err.println("Illegal number format: " + line);
|
System.err.println("Illegal number format: " + line);
|
||||||
@@ -200,7 +200,8 @@ public class SwedishGenerator {
|
|||||||
|
|
||||||
var words = new ArrayList<WordDifficulty>();
|
var words = new ArrayList<WordDifficulty>();
|
||||||
for (var line : raw.split("\\R")) {
|
for (var line : raw.split("\\R")) {
|
||||||
var s = line.trim().toUpperCase(Locale.ROOT);
|
var word = line.split(",",3)[0].trim();
|
||||||
|
var s = word.trim().toUpperCase(Locale.ROOT);
|
||||||
if (s.matches("^[A-Z]{2,8}$")) {
|
if (s.matches("^[A-Z]{2,8}$")) {
|
||||||
var score = llmScores.getOrDefault(s, 5); // Default to middle
|
var score = llmScores.getOrDefault(s, 5); // Default to middle
|
||||||
words.add(new WordDifficulty(s, score));
|
words.add(new WordDifficulty(s, score));
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
package puzzle;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ThemeGraph - Creates a graph between words and themes for filtering.
|
|
||||||
* Uses word embeddings approach: co-occurrence and semantic similarity.
|
|
||||||
*/
|
|
||||||
public class ThemeGraph {
|
|
||||||
|
|
||||||
// Predefined theme keywords for Dutch word filtering
|
|
||||||
private static final Map<String, Set<String>> THEME_KEYWORDS = new HashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
// News/Politics
|
|
||||||
THEME_KEYWORDS.put("nieuws", Set.of(
|
|
||||||
"POLITIEK", "VERKIEZING", "MINISTER", "PARLEMENT", "WET", "BELEID",
|
|
||||||
"REGERING", "PARTIJ", "STEM", "KAMER", "RAAD", "STAAT"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Technology
|
|
||||||
THEME_KEYWORDS.put("technologie", Set.of(
|
|
||||||
"COMPUTER", "INTERNET", "SOFTWARE", "APP", "DATA", "CODE",
|
|
||||||
"NETWERK", "SYSTEEM", "DIGITAAL", "TECH", "ROBOT", "AI"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Sports
|
|
||||||
THEME_KEYWORDS.put("sport", Set.of(
|
|
||||||
"VOETBAL", "TENNIS", "WIELREN", "SPELER", "WEDSTRIJD", "TEAM",
|
|
||||||
"GOAL", "BAL", "SPEL", "WINNEN", "COACH", "ATLEET"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Weather/Nature
|
|
||||||
THEME_KEYWORDS.put("weer", Set.of(
|
|
||||||
"REGEN", "ZON", "WIND", "WOLKEN", "STORM", "SNEEUW",
|
|
||||||
"WEER", "KLIMAAT", "NATUUR", "LUCHT", "WARMTE", "KOU"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Economy
|
|
||||||
THEME_KEYWORDS.put("economie", Set.of(
|
|
||||||
"GELD", "EURO", "MARKT", "PRIJS", "KOPEN", "VERKOOP",
|
|
||||||
"BEDRIJF", "BANK", "HANDEL", "WINST", "SCHULD", "BUDGET"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Health
|
|
||||||
THEME_KEYWORDS.put("gezondheid", Set.of(
|
|
||||||
"ZORG", "DOKTER", "MEDICIJN", "PATIENT", "ZIEKENHUIS", "GEZOND",
|
|
||||||
"VIRUS", "VACCIN", "THERAPIE", "BEHANDEL", "ARTS", "KLINIEK"
|
|
||||||
));
|
|
||||||
|
|
||||||
// General/Common
|
|
||||||
THEME_KEYWORDS.put("algemeen", Set.of(
|
|
||||||
"HUIS", "AUTO", "BOOM", "WATER", "MENS", "TIJD",
|
|
||||||
"LEVEN", "WERK", "SCHOOL", "FAMILIE", "STAD", "LAND"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Score a word against a theme (0.0 = no match, 1.0 = perfect match)
|
|
||||||
*/
|
|
||||||
public static double scoreWordTheme(String word, String theme) {
|
|
||||||
var keywords = THEME_KEYWORDS.get(theme.toLowerCase());
|
|
||||||
if (keywords == null) {
|
|
||||||
return 0.5; // unknown theme = neutral score
|
|
||||||
}
|
|
||||||
|
|
||||||
word = word.toUpperCase();
|
|
||||||
|
|
||||||
// Direct match
|
|
||||||
if (keywords.contains(word)) {
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substring match (partial relevance)
|
|
||||||
for (var kw : keywords) {
|
|
||||||
if (word.contains(kw) || kw.contains(word)) {
|
|
||||||
return 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edit distance similarity (for typos/variations)
|
|
||||||
for (var kw : keywords) {
|
|
||||||
var similarity = editDistanceSimilarity(word, kw);
|
|
||||||
if (similarity > 0.8) {
|
|
||||||
return similarity * 0.9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter word list by theme with minimum score threshold
|
|
||||||
*/
|
|
||||||
public static List<String> filterByTheme(List<String> words, String theme, double minScore) {
|
|
||||||
List<String> filtered = new ArrayList<>();
|
|
||||||
for (var word : words) {
|
|
||||||
var score = scoreWordTheme(word, theme);
|
|
||||||
if (score >= minScore) {
|
|
||||||
filtered.add(word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get theme suggestions for a word (sorted by score)
|
|
||||||
*/
|
|
||||||
public static List<ThemeScore> getThemesForWord(String word) {
|
|
||||||
List<ThemeScore> scores = new ArrayList<>();
|
|
||||||
for (var theme : THEME_KEYWORDS.keySet()) {
|
|
||||||
var score = scoreWordTheme(word, theme);
|
|
||||||
if (score > 0.0) {
|
|
||||||
scores.add(new ThemeScore(theme, score));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scores.sort(Comparator.comparingDouble(ts -> -ts.score));
|
|
||||||
return scores;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-detect best theme from a word list
|
|
||||||
*/
|
|
||||||
public static String detectTheme(List<String> words) {
|
|
||||||
Map<String, Double> themeScores = new HashMap<>();
|
|
||||||
|
|
||||||
for (var theme : THEME_KEYWORDS.keySet()) {
|
|
||||||
double totalScore = 0;
|
|
||||||
for (var word : words) {
|
|
||||||
totalScore += scoreWordTheme(word, theme);
|
|
||||||
}
|
|
||||||
themeScores.put(theme, totalScore / words.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return themeScores.entrySet().stream()
|
|
||||||
.max(Comparator.comparingDouble(Map.Entry::getValue))
|
|
||||||
.map(Map.Entry::getKey)
|
|
||||||
.orElse("algemeen");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple edit distance similarity (normalized Levenshtein)
|
|
||||||
*/
|
|
||||||
private static double editDistanceSimilarity(String a, String b) {
|
|
||||||
var dist = levenshtein(a, b);
|
|
||||||
var maxLen = Math.max(a.length(), b.length());
|
|
||||||
if (maxLen == 0) return 1.0;
|
|
||||||
return 1.0 - ((double) dist / maxLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int levenshtein(String a, String b) {
|
|
||||||
var dp = new int[a.length() + 1][b.length() + 1];
|
|
||||||
|
|
||||||
for (var i = 0; i <= a.length(); i++) dp[i][0] = i;
|
|
||||||
for (var j = 0; j <= b.length(); j++) dp[0][j] = j;
|
|
||||||
|
|
||||||
for (var i = 1; i <= a.length(); i++) {
|
|
||||||
for (var j = 1; j <= b.length(); j++) {
|
|
||||||
var cost = (a.charAt(i - 1) == b.charAt(j - 1)) ? 0 : 1;
|
|
||||||
dp[i][j] = Math.min(
|
|
||||||
Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1),
|
|
||||||
dp[i - 1][j - 1] + cost
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dp[a.length()][b.length()];
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ThemeScore(String theme, double score) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("%s: %.2f", theme, score);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Main for testing ----
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("=== Theme Graph Test ===\n");
|
|
||||||
|
|
||||||
// Test word scoring
|
|
||||||
var testWords = new String[]{ "POLITIEK", "VOETBAL", "COMPUTER", "REGEN", "AUTO" };
|
|
||||||
for (var word : testWords) {
|
|
||||||
System.out.println("Word: " + word);
|
|
||||||
var themes = getThemesForWord(word);
|
|
||||||
for (var ts : themes) {
|
|
||||||
System.out.println(" " + ts);
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test theme detection
|
|
||||||
var techWords = Arrays.asList("COMPUTER", "INTERNET", "SOFTWARE", "DATA");
|
|
||||||
var detected = detectTheme(techWords);
|
|
||||||
System.out.println("Detected theme for tech words: " + detected);
|
|
||||||
|
|
||||||
// Test filtering
|
|
||||||
var allWords = Arrays.asList(
|
|
||||||
"POLITIEK", "COMPUTER", "AUTO", "VOETBAL", "INTERNET", "BOOM"
|
|
||||||
);
|
|
||||||
var filtered = filterByTheme(allWords, "technologie", 0.5);
|
|
||||||
System.out.println("\nFiltered for 'technologie' (min 0.5): " + filtered);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,18 +10,23 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SuppressWarnings("ALL")
|
|
||||||
public class ThemePoolBuilderLength {
|
public class ThemePoolBuilderLength {
|
||||||
|
|
||||||
private static final List<String> DEFAULT_FEEDS = List.of(
|
private static final List<String> DEFAULT_FEEDS = List.of(
|
||||||
"https://feeds.nos.nl/nosnieuwsalgemeen",
|
"https://feeds.nos.nl/nosnieuwsalgemeen",
|
||||||
"https://feeds.nos.nl/nosnieuwstech"
|
"https://feeds.nos.nl/nosnieuwstech");
|
||||||
);
|
static final String url = "jdbc:postgresql://192.168.1.159:5432/postgres";
|
||||||
|
static final String user = "puzzle";
|
||||||
|
static final String pass = "heel-goed-wachtwoord";
|
||||||
// NOTE: normalizeDutchToken strips non A-Z. Keep entries 2-8 after normalization.
|
// NOTE: normalizeDutchToken strips non A-Z. Keep entries 2-8 after normalization.
|
||||||
private static final List<String> DEFAULT_SHORTS = List.of(
|
private static final List<String> DEFAULT_SHORTS = List.of(
|
||||||
"EU", "VS", "UK", "NAVO", "NOS", "NS", "ANP", "VN", "NPO", "RTL",
|
"EU", "VS", "UK", "NAVO", "NOS", "NS", "ANP", "VN", "NPO", "RTL",
|
||||||
@@ -51,46 +56,157 @@ public class ThemePoolBuilderLength {
|
|||||||
"XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"
|
"XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX"
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final String BROWSER_UA =
|
private static final String BROWSER_UA =
|
||||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36";
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36";
|
||||||
|
static int MIN_SIMPLICITY = 520;
|
||||||
|
|
||||||
static final class Opts {
|
static final class Opts {
|
||||||
|
|
||||||
String wordsPath = "/home/mike/dev/puzzle-generator/export_words_only.txt";
|
String endpoint = "https://jarvis-lan.appmodel.nl/api/stoic/";
|
||||||
String endpoint = "https://jarvis-lan.appmodel.nl/api/stoic/";
|
List<String> feeds = new ArrayList<>(DEFAULT_FEEDS);
|
||||||
List<String> feeds = new ArrayList<>(DEFAULT_FEEDS);
|
String outDir = "/data/puzzle";
|
||||||
String outDir = "./out";
|
int bridgeN = 30000;
|
||||||
|
int themeN = 800;
|
||||||
int bridgeN = 40000;
|
int relatedN = 2200;
|
||||||
int themeN = 800;
|
int rssItemsPerFeed = 10;
|
||||||
int relatedN = 2200;
|
String model = "mistralai/mistral-nemo-instruct-2407";
|
||||||
int rssItemsPerFeed = 10;
|
int timeoutSeconds = 180;
|
||||||
|
int retries = 2;
|
||||||
String model = "mistralai/mistral-nemo-instruct-2407";
|
int minLen2 = 1000;
|
||||||
int timeoutSeconds = 180;
|
int minLen3 = 1000;
|
||||||
int retries = 2;
|
int minLen4 = 1000;
|
||||||
|
int minLen5 = 1000; // set if you also want to force 5-letter words, etc.
|
||||||
// ---- NEW: enforce minimum counts per length in the final pool ----
|
int minLen6 = 1000;
|
||||||
// Tune these to your puzzle generator’s appetite for short words.
|
int minLen7 = 1000;
|
||||||
int minLen2 = 1000;
|
int minLen8 = 1000;
|
||||||
int minLen3 = 1000;
|
|
||||||
int minLen4 = 1000;
|
|
||||||
int minLen5 = 1000; // set if you also want to force 5-letter words, etc.
|
|
||||||
int minLen6 = 2000;
|
|
||||||
int minLen7 = 2000;
|
|
||||||
int minLen8 = 2000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
var o = parseArgs(args);
|
||||||
|
|
||||||
|
var outDir = Path.of(o.outDir);
|
||||||
|
Files.createDirectories(outDir);
|
||||||
|
|
||||||
|
System.out.println("Loading lexicon...");
|
||||||
|
Lexicon lex;
|
||||||
|
Class.forName("org.postgresql.Driver");
|
||||||
|
try (var c = DriverManager.getConnection(url, user, pass);) {
|
||||||
|
lex = loadLexicon(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Master words (2-8, A-Z): " + lex.words.size());
|
||||||
|
|
||||||
|
// RSS via curl (browser-like)
|
||||||
|
var all = new ArrayList<RssItem>();
|
||||||
|
for (var feed : o.feeds) {
|
||||||
|
var f = feed.trim();
|
||||||
|
if (f.isEmpty()) continue;
|
||||||
|
System.out.println("Fetching RSS: " + f);
|
||||||
|
all.addAll(fetchRssViaCurlBrowser(f, o.rssItemsPerFeed, o.timeoutSeconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
var rssText = new StringBuilder();
|
||||||
|
var k = 0;
|
||||||
|
for (var it : all) {
|
||||||
|
k++;
|
||||||
|
rssText.append(k).append(". ").append(it.title).append("\n");
|
||||||
|
if (!it.desc.isBlank()) rssText.append(" ").append(it.desc).append("\n");
|
||||||
|
}
|
||||||
|
Files.writeString(outDir.resolve("rss.txt"), rssText.toString(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// LM Studio via curl
|
||||||
|
var modelId = o.model;
|
||||||
|
if (modelId == null) {
|
||||||
|
var modelsUrl = apiUrl(o.endpoint, "/models");
|
||||||
|
System.out.println("LM Studio GET: " + modelsUrl);
|
||||||
|
var modelsJson = curlGetJson(o, modelsUrl);
|
||||||
|
modelId = pickModelId(modelsJson);
|
||||||
|
if (modelId == null) {
|
||||||
|
throw new IOException("Could not auto-pick model id from /v1/models. Use --model <id>.\n--- /models ---\n" + modelsJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Using model: " + modelId);
|
||||||
|
System.out.println("Generating theme words via LM Studio...");
|
||||||
|
var llmWords = llmThemeWords(o, modelId, rssText.toString());
|
||||||
|
|
||||||
|
var themeKept = new LinkedHashSet<String>();
|
||||||
|
for (var wRaw : llmWords) {
|
||||||
|
var w = normalizeDutchToken(wRaw);
|
||||||
|
if (w == null) continue;
|
||||||
|
if (lex.idOf.containsKey(w)) themeKept.add(w);
|
||||||
|
}
|
||||||
|
Files.write(outDir.resolve("theme.txt"), themeKept, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// BitSets
|
||||||
|
var themeBs = bitmapFromWords(lex, themeKept);
|
||||||
|
var bridgeBs = buildBridgeBitmap(lex, o.bridgeN);
|
||||||
|
var shortBs = bitmapFromWords(lex, DEFAULT_SHORTS);
|
||||||
|
|
||||||
|
var pool = new BitSet(lex.words.size());
|
||||||
|
pool.or(themeBs);
|
||||||
|
pool.or(bridgeBs);
|
||||||
|
pool.or(shortBs);
|
||||||
|
|
||||||
|
// ---- NEW: enforce minimum counts per length ----
|
||||||
|
enforceMinima(o, lex, pool);
|
||||||
|
|
||||||
|
// Report
|
||||||
|
var themeCounts = countsPerLen(lex, themeBs);
|
||||||
|
var poolCounts = countsPerLen(lex, pool);
|
||||||
|
|
||||||
|
var report = """
|
||||||
|
Date: %s
|
||||||
|
Feeds: %s
|
||||||
|
Model: %s
|
||||||
|
|
||||||
|
Master size: %d
|
||||||
|
Theme kept (in master): %d
|
||||||
|
Bridge size: %d
|
||||||
|
Shorts kept: %d
|
||||||
|
Pool total: %d
|
||||||
|
|
||||||
|
Enforced minima:
|
||||||
|
2: %d
|
||||||
|
3: %d
|
||||||
|
4: %d
|
||||||
|
5: %d
|
||||||
|
6: %d
|
||||||
|
7: %d
|
||||||
|
8: %d
|
||||||
|
|
||||||
|
Counts per length (theme):
|
||||||
|
%s
|
||||||
|
|
||||||
|
Counts per length (pool):
|
||||||
|
%s
|
||||||
|
""".formatted(
|
||||||
|
LocalDate.now(),
|
||||||
|
String.join(", ", o.feeds),
|
||||||
|
modelId,
|
||||||
|
lex.words.size(),
|
||||||
|
themeBs.cardinality(),
|
||||||
|
bridgeBs.cardinality(),
|
||||||
|
shortBs.cardinality(),
|
||||||
|
pool.cardinality(),
|
||||||
|
o.minLen2, o.minLen3, o.minLen4, o.minLen5, o.minLen6, o.minLen7, o.minLen8,
|
||||||
|
mapToLines(themeCounts),
|
||||||
|
mapToLines(poolCounts)
|
||||||
|
);
|
||||||
|
|
||||||
|
Files.writeString(outDir.resolve("report.txt"), report, StandardCharsets.UTF_8);
|
||||||
|
System.out.println(report);
|
||||||
|
|
||||||
|
// Output pool list
|
||||||
|
var poolFile = outDir.resolve("pool.txt");
|
||||||
|
writeWordList(poolFile, lex, pool);
|
||||||
|
System.out.println("Wrote: " + poolFile.toAbsolutePath());
|
||||||
|
}
|
||||||
static Opts parseArgs(String[] args) {
|
static Opts parseArgs(String[] args) {
|
||||||
var o = new Opts();
|
var o = new Opts();
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
var a = args[i];
|
var a = args[i];
|
||||||
var v = (i + 1 < args.length) ? args[i + 1] : null;
|
var v = (i + 1 < args.length) ? args[i + 1] : null;
|
||||||
switch (a) {
|
switch (a) {
|
||||||
case "--words" -> {
|
|
||||||
o.wordsPath = v;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
case "--endpoint" -> {
|
case "--endpoint" -> {
|
||||||
o.endpoint = v;
|
o.endpoint = v;
|
||||||
i++;
|
i++;
|
||||||
@@ -193,7 +309,6 @@ public class ThemePoolBuilderLength {
|
|||||||
default -> throw new IllegalArgumentException("Unknown arg: " + a);
|
default -> throw new IllegalArgumentException("Unknown arg: " + a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (o.wordsPath == null) throw new IllegalArgumentException("--words is required");
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,54 +379,50 @@ public class ThemePoolBuilderLength {
|
|||||||
*/
|
*/
|
||||||
record Lexicon(List<String> words, Map<String, Integer> idOf, int[] score, BitSet[] byLen) { }
|
record Lexicon(List<String> words, Map<String, Integer> idOf, int[] score, BitSet[] byLen) { }
|
||||||
|
|
||||||
static Lexicon loadLexicon(String path) throws IOException {
|
/**
|
||||||
var lines = Files.readAllLines(Path.of(path), StandardCharsets.UTF_8);
|
* Loads lexicon from PostgreSQL view/table: export_words_with_hints_2_8
|
||||||
|
* Columns: WOORD, level_1_to_10, hint
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - Normalizes words via normalizeDutchToken(...)
|
||||||
|
* - Dedupes on normalized word
|
||||||
|
* - Uses level_1_to_10 as the "LLM score" (fallback 5)
|
||||||
|
* - Ignores hint for scoring (but you can store it elsewhere if needed)
|
||||||
|
*/
|
||||||
|
static Lexicon loadLexicon(Connection conn) throws SQLException {
|
||||||
|
var out = new ArrayList<String>(200_000);
|
||||||
|
var idOf = new HashMap<String, Integer>(400_000);
|
||||||
|
|
||||||
var out = new ArrayList<String>(lines.size());
|
// Store level per normalized word while loading so we can compute scores later
|
||||||
var idOf = new HashMap<String, Integer>(lines.size() * 2);
|
var levelOf = new HashMap<String, Integer>(400_000);
|
||||||
|
|
||||||
// 1) master lexicon
|
final var sql = """
|
||||||
for (var line : lines) {
|
SELECT woord, 10-level_1_to_10, hint
|
||||||
var w = normalizeDutchToken(line);
|
FROM export_words_with_hints_2_8
|
||||||
if (w == null) continue;
|
order by level_1_to_10 asc
|
||||||
if (idOf.containsKey(w)) continue;
|
""";
|
||||||
idOf.put(w, out.size());
|
|
||||||
out.add(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* // 2) ensure DEFAULT_SHORTS are present even if absent in word-list.txt
|
try (var ps = conn.prepareStatement(sql);
|
||||||
for (var raw : DEFAULT_SHORTS) {
|
var rs = ps.executeQuery()) {
|
||||||
var w = normalizeDutchToken(raw);
|
|
||||||
if (w == null) continue;
|
|
||||||
if (idOf.containsKey(w)) continue;
|
|
||||||
idOf.put(w, out.size());
|
|
||||||
out.add(w);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Load LLM scores
|
while (rs.next()) {
|
||||||
var llmScores = new HashMap<String, Integer>();
|
var rawWord = rs.getString(1);
|
||||||
try {
|
var lvlObj = (Integer) rs.getObject(2); // nullable
|
||||||
var scoreLines = Files.readAllLines(Path.of("word_scores.csv"), StandardCharsets.UTF_8);
|
// String hint = rs.getString(3); // available if you want it later
|
||||||
var first = true;
|
|
||||||
for (var line : scoreLines) {
|
var w = normalizeDutchToken(rawWord);
|
||||||
if (first) {
|
if (w == null) continue;
|
||||||
first = false;
|
|
||||||
continue;
|
if (idOf.containsKey(w)) continue;
|
||||||
}
|
|
||||||
var parts = line.split(",", 3);
|
idOf.put(w, out.size());
|
||||||
if (parts.length >= 3) {
|
out.add(w);
|
||||||
try {
|
|
||||||
var word = parts[0].trim().toUpperCase(Locale.ROOT);
|
var lvl = (lvlObj == null ? 5 : lvlObj.intValue());
|
||||||
var score = Integer.parseInt(parts[1].trim());
|
levelOf.put(w, lvl);
|
||||||
// var status = parts[2].trim();
|
|
||||||
// if ("OK".equalsIgnoreCase(status)) {
|
|
||||||
llmScores.put(word, score);
|
|
||||||
//}
|
|
||||||
} catch (NumberFormatException ignored) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (SQLException e) {
|
||||||
System.err.println("Warning: word_scores.csv not found, using default scores.");
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
var n = out.size();
|
var n = out.size();
|
||||||
@@ -322,11 +433,12 @@ public class ThemePoolBuilderLength {
|
|||||||
for (var i = 0; i < n; i++) {
|
for (var i = 0; i < n; i++) {
|
||||||
var w = out.get(i);
|
var w = out.get(i);
|
||||||
var crossScore = crossabilityScore(w);
|
var crossScore = crossabilityScore(w);
|
||||||
var lScore = llmScores.getOrDefault(w, 5);
|
var lScore = levelOf.getOrDefault(w, 5);
|
||||||
|
|
||||||
// Prioritize simple words (high lScore) and long words.
|
// Prioritize simple words (high lScore) and long words.
|
||||||
// lScore (1-10) adds up to 1000 points (weight 100).
|
// lScore (1-10) adds up to 1000 points (weight 100).
|
||||||
// Length (2-8) adds up to 160 points (weight 20).
|
// Length (2-8) adds up to 160 points (weight 20).
|
||||||
score[i] = crossScore + (lScore * 100) + (w.length() * 30);
|
score[i] = crossScore + (lScore * 100) + (w.length() * 40);
|
||||||
byLen[w.length()].set(i);
|
byLen[w.length()].set(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,15 +447,7 @@ public class ThemePoolBuilderLength {
|
|||||||
|
|
||||||
// ---------------- RSS via curl (browser-like) ----------------
|
// ---------------- RSS via curl (browser-like) ----------------
|
||||||
|
|
||||||
static final class RssItem {
|
record RssItem(String title, String desc) { }
|
||||||
|
|
||||||
final String title;
|
|
||||||
final String desc;
|
|
||||||
RssItem(String title, String desc) {
|
|
||||||
this.title = title;
|
|
||||||
this.desc = desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String textOfFirst(Element parent, String tag) {
|
static String textOfFirst(Element parent, String tag) {
|
||||||
var nl = parent.getElementsByTagName(tag);
|
var nl = parent.getElementsByTagName(tag);
|
||||||
@@ -353,7 +457,7 @@ public class ThemePoolBuilderLength {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<RssItem> fetchRssViaCurlBrowser(String url, int limit, int timeoutSeconds) throws Exception {
|
static List<RssItem> fetchRssViaCurlBrowser(String url, int limit, int timeoutSeconds) throws Exception {
|
||||||
List<String> cmd = new ArrayList<>();
|
var cmd = new ArrayList<String>();
|
||||||
cmd.add("curl");
|
cmd.add("curl");
|
||||||
cmd.add("-fsSL");
|
cmd.add("-fsSL");
|
||||||
cmd.add("-L");
|
cmd.add("-L");
|
||||||
@@ -433,38 +537,6 @@ public class ThemePoolBuilderLength {
|
|||||||
return base + path;
|
return base + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HttpClient buildHttpClient(int timeoutSeconds) {
|
|
||||||
try {
|
|
||||||
return HttpClient.newBuilder()
|
|
||||||
.connectTimeout(java.time.Duration.ofSeconds(Math.max(10, timeoutSeconds)))
|
|
||||||
.build();
|
|
||||||
} catch (RuntimeException ignored) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
var ssl = insecureSslContext();
|
|
||||||
return HttpClient.newBuilder()
|
|
||||||
.connectTimeout(java.time.Duration.ofSeconds(Math.max(10, timeoutSeconds)))
|
|
||||||
.sslContext(ssl)
|
|
||||||
.build();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Could not initialize HttpClient. Fix Java truststore or use curl for all HTTP.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static SSLContext insecureSslContext() throws Exception {
|
|
||||||
var trustAll = new TrustManager[]{
|
|
||||||
new X509TrustManager() {
|
|
||||||
|
|
||||||
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType) { }
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType) { }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var ssl = SSLContext.getInstance("TLS");
|
|
||||||
ssl.init(null, trustAll, new SecureRandom());
|
|
||||||
return ssl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sleepBackoff(int attempt) {
|
static void sleepBackoff(int attempt) {
|
||||||
try {
|
try {
|
||||||
var ms = (long) (300L * Math.pow(2, attempt - 1)); // 300, 600, 1200, ...
|
var ms = (long) (300L * Math.pow(2, attempt - 1)); // 300, 600, 1200, ...
|
||||||
@@ -476,7 +548,7 @@ public class ThemePoolBuilderLength {
|
|||||||
Exception last = null;
|
Exception last = null;
|
||||||
for (var attempt = 1; attempt <= o.retries; attempt++) {
|
for (var attempt = 1; attempt <= o.retries; attempt++) {
|
||||||
try {
|
try {
|
||||||
List<String> cmd = new ArrayList<>();
|
var cmd = new ArrayList<String>();
|
||||||
cmd.add("curl");
|
cmd.add("curl");
|
||||||
cmd.add("-fsSL");
|
cmd.add("-fsSL");
|
||||||
cmd.add("--connect-timeout");
|
cmd.add("--connect-timeout");
|
||||||
@@ -524,7 +596,6 @@ public class ThemePoolBuilderLength {
|
|||||||
var tempFile = Files.createTempFile("lm-request-", ".json");
|
var tempFile = Files.createTempFile("lm-request-", ".json");
|
||||||
try {
|
try {
|
||||||
Files.writeString(tempFile, jsonBody, StandardCharsets.UTF_8);
|
Files.writeString(tempFile, jsonBody, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
List<String> cmd = new ArrayList<>();
|
List<String> cmd = new ArrayList<>();
|
||||||
cmd.add("curl");
|
cmd.add("curl");
|
||||||
cmd.add("-fsSL");
|
cmd.add("-fsSL");
|
||||||
@@ -774,7 +845,7 @@ public class ThemePoolBuilderLength {
|
|||||||
|
|
||||||
var out = new ArrayList<String>(ids.size());
|
var out = new ArrayList<String>(ids.size());
|
||||||
for (var id : ids) {
|
for (var id : ids) {
|
||||||
if (lex.score[id] < 680)
|
if (lex.score[id] < MIN_SIMPLICITY)
|
||||||
continue;
|
continue;
|
||||||
out.add(lex.words.get(id));
|
out.add(lex.words.get(id));
|
||||||
}
|
}
|
||||||
@@ -833,123 +904,4 @@ public class ThemePoolBuilderLength {
|
|||||||
ensureMinLen(lex, pool, 8, o.minLen8);
|
ensureMinLen(lex, pool, 8, o.minLen8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- Main ----------------
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
var o = parseArgs(args);
|
|
||||||
|
|
||||||
var outDir = Path.of(o.outDir);
|
|
||||||
Files.createDirectories(outDir);
|
|
||||||
|
|
||||||
System.out.println("Loading lexicon...");
|
|
||||||
var lex = loadLexicon(o.wordsPath);
|
|
||||||
System.out.println("Master words (2-8, A-Z): " + lex.words.size());
|
|
||||||
|
|
||||||
// RSS via curl (browser-like)
|
|
||||||
var all = new ArrayList<RssItem>();
|
|
||||||
for (var feed : o.feeds) {
|
|
||||||
var f = feed.trim();
|
|
||||||
if (f.isEmpty()) continue;
|
|
||||||
System.out.println("Fetching RSS: " + f);
|
|
||||||
all.addAll(fetchRssViaCurlBrowser(f, o.rssItemsPerFeed, o.timeoutSeconds));
|
|
||||||
}
|
|
||||||
|
|
||||||
var rssText = new StringBuilder();
|
|
||||||
var k = 0;
|
|
||||||
for (var it : all) {
|
|
||||||
k++;
|
|
||||||
rssText.append(k).append(". ").append(it.title).append("\n");
|
|
||||||
if (!it.desc.isBlank()) rssText.append(" ").append(it.desc).append("\n");
|
|
||||||
}
|
|
||||||
Files.writeString(outDir.resolve("rss.txt"), rssText.toString(), StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
// LM Studio via curl
|
|
||||||
var modelId = o.model;
|
|
||||||
if (modelId == null) {
|
|
||||||
var modelsUrl = apiUrl(o.endpoint, "/models");
|
|
||||||
System.out.println("LM Studio GET: " + modelsUrl);
|
|
||||||
var modelsJson = curlGetJson(o, modelsUrl);
|
|
||||||
modelId = pickModelId(modelsJson);
|
|
||||||
if (modelId == null) {
|
|
||||||
throw new IOException("Could not auto-pick model id from /v1/models. Use --model <id>.\n--- /models ---\n" + modelsJson);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println("Using model: " + modelId);
|
|
||||||
|
|
||||||
System.out.println("Generating theme words via LM Studio...");
|
|
||||||
List<String> llmWords = llmThemeWords(o, modelId, rssText.toString());
|
|
||||||
|
|
||||||
// Normalize + keep only those present in master lexicon
|
|
||||||
var themeKept = new LinkedHashSet<String>();
|
|
||||||
for (var wRaw : llmWords) {
|
|
||||||
var w = normalizeDutchToken(wRaw);
|
|
||||||
if (w == null) continue;
|
|
||||||
if (lex.idOf.containsKey(w)) themeKept.add(w);
|
|
||||||
}
|
|
||||||
Files.write(outDir.resolve("theme.txt"), themeKept, StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
// BitSets
|
|
||||||
var themeBs = bitmapFromWords(lex, themeKept);
|
|
||||||
var bridgeBs = buildBridgeBitmap(lex, o.bridgeN);
|
|
||||||
var shortBs = bitmapFromWords(lex, DEFAULT_SHORTS);
|
|
||||||
|
|
||||||
var pool = new BitSet(lex.words.size());
|
|
||||||
pool.or(themeBs);
|
|
||||||
pool.or(bridgeBs);
|
|
||||||
pool.or(shortBs);
|
|
||||||
|
|
||||||
// ---- NEW: enforce minimum counts per length ----
|
|
||||||
enforceMinima(o, lex, pool);
|
|
||||||
|
|
||||||
// Report
|
|
||||||
var themeCounts = countsPerLen(lex, themeBs);
|
|
||||||
var poolCounts = countsPerLen(lex, pool);
|
|
||||||
|
|
||||||
var report = """
|
|
||||||
Date: %s
|
|
||||||
Feeds: %s
|
|
||||||
Model: %s
|
|
||||||
|
|
||||||
Master size: %d
|
|
||||||
Theme kept (in master): %d
|
|
||||||
Bridge size: %d
|
|
||||||
Shorts kept: %d
|
|
||||||
Pool total: %d
|
|
||||||
|
|
||||||
Enforced minima:
|
|
||||||
2: %d
|
|
||||||
3: %d
|
|
||||||
4: %d
|
|
||||||
5: %d
|
|
||||||
6: %d
|
|
||||||
7: %d
|
|
||||||
8: %d
|
|
||||||
|
|
||||||
Counts per length (theme):
|
|
||||||
%s
|
|
||||||
|
|
||||||
Counts per length (pool):
|
|
||||||
%s
|
|
||||||
""".formatted(
|
|
||||||
LocalDate.now(),
|
|
||||||
String.join(", ", o.feeds),
|
|
||||||
modelId,
|
|
||||||
lex.words.size(),
|
|
||||||
themeBs.cardinality(),
|
|
||||||
bridgeBs.cardinality(),
|
|
||||||
shortBs.cardinality(),
|
|
||||||
pool.cardinality(),
|
|
||||||
o.minLen2, o.minLen3, o.minLen4, o.minLen5, o.minLen6, o.minLen7, o.minLen8,
|
|
||||||
mapToLines(themeCounts),
|
|
||||||
mapToLines(poolCounts)
|
|
||||||
);
|
|
||||||
|
|
||||||
Files.writeString(outDir.resolve("report.txt"), report, StandardCharsets.UTF_8);
|
|
||||||
System.out.println(report);
|
|
||||||
|
|
||||||
// Output pool list
|
|
||||||
var poolFile = outDir.resolve("pool.txt");
|
|
||||||
writeWordList(poolFile, lex, pool);
|
|
||||||
System.out.println("Wrote: " + poolFile.toAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/puzzle/WordScore.java
Normal file
24
src/puzzle/WordScore.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package puzzle;
|
||||||
|
|
||||||
|
// ===== DATA CLASS =====
|
||||||
|
class WordScore {
|
||||||
|
|
||||||
|
String word;
|
||||||
|
int score;
|
||||||
|
String status;
|
||||||
|
String endpoint;
|
||||||
|
int batchId;
|
||||||
|
|
||||||
|
WordScore(String word, int score, String status, String endpoint, int batchId) {
|
||||||
|
this.word = word;
|
||||||
|
this.score = score;
|
||||||
|
this.status = status;
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.batchId = batchId;
|
||||||
|
}
|
||||||
|
WordScore(String word, int score, String status) {
|
||||||
|
this.word = word;
|
||||||
|
this.score = score;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/puzzle/postgresql-42.7.8.jar
Normal file
BIN
src/puzzle/postgresql-42.7.8.jar
Normal file
Binary file not shown.
91871
word-list.txt
91871
word-list.txt
File diff suppressed because it is too large
Load Diff
91872
word_scores.csv
91872
word_scores.csv
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user