├── .projectile
├── .gitignore
├── resources
└── public
│ ├── img
│ ├── wordchampions-en.png
│ ├── pl.svg
│ └── en.svg
│ ├── index.html
│ └── puzzles
│ └── nkjp.txt
├── package.json
├── src
├── c
│ ├── Makefile
│ ├── hashset.h
│ ├── hashset.c
│ └── generate.c
├── cljs
│ └── gridlock
│ │ ├── core.cljs
│ │ ├── cartesian.cljs
│ │ ├── i18n.cljs
│ │ ├── subs.cljs
│ │ ├── db.cljs
│ │ ├── events.cljs
│ │ └── views.cljs
└── sass
│ └── app.sass
├── shadow-cljs.edn
├── Makefile
├── README.md
├── wordlists
├── nkjp59.txt
└── en59.txt
└── yarn.lock
/.projectile:
--------------------------------------------------------------------------------
1 | -/target
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .shadow-cljs
2 | node_modules
3 | resources/public/css
4 | resources/public/js
--------------------------------------------------------------------------------
/resources/public/img/wordchampions-en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathell/wordchampions/HEAD/resources/public/img/wordchampions-en.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "react": "17.0.1",
4 | "react-dom": "17.0.1",
5 | "shadow-cljs": "^2.16.12"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/c/Makefile:
--------------------------------------------------------------------------------
1 | all: generate
2 |
3 | generate: generate.c hashset.c hashset.h
4 | $(CC) $(CFLAGS) $(LDFLAGS) generate.c hashset.c -o $@
5 |
6 | clean:
7 | rm generate generate.o
8 |
--------------------------------------------------------------------------------
/resources/public/img/pl.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | {:dependencies [[re-frame "1.3.0-rc2"]
2 | [day8.re-frame/http-fx "0.2.4"]]
3 | :source-paths ["src/cljs"]
4 | :dev-http {8000 "resources/public"}
5 | :builds {:app {:target :browser
6 | :output-dir "resources/public/js"
7 | :asset-path "/js"
8 | :modules {:app {:entries [gridlock.core]}}}}}
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | OUT := resources/public
2 |
3 | all: $(OUT)/css/app.css watch
4 | release: $(OUT)/css/app.css $(OUT)/js/app.js
5 |
6 | watch:
7 | shadow-cljs watch app
8 |
9 | $(OUT)/css/app.css: src/sass/app.sass
10 | mkdir -p $(OUT)/css
11 | sassc $< $@
12 |
13 | $(OUT)/js/app.js: src/cljs/gridlock/*.cljs
14 | shadow-cljs release app
15 |
16 | clean:
17 | rm -rf $(OUT)/js $(OUT)/css
18 |
19 | .PHONY: all clean release watch
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Word Champions
2 |
3 | A fun word game!
4 |
5 | ## Building and hacking
6 |
7 | First, do `yarn install` to install shadow-cljs. Then just `make`.
8 |
9 | This will start a dev server on http://localhost:8000, serving the contents of `resources/public`.
10 |
11 | To build in release mode: `make release`. After that, you can just server
12 | `resources/public` with a static server.
13 |
14 | ## Play it
15 |
16 | http://danieljanus.pl/wladcyslow/
17 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/core.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.core
2 | (:require
3 | [gridlock.events :as events]
4 | [gridlock.subs :as subs]
5 | [gridlock.views :as views]
6 | [re-frame.core :refer [dispatch-sync]]
7 | [reagent.dom :as rdom]))
8 |
9 | (defn ^:dev/after-load render-root []
10 | (rdom/render [views/root] (.getElementById js/document "app")))
11 |
12 | (defn init []
13 | (dispatch-sync [:init])
14 | (render-root))
15 |
16 | (js/document.addEventListener "DOMContentLoaded" init)
17 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/cartesian.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.cartesian)
2 |
3 | (defn encode
4 | [[dim & other-dims] [x & xs]]
5 | (when (or (nil? dim) (nil? x))
6 | (throw (js/Error. (str "Dimension mismatch: " dim "," x))))
7 | (when (>= x dim)
8 | (throw (js/Error. (str "Entry out of dimension: " x "," dim))))
9 | (if (and (empty? other-dims) (empty? xs))
10 | x
11 | (+ (* dim (encode other-dims xs)) x)))
12 |
13 | (defn decode
14 | [dims x]
15 | (loop [dims dims x x acc []]
16 | (if (empty? dims)
17 | acc
18 | (let [[dim & other-dims] dims
19 | n (mod x dim)
20 | x (/ (- x n) dim)]
21 | (recur other-dims x (conj acc n))))))
22 |
--------------------------------------------------------------------------------
/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
24 | Loading, please wait…
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/resources/public/img/en.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/i18n.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.i18n)
2 |
3 | (def i18n
4 | {:pl
5 | {:hint "Podpowiedź"
6 | :reset "Resetuj"
7 | :new-game "Nowa gra"
8 | :hello "Witaj!"
9 | :start-game "Zacznij grę"
10 | :how-to-play "Jak grać?"
11 | :feedback "Opinie"
12 | :hooray "Brawo!"
13 | :play-again "Jeszcze raz"
14 | :select-difficulty "Wybierz poziom trudności:"
15 | :easy "Łatwy"
16 | :normal "Średni"
17 | :hard "Trudny"
18 | :loading-dictionaries "Ładuję słowniki"
19 | :written-in-cljs "Napisane w języku ClojureScript"
20 | :source-code "Kod źródłowy"
21 | :time "Czas"
22 | :hints "Podpowiedzi"
23 | :word-champions "Władcy słów"
24 | :game "gra"
25 | :share "Udostępnij"
26 | :share-msg1 "Rozwiązał_m zagadkę w grze Władcy Słów na poziomie "
27 | :share-easy "łatwym"
28 | :share-medium "średnim"
29 | :share-hard "trudnym"
30 | :share-msg2 " w czasie "
31 | :share-msg3 " Sprawdź, czy umiesz szybciej!\n\nMoje słowa: "
32 | :copied-to-clipboard "Skopiowano do schowka"
33 | :not-copied-to-clipboard "Błąd przy kopiowaniu do schowka"}
34 | :en
35 | {:hint "Hint"
36 | :reset "Reset"
37 | :new-game "New game"
38 | :hello "Hello!"
39 | :start-game "Start game"
40 | :how-to-play "How to play"
41 | :feedback "Feedback"
42 | :hooray "Hooray!"
43 | :play-again "Play again"
44 | :select-difficulty "Select difficulty:"
45 | :easy "Easy"
46 | :normal "Medium"
47 | :hard "Hard"
48 | :loading-dictionaries "Loading dictionaries"
49 | :written-in-cljs "Written in ClojureScript"
50 | :source-code "Source code"
51 | :time "Time"
52 | :hints "Hints"
53 | :word-champions "Word Champions"
54 | :game "game"
55 | :share "Share"
56 | :share-msg1 "I solved a Word Champions "
57 | :share-easy "easy"
58 | :share-medium "medium"
59 | :share-hard "hard"
60 | :share-msg2 "-level puzzle in "
61 | :share-msg3 " Try and see if you can beat my time!\n\nMy words: "
62 | :copied-to-clipboard "Copied to clipboard"
63 | :not-copied-to-clipboard "Copy to clipboard failed"}})
64 |
--------------------------------------------------------------------------------
/src/c/hashset.h:
--------------------------------------------------------------------------------
1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 | /*
3 | * Copyright 2012 Couchbase, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | #ifndef HASHSET_H
19 | #define HASHSET_H 1
20 |
21 | #include
22 |
23 | #ifdef __cplusplus
24 | extern "C" {
25 | #endif
26 |
27 | struct hashset_st {
28 | size_t nbits;
29 | size_t mask;
30 |
31 | size_t capacity;
32 | size_t *items;
33 | size_t nitems;
34 | size_t n_deleted_items;
35 | };
36 |
37 | typedef struct hashset_st *hashset_t;
38 |
39 | /* create hashset instance */
40 | hashset_t hashset_create(void);
41 |
42 | /* destroy hashset instance */
43 | void hashset_destroy(hashset_t set);
44 |
45 | size_t hashset_num_items(hashset_t set);
46 |
47 | /* add item into the hashset.
48 | *
49 | * @note 0 and 1 is special values, meaning nil and deleted items. the
50 | * function will return -1 indicating error.
51 | *
52 | * returns zero if the item already in the set and non-zero otherwise
53 | */
54 | int hashset_add(hashset_t set, void *item);
55 |
56 | /* remove item from the hashset
57 | *
58 | * returns non-zero if the item was removed and zero if the item wasn't
59 | * exist
60 | */
61 | int hashset_remove(hashset_t set, void *item);
62 |
63 | /* check if existence of the item
64 | *
65 | * returns non-zero if the item exists and zero otherwise
66 | */
67 | int hashset_is_member(hashset_t set, void *item);
68 |
69 | #ifdef __cplusplus
70 | }
71 | #endif
72 |
73 | #endif
74 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/subs.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.subs
2 | (:require
3 | [gridlock.db :as db :refer [msg]]
4 | [gridlock.i18n :as i18n]
5 | [re-frame.core :refer [reg-sub]]))
6 |
7 | (defn finished?
8 | [{:keys [horiz vert fill]}]
9 | (let [[a b c] horiz]
10 | (= (str (subs a 1 4) (subs b 1 4) (subs c 1 4)) fill)))
11 |
12 | (defn can-place?
13 | [{:keys [compat current-tile dragging]} diagram-number]
14 | (let [source (or dragging current-tile)
15 | acceptable-source (get compat diagram-number)
16 | diagram-source (:diagram-number source)
17 | nine-source (:nine-number source)]
18 | (cond diagram-source (= diagram-source diagram-number)
19 | nine-source (or (= acceptable-source nine-source)
20 | (and (nil? acceptable-source)
21 | (not (contains? (set (vals compat)) nine-source))))
22 | :otherwise false)))
23 |
24 | (defn ->diagram
25 | [db i {:keys [horiz vert fill] :as zag}]
26 | {:diagram-number i
27 | :top (apply str (map first vert))
28 | :bottom (apply str (map last vert))
29 | :left (apply str (map first horiz))
30 | :right (apply str (map last horiz))
31 | :placed fill
32 | :highlighted (can-place? db i)
33 | :finished (finished? zag)})
34 |
35 | (reg-sub
36 | :diagrams
37 | (fn [db _]
38 | (map-indexed (partial ->diagram db) (:zag db))))
39 |
40 | (reg-sub
41 | :nines
42 | (fn [{:keys [words]} _]
43 | (map-indexed (fn [i {:keys [available]}]
44 | {:nine-number i, :letters available})
45 | words)))
46 |
47 | (reg-sub
48 | :can-place?
49 | (fn [db [_ diagram-number]]
50 | (can-place? db diagram-number)))
51 |
52 | (reg-sub
53 | :mode
54 | (fn [db _]
55 | (:mode db)))
56 |
57 | (reg-sub
58 | :current-diagram
59 | (fn [db _]
60 | (:current-diagram db)))
61 |
62 | (reg-sub
63 | :requested-difficulty
64 | (fn [db _]
65 | (count (:problem-numbers db))))
66 |
67 | (reg-sub
68 | :title-bar
69 | (fn [db _]
70 | (if (contains? #{:in-progress :success} (:mode db))
71 | (str (msg db :time)
72 | ": "
73 | (db/format-time (:time db))
74 | " "
75 | (msg db :hints)
76 | ": "
77 | (:hints db))
78 | (str
79 | (msg db :word-champions)
80 | (when (seq (:problem-numbers db))
81 | (str " – "
82 | (msg db :game)
83 | " "
84 | (subs js/window.location.hash 1)))))))
85 |
86 | (reg-sub
87 | :dictionary-selected?
88 | (fn [db [_ dict]]
89 | (= (:dictionary db) dict)))
90 |
91 | (reg-sub
92 | :loaded?
93 | (fn [{:keys [dictionaries language]} _]
94 | (case language
95 | :pl (and (:nkjp dictionaries) (:osps dictionaries) true)
96 | :en (and (:en dictionaries) true))))
97 |
98 | (reg-sub
99 | :current-tile
100 | (fn [db _]
101 | (:current-tile db)))
102 |
103 | (reg-sub
104 | :language
105 | (fn [db _]
106 | (:language db)))
107 |
108 | (reg-sub
109 | :i18n-message
110 | :<- [:language]
111 | (fn [language [_ id]]
112 | (get-in i18n/i18n [language id])))
113 |
114 | (reg-sub
115 | :toast-shown?
116 | (fn [db _]
117 | (:toast-shown? db)))
118 |
119 | (reg-sub
120 | :toast-message
121 | (fn [db _]
122 | (:toast-message db)))
123 |
--------------------------------------------------------------------------------
/src/c/hashset.c:
--------------------------------------------------------------------------------
1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 | /*
3 | * Copyright 2012 Couchbase, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | #include "hashset.h"
19 | #include
20 |
21 | static const unsigned int prime_1 = 73;
22 | static const unsigned int prime_2 = 5009;
23 |
24 | hashset_t hashset_create()
25 | {
26 | hashset_t set = calloc(1, sizeof(struct hashset_st));
27 |
28 | if (set == NULL) {
29 | return NULL;
30 | }
31 | set->nbits = 3;
32 | set->capacity = (size_t)(1 << set->nbits);
33 | set->mask = set->capacity - 1;
34 | set->items = calloc(set->capacity, sizeof(size_t));
35 | if (set->items == NULL) {
36 | hashset_destroy(set);
37 | return NULL;
38 | }
39 | set->nitems = 0;
40 | set->n_deleted_items = 0;
41 | return set;
42 | }
43 |
44 | size_t hashset_num_items(hashset_t set)
45 | {
46 | return set->nitems;
47 | }
48 |
49 | void hashset_destroy(hashset_t set)
50 | {
51 | if (set) {
52 | free(set->items);
53 | }
54 | free(set);
55 | }
56 |
57 | static int hashset_add_member(hashset_t set, void *item)
58 | {
59 | size_t value = (size_t)item;
60 | size_t ii;
61 |
62 | if (value == 0 || value == 1) {
63 | return -1;
64 | }
65 |
66 | ii = set->mask & (prime_1 * value);
67 |
68 | while (set->items[ii] != 0 && set->items[ii] != 1) {
69 | if (set->items[ii] == value) {
70 | return 0;
71 | } else {
72 | /* search free slot */
73 | ii = set->mask & (ii + prime_2);
74 | }
75 | }
76 | set->nitems++;
77 | if (set->items[ii] == 1) {
78 | set->n_deleted_items--;
79 | }
80 | set->items[ii] = value;
81 | return 1;
82 | }
83 |
84 | static void maybe_rehash(hashset_t set)
85 | {
86 | size_t *old_items;
87 | size_t old_capacity, ii;
88 |
89 |
90 | if (set->nitems + set->n_deleted_items >= (double)set->capacity * 0.85) {
91 | old_items = set->items;
92 | old_capacity = set->capacity;
93 | set->nbits++;
94 | set->capacity = (size_t)(1 << set->nbits);
95 | set->mask = set->capacity - 1;
96 | set->items = calloc(set->capacity, sizeof(size_t));
97 | set->nitems = 0;
98 | set->n_deleted_items = 0;
99 | assert(set->items);
100 | for (ii = 0; ii < old_capacity; ii++) {
101 | hashset_add_member(set, (void *)old_items[ii]);
102 | }
103 | free(old_items);
104 | }
105 | }
106 |
107 | int hashset_add(hashset_t set, void *item)
108 | {
109 | int rv = hashset_add_member(set, item);
110 | maybe_rehash(set);
111 | return rv;
112 | }
113 |
114 | int hashset_remove(hashset_t set, void *item)
115 | {
116 | size_t value = (size_t)item;
117 | size_t ii = set->mask & (prime_1 * value);
118 |
119 | while (set->items[ii] != 0) {
120 | if (set->items[ii] == value) {
121 | set->items[ii] = 1;
122 | set->nitems--;
123 | set->n_deleted_items++;
124 | return 1;
125 | } else {
126 | ii = set->mask & (ii + prime_2);
127 | }
128 | }
129 | return 0;
130 | }
131 |
132 | int hashset_is_member(hashset_t set, void *item)
133 | {
134 | size_t value = (size_t)item;
135 | size_t ii = set->mask & (prime_1 * value);
136 |
137 | while (set->items[ii] != 0) {
138 | if (set->items[ii] == value) {
139 | return 1;
140 | } else {
141 | ii = set->mask & (ii + prime_2);
142 | }
143 | }
144 | return 0;
145 | }
146 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/db.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.db
2 | (:require [clojure.string :as string]
3 | [gridlock.cartesian :as cartesian]
4 | [gridlock.i18n :as i18n]))
5 |
6 | (defn msg
7 | [db id]
8 | (get-in i18n/i18n [(:language db) id]))
9 |
10 | (defn substitute-letter [w i c]
11 | (str (subs w 0 i) c (subs w (inc i) (count w))))
12 |
13 | (defn convert-problem [{:keys [word horiz vert]}]
14 | {:word word,
15 | :horiz (mapv rand-nth horiz),
16 | :vert (mapv rand-nth vert),
17 | :fill "........."})
18 |
19 | (defn rand-nth-with-index
20 | "Returns a 2-element vector [random index into given coll,
21 | element under that index]."
22 | [coll]
23 | (let [i (rand-int (count coll))]
24 | [i (nth coll i)]))
25 |
26 | (defn make-problem
27 | [subparts variant]
28 | (let [[middles word h1 h2 h3 v1 v2 v3] (mapv nth subparts variant)
29 | middles (partition 3 middles)
30 | horiz-middles (map #(apply str %) middles)
31 | vert-middles (apply map str middles)
32 | horiz (mapv #(str (first %2) %1 (last %2)) horiz-middles [h1 h2 h3])
33 | vert (mapv #(str (first %2) %1 (last %2)) vert-middles [v1 v2 v3])]
34 | {:word word
35 | :horiz horiz
36 | :vert vert
37 | :fill "........."}))
38 |
39 | (defn split-problem
40 | [problem]
41 | (let [parts (string/split problem #",")
42 | subparts (mapv #(string/split % #";") parts)
43 | dimensions (mapv count subparts)]
44 | {:subparts subparts, :dimensions dimensions}))
45 |
46 | (defn parse-problem
47 | [n-problems [index problem]]
48 | (when problem
49 | (let [{:keys [subparts dimensions]} (split-problem problem)
50 | variant (mapv rand-int dimensions)
51 | all-dimensions (into [n-problems] dimensions)
52 | all-variant (into [index] variant)]
53 | (-> (make-problem subparts variant)
54 | (assoc :problem (cartesian/encode all-dimensions all-variant))))))
55 |
56 | (defn retrieve-problem
57 | [db dict problem-number]
58 | (let [problems (get-in db [:dictionaries dict])
59 | n-problems (count problems)
60 | n (mod problem-number n-problems)
61 | problem (nth problems n)
62 | {:keys [subparts dimensions]} (split-problem problem)
63 | all-dimensions (into [n-problems] dimensions)
64 | variant (next (cartesian/decode all-dimensions problem-number))]
65 | (-> (make-problem subparts variant)
66 | (assoc :problem problem-number))))
67 |
68 | (defn generate-problem
69 | [db dict]
70 | (let [problems (get-in db [:dictionaries dict])
71 | n-problems (count problems)]
72 | (->> problems
73 | rand-nth-with-index
74 | (parse-problem n-problems))))
75 |
76 | (def dictionaries
77 | {:pl #{:osps :nkjp}, :en #{:en}})
78 |
79 | (def dict->lang
80 | (into {}
81 | (for [[k vs] dictionaries v vs]
82 | [v k])))
83 |
84 | (defn problems
85 | [db dict n]
86 | (let [items (if-let [problem-numbers (:problem-numbers db)]
87 | (mapv (partial retrieve-problem db dict) problem-numbers)
88 | (repeatedly n #(generate-problem db dict)))
89 | words (map-indexed (fn [i x] {:diagram-number i, :full (:word x), :available (:word x)})
90 | items)]
91 | {:zag (mapv #(dissoc % :word) items)
92 | :words (vec (shuffle words))
93 | :url (string/join "/"
94 | (into [(name dict)] (map :problem items)))}))
95 |
96 | (defn parse-url [url]
97 | (let [parts (string/split url #"/")]
98 | (when parts
99 | (let [[dict & problems] parts
100 | dict (keyword dict)
101 | language (dict->lang dict)
102 | problems (mapv #(js/parseInt %) problems)]
103 | (when (and language
104 | (every? int? problems)
105 | (contains? #{1 3 5} (count problems)))
106 | {:language language,
107 | :dictionary dict,
108 | :mode :before-start-selected,
109 | :time 0,
110 | :problem-numbers problems})))))
111 |
112 | (defn expected-letters
113 | [{[a b c] :horiz}]
114 | (str (subs a 1 4) (subs b 1 4) (subs c 1 4)))
115 |
116 | (defn success?
117 | ([db]
118 | (reduce #(and %1 %2)
119 | (map (partial success? db)
120 | (range (count (:zag db))))))
121 | ([db i]
122 | (let [problem (get-in db [:zag i])]
123 | (= (expected-letters problem) (:fill problem)))))
124 |
125 | (defn return-letter [db]
126 | (let [{:keys [diagram pos]} (:dragged-letter db)]
127 | (if diagram
128 | (let [iword (get-in db [:compat diagram])
129 | word (get-in db [:words iword :full])
130 | aword (get-in db [:words iword :available])
131 | w (get-in db [:zag diagram :fill])
132 | c (nth w pos)
133 | i (first (filter #(and (= (nth word %) c) (= (nth aword %) "."))
134 | (range 9)))
135 | new-fill (substitute-letter (get-in db [:zag diagram :fill]) pos ".")]
136 | (-> db
137 | (assoc-in [:zag diagram :fill] new-fill)
138 | (update-in [:words iword :available]
139 | #(substitute-letter % i c))
140 | (update-in [:compat diagram]
141 | (if (= new-fill ".........") (constantly nil) identity))
142 | (dissoc :dragged-letter)))
143 | (dissoc db :dragged-letter))))
144 |
145 | (defn leading-zero
146 | [s]
147 | (if (< s 10)
148 | (str "0" s)
149 | (str s)))
150 |
151 | (defn format-time [t]
152 | (str (leading-zero (int (/ t 60))) ":" (leading-zero (mod t 60))))
153 |
154 | (defn share-message [{lang :language, time :time, hints :hints, :as db} url]
155 | (str (msg db :share-msg1)
156 | (msg db (case (-> db :zag count)
157 | 1 :share-easy
158 | 3 :share-medium
159 | :share-hard))
160 | (msg db :share-msg2)
161 | (format-time time)
162 | (cond
163 | (and (= lang :pl) (zero? hints)) ", nie wykorzystując podpowiedzi!"
164 | (and (= lang :pl) (= hints 1)) ", wykorzystując 1 podpowiedź."
165 | (= lang :pl) (str ", wykorzystując " hints " podpowiedzi.")
166 | (and (= lang :en) (zero? hints)) ", not using any hints!"
167 | (and (= lang :en) (= hints 1)) ", using 1 hint."
168 | (= lang :en) (str ", using " hints " hints."))
169 | (msg db :share-msg3)
170 | (string/join ", " (map #(string/upper-case (:full %)) (:words db)))
171 | "\n\n"
172 | url))
173 |
--------------------------------------------------------------------------------
/src/c/generate.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "hashset.h"
9 |
10 | const char pl_letters[] = "ąćęłńóśźż";
11 | const int NUM_LETTERS = 32;
12 | const int ASCII_LETTERS = 23;
13 |
14 | uint64_t (*encode)(const char *, size_t);
15 | const char *(*decode)(uint64_t, size_t);
16 |
17 | uint64_t encode_pl(const char *s, size_t sz) {
18 | uint64_t res = 0;
19 | while (sz) {
20 | uint64_t x;
21 | if (*s >= 'a' && *s <= 'z') {
22 | x = *s - 'a';
23 | if (*s > 'q') x--;
24 | if (*s > 'v') x--;
25 | if (*s > 'x') x--;
26 | s++;
27 | } else {
28 | const uint16_t c = *(const uint16_t *)s;
29 | const uint16_t *l = (const uint16_t *)pl_letters;
30 | x = ASCII_LETTERS;
31 | while (x < NUM_LETTERS && *l != c) l++, x++;
32 | if (x == NUM_LETTERS) return -1;
33 |
34 | s += 2;
35 | }
36 | res = NUM_LETTERS * res + x;
37 | sz--;
38 | }
39 | return res;
40 | }
41 |
42 | uint64_t encode_en(const char *s, size_t sz) {
43 | uint64_t res = 0;
44 | while (sz) {
45 | uint64_t x = *s++ - 'a';
46 | res = NUM_LETTERS * res + x;
47 | sz--;
48 | }
49 | return res;
50 | }
51 |
52 | #define N 20
53 |
54 | const char *decode_pl(uint64_t num, size_t sz) {
55 | static char res[N];
56 | res[N - 1] = 0;
57 | char *s = res + N - 2;
58 | while (sz--) {
59 | int x = num % NUM_LETTERS;
60 | if (x < ASCII_LETTERS) {
61 | *s = x + 'a';
62 | if (x > 15) (*s)++;
63 | if (x > 19) (*s)++;
64 | if (x > 20) (*s)++;
65 | s--;
66 | } else {
67 | const char *u = pl_letters + 2 * (x - ASCII_LETTERS);
68 | *s = *(u + 1);
69 | *(s - 1) = *u;
70 | s -= 2;
71 | }
72 | num /= NUM_LETTERS;
73 | }
74 | return s + 1;
75 | }
76 |
77 | const char *decode_en(uint64_t num, size_t sz) {
78 | static char res[N];
79 | res[N - 1] = 0;
80 | char *s = res + N - 2;
81 | while (sz--) {
82 | int x = num % NUM_LETTERS;
83 | *s-- = x + 'a';
84 | num /= NUM_LETTERS;
85 | }
86 | return s + 1;
87 | }
88 |
89 | int cmp(const void *x, const void *y) {
90 | return *((const char *)x) - *((const char *)y);
91 | }
92 |
93 | uint64_t sortnum(uint64_t num) {
94 | static char arr[N];
95 | char *s = arr;
96 | size_t n = 0;
97 | while (num) {
98 | *s++ = num % NUM_LETTERS;
99 | num /= NUM_LETTERS;
100 | n++;
101 | }
102 | qsort(arr, n, 1, cmp);
103 | s = arr;
104 | while (n--) {
105 | num = num * NUM_LETTERS + *s++;
106 | }
107 | return num;
108 | }
109 |
110 | void unextchar(const char **s) {
111 | unsigned char c = (unsigned char)**s;
112 | if ((c & 0x80) == 0) *s += 1;
113 | else if ((c & 0xE0) == 0xC0) *s += 2;
114 | else if ((c & 0xF0) == 0xE0) *s += 3;
115 | else if ((c & 0xF8) == 0xF0) *s += 4;
116 | }
117 |
118 | size_t ustrlen(const char *s, char terminator) {
119 | size_t len = 0;
120 | while (*s != terminator) {
121 | len++;
122 | unextchar(&s);
123 | }
124 | return len;
125 | }
126 |
127 | void *slurp(const char *filename, size_t *sizeptr) {
128 | struct stat statbuf;
129 | size_t size;
130 | char *buf;
131 | size_t done = 0, todo;
132 | FILE *f;
133 |
134 | if (stat(filename, &statbuf) == -1) {
135 | perror(filename);
136 | exit(1);
137 | }
138 |
139 | size = (size_t)statbuf.st_size;
140 | todo = size;
141 |
142 | buf = (char *)malloc(size + 1);
143 | if (buf == NULL) {
144 | fprintf(stderr, "Out of memory\n");
145 | exit(1);
146 | }
147 |
148 | f = fopen(filename, "rb");
149 | if (f == NULL) {
150 | perror(filename);
151 | exit(1);
152 | }
153 |
154 | while (todo) {
155 | size_t numread = fread(buf + done, 1, todo, f);
156 | if (numread == 0) {
157 | fprintf(stderr, "Error reading %s\n", filename);
158 | exit(1);
159 | }
160 | done += numread;
161 | todo -= numread;
162 | }
163 | buf[size] = 0;
164 |
165 | *sizeptr = size;
166 | return (void *)buf;
167 | }
168 |
169 | void print_base(char *nines, uint64_t w9) {
170 | char *wordstmp = nines;
171 | int found = 0;
172 | while (*wordstmp) {
173 | char *next = strchr(wordstmp, '\n');
174 | if (sortnum(encode(wordstmp, 9)) == w9) {
175 | if (found) putchar(';');
176 | found = 1;
177 | char tmp = *next;
178 | *next = 0;
179 | printf("%s", wordstmp);
180 | *next = tmp;
181 | };
182 | wordstmp = next;
183 | if (wordstmp)
184 | wordstmp++;
185 | }
186 | }
187 |
188 | const char *wputchar(const char *s) {
189 | const char *tmp = s;
190 | unextchar(&tmp);
191 | while (s < tmp) putchar(*s++);
192 | return tmp;
193 | }
194 |
195 | void print_matches(char *words, char *nines, uint64_t w3) {
196 | char *wordstmp = words;
197 | int found = 0;
198 | putchar(',');
199 | while (wordstmp != nines) {
200 | char *next = strchr(wordstmp, '\n');
201 | char *letter = wordstmp;
202 | unextchar((const char **)&letter);
203 | uint64_t w = encode(letter, 3);
204 | if (w == w3) {
205 | if (found) putchar(';');
206 | found = 1;
207 | wputchar(wordstmp);
208 | unextchar((const char **)&letter);
209 | unextchar((const char **)&letter);
210 | unextchar((const char **)&letter);
211 | wputchar(letter);
212 | }
213 | wordstmp = next;
214 | if (wordstmp)
215 | wordstmp++;
216 | }
217 | }
218 |
219 | int main(int argc, char **argv) {
220 | FILE *f;
221 | char s[20], *words, *wordstmp, *nines;
222 | uint64_t w3[30000];
223 | hashset_t h3 = hashset_create();
224 | hashset_t h9 = hashset_create();
225 | size_t i = 0, n = 0, j, k, a = 0, filesize, prevlen;
226 | if (argc < 3) {
227 | fprintf(stderr, "Usage: %s {pl|en} \n", argv[0]);
228 | return 1;
229 | }
230 |
231 | if (strcmp(argv[1], "en") == 0) {
232 | encode = encode_en;
233 | decode = decode_en;
234 | } else {
235 | encode = encode_pl;
236 | decode = decode_pl;
237 | }
238 |
239 | words = (char *)slurp(argv[2], &filesize);
240 |
241 | wordstmp = words;
242 | prevlen = 0;
243 | while (*wordstmp) {
244 | char *next = strchr(wordstmp, '\n');
245 | size_t len = ustrlen(wordstmp, '\n');
246 | if (len == 5) {
247 | uint64_t w;
248 | unextchar((const char **)&wordstmp);
249 | w = encode(wordstmp, 3);
250 | if (!hashset_is_member(h3, (void *)w))
251 | w3[n++] = w;
252 | hashset_add(h3, (void *)w);
253 | } else if (len == 9) {
254 | if (prevlen == 5)
255 | nines = wordstmp;
256 | hashset_add(h9, (void *)sortnum(encode(wordstmp, 9)));
257 | };
258 | prevlen = len;
259 | wordstmp = next;
260 | if (wordstmp)
261 | wordstmp++;
262 | }
263 |
264 | for (i = 0; i < n; i++) {
265 | uint64_t wh1 = w3[i];
266 | for (j = 0; j < n; j++) {
267 | uint64_t wh2 = w3[j];
268 | for (k = 0; k < n; k++) {
269 | uint64_t wh3 = w3[k];
270 | uint64_t
271 | wv1 =
272 | ((wh1 >> 10) << 10) +
273 | ((wh2 >> 10) << 5) +
274 | (wh3 >> 10),
275 | wv2 =
276 | (((wh1 >> 5) & 31) << 10) +
277 | (((wh2 >> 5) & 31) << 5) +
278 | ((wh3 >> 5) & 31),
279 | wv3 =
280 | ((wh1 & 31) << 10) +
281 | ((wh2 & 31) << 5) +
282 | (wh3 & 31),
283 | all = sortnum((wh1 << 30) + (wh2 << 15) + wh3);
284 | if (hashset_is_member(h3, (void *)wv1) &&
285 | hashset_is_member(h3, (void *)wv2) &&
286 | hashset_is_member(h3, (void *)wv3) &&
287 | hashset_is_member(h9, (void *)all))
288 | {
289 | printf("%s", decode(wh1, 3));
290 | printf("%s", decode(wh2, 3));
291 | printf("%s", decode(wh3, 3));
292 | putchar(',');
293 | print_base(nines, all);
294 | print_matches(words, nines, wh1);
295 | print_matches(words, nines, wh2);
296 | print_matches(words, nines, wh3);
297 | print_matches(words, nines, wv1);
298 | print_matches(words, nines, wv2);
299 | print_matches(words, nines, wv3);
300 | putchar('\n');
301 | }
302 | a++;
303 | }
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/src/sass/app.sass:
--------------------------------------------------------------------------------
1 | // https://www.colourlovers.com/palette/44749/Valiant
2 |
3 | $desktop: 960px
4 |
5 | =mobile
6 | @media screen and (max-width: $desktop - 1px)
7 | @content
8 |
9 | =desktop
10 | @media screen and (min-width: $desktop)
11 | @content
12 |
13 | $purple: #7F4B61
14 | $greenish: #A5AC82
15 | $pale: #F5EBB0
16 | $green: #ACB852
17 | $maroon: #4C4028
18 | $white: lighten($pale, 10)
19 | $grey: lighten($maroon, 40)
20 | $pale-green: lighten($green, 20)
21 | $paler-green: lighten($green, 30)
22 | $pale-greenish: lighten($greenish, 20)
23 |
24 | html, body
25 | margin: 0
26 | font-family: Helvetica, Arial, sans-serif
27 |
28 | html
29 | height: 100%
30 |
31 | body, #app
32 | height: 100%
33 | color: $maroon
34 |
35 | a
36 | color: $purple
37 |
38 | h3
39 | font-size: 20px
40 | line-height: 1.25
41 |
42 | h3, p
43 | margin: 0
44 |
45 | h3:not(:last-child), p:not(:last-child)
46 | margin-bottom: 12px
47 |
48 | .is-hidden-mobile
49 | +mobile
50 | display: none
51 |
52 | .root
53 | min-height: 100%
54 | position: relative
55 | display: flex
56 | flex-direction: column
57 |
58 | .title-bar
59 | flex: 0 0 48px
60 | background-color: $purple
61 | color: $white
62 | +desktop
63 | padding-left: 24px
64 | font-size: 24px
65 | line-height: 48px
66 | +mobile
67 | flex: 0 0 30px
68 | padding-left: 12px
69 | font-size: 18px
70 | line-height: 30px
71 |
72 | .main-panel
73 | flex: 1
74 | display: flex
75 | justify-content: center
76 | align-items: center
77 | background-color: $pale
78 | padding: 24px 0
79 | +mobile
80 | padding: 12px 0
81 |
82 | .panel
83 | display: flex
84 | flex-direction: column
85 | text-align: center
86 |
87 | .game
88 | user-select: none
89 | -moz-user-select: none
90 |
91 | .button
92 | display: inline-block
93 | margin: 0 6px
94 | text-decoration: none
95 | background-color: $purple
96 | color: $white
97 | +desktop
98 | height: 48px
99 | font-size: 20px
100 | line-height: 48px
101 | width: 150px
102 | +mobile
103 | height: 32px
104 | font-size: 16px
105 | line-height: 32px
106 | width: 120px
107 | border: none
108 | border-radius: 4px
109 | box-shadow: none
110 | -webkit-appearance: none
111 | &:focus
112 | outline: none
113 | &:hover
114 | background-color: lighten($purple, 10)
115 | cursor: pointer
116 |
117 | $language-icon-size: 50px
118 |
119 | .language-picker
120 | img
121 | width: $language-icon-size
122 | height: $language-icon-size
123 | opacity: 0.4
124 | &:hover
125 | cursor: pointer
126 | &:not(:last-child)
127 | margin-right: 20px
128 | &.selected
129 | border-radius: $language-icon-size / 2
130 | box-shadow: 0 0 10px $purple
131 | opacity: 1
132 |
133 | .welcome
134 | text-align: center
135 | .title
136 | font-size: 72px
137 | line-height: 1.5
138 |
139 | .how-to-play
140 | align-self: start
141 | padding: 0 20px 20px 20px
142 | max-width: 600px
143 | .nines-area
144 | margin-top: 18px
145 | svg
146 | stroke: $grey
147 | display: inline-block
148 | width: 20px
149 | height: 20px
150 | +mobile
151 | width: 16px
152 | height: 16px
153 | button
154 | margin: 0
155 | p
156 | margin: 12px 0
157 | line-height: 1.4
158 | +desktop
159 | font-size: 20px
160 |
161 | $tile-size: 40px
162 | $mobile-tile-size: 24px
163 | $border-size: 1px
164 | $grid-item-padding: 3px
165 | $grid-item-size: $tile-size + ($grid-item-padding) * 2
166 | $letter-size: 3/4 * $tile-size
167 | $mobile-grid-item-size: $mobile-tile-size + ($grid-item-padding) * 2
168 | $mobile-letter-size: 3/4 * $mobile-tile-size
169 | $mobile-small-tile-size: 9px
170 | $mobile-small-grid-item-size: 12px
171 | $mobile-small-letter-size: 9px
172 |
173 | .diagram
174 | display: inline-grid
175 | padding: 8px
176 | grid-template-columns: repeat(5, $grid-item-size)
177 | grid-template-rows: repeat(5, $grid-item-size)
178 | +mobile
179 | grid-template-columns: repeat(5, $mobile-grid-item-size)
180 | grid-template-rows: repeat(5, $mobile-grid-item-size)
181 | grid-gap: $border-size
182 | box-sizing: border-box
183 |
184 | .diagram-small
185 | +mobile
186 | grid-template-columns: repeat(5, $mobile-small-grid-item-size)
187 | grid-template-rows: repeat(5, $mobile-small-grid-item-size)
188 |
189 | .diagram-finished
190 | .diagram-item
191 | text-stroke: 1px white
192 | text-shadow: 0 0 10px white
193 | background: $pale-green
194 | .tile
195 | cursor: default
196 | background: none
197 | border: none
198 |
199 | .diagram-item
200 | cursor: default
201 | background: $white
202 | display: flex
203 | justify-content: center
204 | align-items: center
205 | box-shadow: 0 0 0 $border-size $maroon
206 |
207 | .diagram-highlighted .diagram-item
208 | background: $paler-green
209 |
210 | @mixin highlighted
211 | background: $greenish !important
212 | transition: background 200ms
213 |
214 | .diagram-item-highlighted
215 | @include highlighted
216 |
217 | .diagram-item-corner
218 | visibility: hidden
219 |
220 | .reload
221 | display: flex
222 | justify-content: center
223 | align-items: center
224 | cursor: pointer
225 | svg
226 | display: block
227 | width: $letter-size
228 | height: $letter-size
229 | +mobile
230 | width: $mobile-letter-size
231 | height: $mobile-letter-size
232 | stroke: $grey
233 | &:hover
234 | svg
235 | stroke: $maroon
236 |
237 | .diagram-item-border
238 | font-weight: 700
239 | font-size: $letter-size
240 | text-transform: uppercase
241 | +mobile
242 | font-size: $mobile-letter-size
243 |
244 | .diagram-small .diagram-item-border
245 | +mobile
246 | font-size: $mobile-small-letter-size
247 |
248 | .tile
249 | cursor: pointer
250 | display: inline-block
251 | width: $tile-size
252 | height: $tile-size
253 | line-height: $tile-size
254 | font-size: $letter-size
255 | +mobile
256 | width: $mobile-tile-size
257 | height: $mobile-tile-size
258 | line-height: $mobile-tile-size
259 | font-size: $mobile-letter-size
260 | box-sizing: border-box
261 | background: $pale-greenish
262 | border: 1px solid $greenish
263 | border-radius: 6px
264 | text-align: center
265 | font-weight: 700
266 | text-transform: uppercase
267 |
268 | .diagram-small .tile
269 | +mobile
270 | width: $mobile-small-tile-size
271 | height: $mobile-small-tile-size
272 | line-height: $mobile-small-tile-size
273 | font-size: $mobile-small-letter-size
274 | border-radius: 1px
275 |
276 | .diagram-small .reload
277 | +mobile
278 | visibility: hidden
279 |
280 | .tile-hidden
281 | transform: translateX(-9999px)
282 |
283 | .diagrams-area
284 | margin-bottom: 10px
285 | display: flex
286 | flex-wrap: wrap
287 | justify-content: center
288 |
289 | .diagram-current
290 | order: 5
291 |
292 | .nines-area
293 | margin: 0 auto
294 | padding: 12px
295 | width: 9 * $tile-size + 12px
296 | +mobile
297 | width: 100%
298 | display: inline-block
299 | background: $white
300 | border: 1px solid black
301 | +mobile
302 | border-left: none
303 | border-right: none
304 | padding: 6px 0
305 | .nine
306 | display: flex
307 | align-items: center
308 | margin-bottom: 0
309 | +mobile
310 | width: 9 * $mobile-tile-size
311 | margin: 0 auto
312 | .tile
313 | margin: 0
314 |
315 | .nines-area-highlighted
316 | @include highlighted
317 |
318 | .nine
319 | padding: 5px 5px
320 | height: $tile-size + 5px
321 | +mobile
322 | padding: 2px 2px
323 | height: $mobile-tile-size + 2px
324 | margin-bottom: 10px
325 | text-align: left
326 |
327 | .author
328 | position: absolute
329 | bottom: 0px
330 | left: 6px
331 |
332 | .difficulty
333 | +mobile
334 | padding-bottom: 24px
335 | h2
336 | margin: 0
337 |
338 | .dictionaries
339 |
340 | .dictionary
341 | vertical-align: middle
342 | display: inline-block
343 | border: 1px solid $purple
344 | border-radius: 18px
345 | width: 80%
346 | +desktop
347 | width: 200px
348 | height: 200px
349 | padding: 18px
350 | margin: 18px
351 | +mobile
352 | padding: 12px
353 | margin: 12px
354 | transition: background-color 0.2s
355 | cursor: pointer
356 | &.selected, &:hover
357 | background-color: $purple
358 | color: $white
359 | a
360 | color: $white
361 |
362 | .success
363 | h1
364 | display: block
365 | margin: 0
366 | font-size: 150px
367 | +mobile
368 | font-size: 80px
369 | text-shadow: 0 0 30px $maroon
370 | animation: tilt 2s ease infinite 0s
371 |
372 | .buttons
373 | margin-top: 18px
374 | text-align: center
375 | +mobile
376 | .button
377 | display: inline-block
378 | &:not(:last-child)
379 | margin-bottom: 6px
380 |
381 | .tile-current
382 | transform: scale(1.5,1.5)
383 |
384 | .toast
385 | position: absolute
386 | top: -100px
387 | width: 50%
388 | left: 0
389 | right: 0
390 | margin: 0 auto
391 | height: 50px
392 | background: $purple
393 | color: $white
394 | font-size: 20px
395 | line-height: 1.25
396 | display: grid
397 | place-content: center
398 | transition: top 0.6s
399 | +mobile
400 | width: 90%
401 |
402 | .toast.shown
403 | top: 100px
404 |
405 | @keyframes tilt
406 | 0% { transform: rotate(20deg); }
407 | 25% { transform: rotate(0); }
408 | 50% { transform: rotate(-20deg); }
409 | 75% { transform: rotate(0); }
410 | 100% { transform: rotate(20deg); }
411 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/events.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.events
2 | (:require
3 | [ajax.core :as ajax]
4 | [clojure.string :as string]
5 | [day8.re-frame.http-fx]
6 | [gridlock.db :as db]
7 | [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx]]))
8 |
9 | (reg-event-db
10 | :start-drag
11 | (fn [db [_ dragged-letter]]
12 | (assoc db :dragging dragged-letter)))
13 |
14 | (reg-event-db
15 | :end-drag
16 | (fn [db _]
17 | (assoc db :dragging nil)))
18 |
19 | (reg-event-fx
20 | :fetch-dictionary
21 | (fn [{db :db} [_ dict]]
22 | (if (get-in db [:dictionaries dict])
23 | {}
24 | {:http-xhrio {:method :get
25 | :uri (str "puzzles/" (name dict) ".txt")
26 | :timeout 10000
27 | :response-format (ajax/text-response-format)
28 | :on-success [:fetch-dictionary-success dict]}})))
29 |
30 | (reg-event-db
31 | :fetch-dictionary-success
32 | (fn [db [_ dict-name dict]]
33 | (assoc-in db [:dictionaries dict-name] (string/split dict #"\n"))))
34 |
35 | (defn letter-at
36 | [db {:keys [diagram-number nine-number letter-pos]}]
37 | (cond
38 | diagram-number (get-in db [:zag diagram-number :fill letter-pos])
39 | nine-number (get-in db [:words nine-number :available letter-pos])))
40 |
41 | (defn move-ok?
42 | [db source target]
43 | true)
44 |
45 | (defn remove-from
46 | [db {:keys [diagram-number nine-number letter-pos] :as args}]
47 | (cond
48 | nine-number (update-in db [:words nine-number :available] db/substitute-letter letter-pos ".")
49 | diagram-number (update-in db [:zag diagram-number :fill] db/substitute-letter letter-pos ".")
50 | :otherwise db))
51 |
52 | (defn insert-to-diagram
53 | [db {:keys [diagram-number letter-pos] :as args} letter]
54 | (update-in db [:zag diagram-number :fill] db/substitute-letter letter-pos letter))
55 |
56 | (defn find-place-for-letter
57 | [{:keys [full available]} letter]
58 | (first
59 | (for [letter-number (range (count full))
60 | :when (and (= (.charAt full letter-number) letter)
61 | (= (.charAt available letter-number) "."))]
62 | letter-number)))
63 |
64 | (defn insert-to-nines
65 | [db nine-number letter]
66 | (if-let [letter-pos (find-place-for-letter (get-in db [:words nine-number]) letter)]
67 | (update-in db [:words nine-number :available] db/substitute-letter letter-pos letter)
68 | db))
69 |
70 | (defn update-compat
71 | [db {source-nine :nine-number} {target-diagram :diagram-number}]
72 | (if source-nine
73 | (update db :compat assoc target-diagram source-nine)
74 | db))
75 |
76 | (defn remove-compat-if-needed
77 | [db source-diagram target-nine]
78 | (let [{:keys [full available]} (get-in db [:words target-nine])]
79 | (if (= full available)
80 | (update db :compat dissoc source-diagram)
81 | db)))
82 |
83 | (defn check-success [db]
84 | (if (db/success? db)
85 | (assoc db :mode :success)
86 | db))
87 |
88 | (defn move-to-diagram [db source target]
89 | (let [letter (letter-at db source)]
90 | (if (move-ok? db source target)
91 | (-> db
92 | (remove-from source)
93 | (insert-to-diagram target letter)
94 | (update-compat source target)
95 | (check-success))
96 | db)))
97 |
98 | (reg-event-db
99 | :drop-diagram
100 | (fn [db [_ target]]
101 | (let [source (:dragging db)]
102 | (move-to-diagram db source target))))
103 |
104 | (defn move-to-nines [db source]
105 | (let [source-diagram (:diagram-number source)
106 | target-nine (get-in db [:compat source-diagram])
107 | letter (letter-at db source)]
108 | (if-not source-diagram
109 | db
110 | (-> db
111 | (remove-from source)
112 | (insert-to-nines target-nine letter)
113 | (remove-compat-if-needed source-diagram target-nine)))))
114 |
115 | (defn clean-diagram [db diagram-number]
116 | (if-let [nine-number (get-in db [:compat diagram-number])]
117 | (-> db
118 | (update-in [:words nine-number] #(assoc % :available (:full %)))
119 | (assoc-in [:zag diagram-number :fill] ".........")
120 | (update :compat dissoc diagram-number))
121 | db))
122 |
123 | (reg-event-db
124 | :clean-diagram
125 | (fn [db [_ diagram-number]]
126 | (clean-diagram db diagram-number)))
127 |
128 | (reg-event-db
129 | :drop-nines
130 | (fn [db _]
131 | (move-to-nines db (:dragging db))))
132 |
133 | (defn find-target
134 | [problem letter]
135 | (let [fill (:fill problem)
136 | expected-letters (db/expected-letters problem)]
137 | (first
138 | (for [[i candidate] (map-indexed vector expected-letters)
139 | :when (and (= candidate letter) (= (nth fill i) "."))]
140 | i))))
141 |
142 | (defn all-letters-for-hint [db]
143 | (for [[nine-number nine] (map-indexed vector (:words db))
144 | [letter-pos letter] (map-indexed vector (:available nine))
145 | :when (not= letter ".")]
146 | [{:nine-number nine-number, :letter-pos letter-pos}
147 | {:diagram-number (:diagram-number nine), :letter-pos (find-target (get-in db [:zag (:diagram-number nine)]) letter)}]))
148 |
149 | (defn all-wrong-letters [db]
150 | (for [[diagram-number problem] (map-indexed vector (:zag db))
151 | :let [expected (db/expected-letters problem)
152 | fill (:fill problem)]
153 | letter-pos (range 9)
154 | :when (and (not= (nth fill letter-pos) ".")
155 | (or (not= (nth fill letter-pos) (nth expected letter-pos))
156 | (when-let [word-number (get-in db [:compat diagram-number])]
157 | (not= diagram-number (get-in db [:words word-number :diagram-number])))))]
158 | {:diagram-number diagram-number, :letter-pos letter-pos}))
159 |
160 | (defn apply-hint
161 | [db]
162 | (if-let [wrong (seq (all-wrong-letters db))]
163 | (move-to-nines db (rand-nth wrong))
164 | (let [[source target] (rand-nth (all-letters-for-hint db))]
165 | (move-to-diagram db source target))))
166 |
167 | (reg-event-db
168 | :hint
169 | (fn [db _]
170 | (-> db
171 | apply-hint
172 | (update :hints inc))))
173 |
174 | (reg-event-fx
175 | :fetch-dictionaries
176 | (fn [{db :db} _]
177 | {:dispatch-n (case (:language db)
178 | :pl [[:fetch-dictionary :osps]
179 | [:fetch-dictionary :nkjp]]
180 | :en [[:fetch-dictionary :en]])}))
181 |
182 | (def default-dictionary
183 | {:pl :nkjp, :en :en})
184 |
185 | (reg-event-fx
186 | :init
187 | (fn [_ _]
188 | (let [language (if (= js/window.navigator.language "pl") :pl :en)
189 | url (subs js/window.location.hash 1)]
190 | {:db (or (db/parse-url url)
191 | {:language language
192 | :mode :before-start
193 | :time 0
194 | :dictionary (default-dictionary language)})
195 | :dispatch [:fetch-dictionaries]})))
196 |
197 | (reg-event-db
198 | :select-difficulty
199 | (fn [db _]
200 | (assoc db :mode :difficulty)))
201 |
202 | (reg-fx
203 | :set-url-hash
204 | (fn [hash]
205 | (set! js/window.location.hash hash)))
206 |
207 | (reg-event-fx
208 | :start
209 | (fn [{db :db} [_ n]]
210 | (let [prs (db/problems db (:dictionary db) n)]
211 | (merge (when-not (= (:mode db) :in-progress)
212 | {:dispatch [:tick]})
213 | {:set-url-hash (:url prs)
214 | :db (merge db prs
215 | {:mode :in-progress
216 | :current-diagram 0
217 | :time 0
218 | :hints 0
219 | :compat {}})}))))
220 |
221 | (reg-event-fx
222 | :tick
223 | (fn [{db :db} _]
224 | (if (= (:mode db) :in-progress)
225 | {:db (update db :time inc)
226 | :dispatch-later [{:ms 1000 :dispatch [:tick]}]}
227 | {})))
228 |
229 | (reg-event-db
230 | :reset
231 | (fn [db _]
232 | (assoc db
233 | :words (mapv #(assoc % :available (:full %)) (:words db))
234 | :zag (mapv #(assoc % :fill ".........") (:zag db))
235 | :compat {})))
236 |
237 | (reg-event-fx
238 | :restart
239 | (fn [{db :db} _]
240 | {:set-url-hash ""
241 | :db (assoc db
242 | :mode :before-start
243 | :problem-numbers nil)}))
244 |
245 | (reg-event-db
246 | :go-back
247 | (fn [db _]
248 | (assoc db :mode
249 | (if (seq (:problem-numbers db))
250 | :before-start-selected
251 | :before-start))))
252 |
253 | (reg-fx
254 | :copy-to-clipboard
255 | (fn [{:keys [text on-success on-error]}]
256 | (-> (js/navigator.clipboard.writeText text)
257 | (.then on-success on-error))))
258 |
259 | (reg-event-fx
260 | :share
261 | (fn [{db :db} _]
262 | {:copy-to-clipboard {:text (db/share-message db js/window.location)
263 | :on-success #(dispatch [:toast/show :copied-to-clipboard])
264 | :on-error #(dispatch [:toast/show :not-copied-to-clipboard])}}))
265 |
266 | (reg-event-db
267 | :show-how-to-play
268 | (fn [db _]
269 | (assoc db :mode :how-to-play)))
270 |
271 | (reg-event-db
272 | :set-dictionary
273 | (fn [db [_ dict]]
274 | (assoc db :dictionary dict)))
275 |
276 | (reg-event-fx
277 | :set-language
278 | (fn [{db :db} [_ language]]
279 | {:db (assoc db
280 | :language language
281 | :dictionary (default-dictionary language))
282 | :dispatch [:fetch-dictionaries]}))
283 |
284 | (reg-event-db
285 | :set-current-diagram
286 | (fn [db [_ diagram]]
287 | (assoc db :current-diagram diagram)))
288 |
289 | (reg-event-db
290 | :tap-tile
291 | (fn [db [_ tile-source]]
292 | (if (:diagram-number tile-source)
293 | (move-to-nines db tile-source)
294 | (assoc db :current-tile tile-source))))
295 |
296 | (reg-event-db
297 | :tap-diagram
298 | (fn [db [_ target]]
299 | (let [source (:current-tile db)]
300 | (if (and source (= (:current-diagram db) (:diagram-number target)))
301 | (-> db
302 | (move-to-diagram source target)
303 | (assoc :current-tile nil))
304 | db))))
305 |
306 | (reg-event-fx
307 | :toast/show
308 | (fn [{db :db} [_ message]]
309 | {:db (assoc db
310 | :toast-shown? true
311 | :toast-message message)
312 | :dispatch-later {:ms 4000 :dispatch [:toast/hide]}}))
313 |
314 | (reg-event-db
315 | :toast/hide
316 | (fn [db _]
317 | (assoc db :toast-shown? false)))
318 |
--------------------------------------------------------------------------------
/resources/public/puzzles/nkjp.txt:
--------------------------------------------------------------------------------
1 | drepozinu,uprzednio,as,sa,ms,os,ft;go,js
2 | ktoramasi,amatorski,ar,ba,ba;gć;ka,en;sj,pi,kn
3 | ktorameda,demokrata,ar,ba,ml,os,so,rn
4 | ktoramade,demokrata,ar,ba,rk;żn,en;sj,so,dk;tk
5 | ktoratele,elektorat,ar,ka,jń,os,se,fl;hl;pm;tż
6 | ktorleeat,elektorat,ar,on,ba;tr,os,as,pa
7 | ktoraseri,orkiestra,ar,pa;ta,fe;sa;so,os,sa;se;st;sy,nć;za
8 | ktoorlren,kontroler,ar,wd,aa;ia;td,so,ss,dy;py;ry;we;wo;wy
9 | niotaserz,rozstanie,ał;un,pi,jy,ak;ir,ma;wa,kt;na
10 | nteiarosz,rozstanie,ak;ir,ma;wa,kt;na,ał;un,pi,jy
11 | tlarusacj,lustracja,as,py,ra,sż,kz,pa
12 | adatykrtu,dyktatura,bć;gć;nl;nć;pć;rr;zć,ea,ar,ty,ea,jb;zp
13 | androzawi,darowizna,ba;wa,ga;pa,bć;dd;jć,bk;bn;gż;kć;nz;ts;zz,zu,ge
14 | araferini,rafineria,bk;bn;gż;kć;nz;ts;zz,aa;sa,la,ma,aa;ia;td,ma
15 | aratalusi,australia,bk;bn;gż;kć;nz;ts;zz,se,dć;kć,tś,pa;ta,pć;wć
16 | aranowdzi,darowizna,bk;bn;gż;kć;nz;ts;zz,zu,ge,ba;wa,ga;pa,bć;dd;jć
17 | azaperimn,przemiana,br;kć,oa,ze;zo;zy,ns;nć;zs,cu,ky;me
18 | etoratkle,elektorat,bn,ka,sp,na,se,fl;hl;pm;tż
19 | etorasirk,orkiestra,bn,pa;ta,ma,fe;sa;so,sa;se;st;sy,bi
20 | etokaltre,elektorat,bn,sa,ss,sa,sa;se;st;sy,bć;kj;pk;wć
21 | etotalerk,elektorat,bn,se,na,pr,sa;se;st;sy,pa
22 | etotalkre,elektorat,bn,se,os,sa,sa;se;st;sy,bć;kj;pk;wć
23 | etotarkle,elektorat,bn,sa;se;st;sy,sp,sa,se,ka;wk
24 | iedonoław,odwołanie,ba;ky;mź,hr;pć,sa,zo,st,wa
25 | iedrzakon,nierzadko,ba;ky;mź,kk,ia,ma,sn,uy
26 | iledeaodn,oddalenie,bt,ił,ge;gy;my;wy,wk,śź,ss
27 | ladamagen,magdalena,by,łć,at,fa,js;zk,uy
28 | olewanami,malowanie,bć;kj;pk;wć,as,kl;rę,kl;nk;tr,pa,cć;ln;ts
29 | ramuligen,regulamin,ba,ja,at,di,mć;pc;wk;zw,ga
30 | rzeandkal,kalendarz,bg;kw;oc;oł;pd;pz,ba;wa,sa,tt,uć,we
31 | urasadzki,arkadiusz,bk,oa,sc,da;ma;ra,tt,ro
32 | uratalasi,australia,bk,se,ba;gć;ka,tj,pa;ta,pć;wć
33 | uratalisa,australia,bk,se,pć,pn,pa;ta,zć
34 | eniroszta,rozstanie,cć;ln;ts,gz,sb,jy,ca,pć
35 | orawagówn,równowaga,cz,ua,re;ro;ry,dd;pd,bo;po;py;ta,bo
36 | ytarenang,argentyna,ct;pć,aa;ia;td,ra,wz,aa,ra
37 | ytalekndi,delikatny,ct;pć,mo,ie,ty,wy,jś;jż
38 | ytatarudk,dyktatura,ct;pć,sa;se;st;sy,ba;da,tł,so,ja;ma
39 | zaridekon,nierzadko,ca;sy,lr;wo,ia,di,rm,aa;ia;td
40 | zecileena,zalecenie,ch;rz,bt,st,dń,cy,on
41 | anirensta,starannie,da;de;jk;ta;to;zm,aa;ia;td,uć;wć,mz,aa,fł
42 | anirasent,starannie,da;de;jk;ta;to;zm,pa;ta,ra,dk;mk,za;zy,la
43 | aregatist,strategia,dk;mk,aa,la,ma,pa;ta,go;no
44 | arekonowi,rokowanie,dk;mk,ia,łć,jś;zn,ka,cć;ln;ts
45 | arekorist,orkiestra,dk;mk,so,la,jś;jż,gz,ve
46 | arebożeni,obrażenie,dk;mk,ze,cć;ln;ts,kl,ft;go,rm
47 | arenanist,starannie,dk;mk,za;zy,la,da;de;jk;ta;to;zm,pa;ta,ra
48 | awarozind,darowizna,dć;kł,ga;pa,wa,ma,ia,ja
49 | awakarini,kawiarnia,dć;kł,sb,la,jś;jż,as,ma
50 | awarakini,kawiarnia,dć;kł,tt,la,ma,as,jś;jż
51 | ietoraskr,orkiestra,da,cz,ia,kk,na,sa;se;st;sy
52 | olawanemi,malowanie,dr;pk,as,rs,rr,pa,da;de;jk;ta;to;zm
53 | owórawagn,równowaga,dd;pd,bo;po;py;ta,bo,cz,ua,re;ro;ry
54 | owówaragn,równowaga,dd;pd,ga;tz,bo,kl;nk;tr,ua,gy
55 | rugalemin,regulamin,di,mć;pc;wk;zw,ga,ba,ja,at
56 | uszrakadi,arkadiusz,da;ma;ra,tt,ro,bk,oa,sc
57 | uszstakar,staruszka,da;ma;ra,uć;wć,sb,ri,uć;wć,ca;sy
58 | ziawanesk,wskazanie,dd;dć;dł,as,da,sd,pt,ha;ja
59 | ziaiedeln,niedziela,dd;dć;dł,ba;ky;mź,cy,dń,we,ra;ry;ły
60 | zieelncea,zalecenie,dń,cy,on,ch;rz,bt,st
61 | zieilkeks,kieliszek,dń,ka,tt,dń,ka,tt
62 | zieratosn,rozstanie,dń,ka,sa,wk,pt,li
63 | zielażane,zażalenie,dń,pa,jk;pl;rk,sk,mo;so,lć
64 | zieieladn,niedziela,dń,we,ra;ry;ły,dd;dć;dł,ba;ky;mź,cy
65 | zikadoren,nierzadko,di,rm,aa;ia;td,ca;sy,lr;wo,ia
66 | kratasomi,amatorski,en;sj,pi,kn,ar,ba,ba;gć;ka
67 | kratadome,demokrata,en;sj,so,dk;tk,ar,ba,rk;żn
68 | erikonazd,nierzadko,fe;sa;so,ia,ja,po,ga;pa,wa
69 | erikonkwi,kierownik,fe;sa;so,ia,tć,li;lo,ka,la
70 | eriratosk,orkiestra,fe;sa;so,ka,bi,pn,pa;ta,na
71 | eritanasn,starannie,fe;sa;so,sy,jo;jy,ml,pa;ta,wa;wy
72 | eritarosk,orkiestra,fe;sa;so,sa;se;st;sy,bi,bn,pa;ta,ma
73 | ilanetaku,aktualnie,fr,aa,jb;zp,fł,mo,tś
74 | inalekatu,aktualnie,fł,mo,tś,fr,aa,jb;zp
75 | inazepyta,zapytanie,fł,st,ct;pć,fk,aa,nd;zs;zł;łć
76 | izynetapa,zapytanie,fk,aa,nd;zs;zł;łć,fł,st,ct;pć
77 | izyewnlek,niezwykle,fk,pe;po;py,mo,we,sd,ra
78 | lagamedan,magdalena,fa,js;zk,uy,by,łć,at
79 | oteratelk,elektorat,fl;hl;pm;tż,ka,ba,ka;wk,se,sa
80 | otetalerk,elektorat,fl;hl;pm;tż,se,na,fl;hl;pm;tż,sa;se;st;sy,ba
81 | otetarelk,elektorat,fl;hl;pm;tż,sa;se;st;sy,ba,fl;hl;pm;tż,se,na
82 | otenanowi,notowanie,fl;hl;pm;tż,za;zy,łć,hr;pć,sa,cć;ln;ts
83 | dzionawar,darowizna,ge,pd,ga;tz,wa,uć,ma;wa
84 | nieotowan,notowanie,gw;śg,mr;pk,as,zu,wć,la
85 | odnwroiet,odwrotnie,ge;gy;my;wy,zt,da,łć,as,ca
86 | oniłotawk,kotłownia,gć,bo;zo;zy,da;ła,wć,zu,na
87 | oniwoneta,notowanie,gć,ia,ml,rr,ca,fł
88 | oniłodawe,odwołanie,gć,me;my,nt;pł;wl,wć,zu,lr;wo
89 | onibieact,obietnica,gć,og;uc;zg,fo,rk,mh;zz,da
90 | onipolawe,polowanie,gć,oe,nt;pł;wl,kć,zu,bt
91 | racajegen,generacja,gz;pa,nm,at,pa,nm,oa;sa
92 | rosywipie,piersiowy,gz,cl;rn;żć,uc;św,ga,łć,om
93 | rosakitre,orkiestra,gz,jś;jż,ss,ka,my,om
94 | rozarygen,rozegrany,ga;pa,mś;pż;zs,at,pa,ka;wk,sa
95 | rypowisie,piersiowy,ga,łć,om,gz,cl;rn;żć,uc;św
96 | uzisadkra,arkadiusz,gk,oa,en;sj,ri,ca;sy,wć
97 | waropanic,pracownia,ga;tz,kć,mh;zz,ia,ns;nć;zs,gz;pa
98 | ononitawe,notowanie,hr;pć,aa,nt;pł;wl,pd,żo,fl;hl;pm;tż
99 | onotaweni,notowanie,hr;pć,sa,cć;ln;ts,fl;hl;pm;tż,za;zy,łć
100 | ononiwate,notowanie,hr;pć,żo,zm,pd,aa,rr
101 | konortrle,kontroler,ia,pa,on,so,wd,ak;ir
102 | wonapirac,pracownia,ia,ns;nć;zs,gz;pa,ga;tz,kć,mh;zz
103 | akiwanari,kawiarnia,jś;jż,as,ma,dć;kł,sb,la
104 | akirosert,orkiestra,jś;jż,gz,ve,dk;mk,so,la
105 | akowoneri,rokowanie,jś;zn,ia,fe;sa;so,nt;pł;wl,so,gć
106 | akoroweni,rokowanie,jś;zn,ka,cć;ln;ts,dk;mk,ia,łć
107 | akonoweri,rokowanie,jś;zn,zu,fe;sa;so,jk;pl;rk,so,łć
108 | aneponawi,panowanie,jk;pl;rk,oa,bć;dd;jć,nd;zs;zł;łć,zu,cć;ln;ts
109 | aneponiwa,panowanie,jk;pl;rk,oa,kć,ns;nć;zs,zu,st
110 | anekorowi,rokowanie,jk;pl;rk,so,łć,jś;zn,zu,fe;sa;so
111 | erznotisa,rozstanie,jy,ca,pć,cć;ln;ts,gz,sb
112 | erzronaga,rozegrana,jy,ft;go,bż,tz,da;di;do;wi,uć
113 | erzkonida,nierzadko,jy,ia,wć,pn,ba;ua;śa,uć
114 | ezuminied,zdumienie,js,ga,ba;ky;mź,rs,dń,ra
115 | ulitenaka,aktualnie,ja,aa,nz;zz,tj,mo,fł
116 | ulitasara,australia,ja,pi,bk;bn;gż;kć;nz;ts;zz,tj,am,pć
117 | aberoneżi,obrażenie,kl,ft;go,rm,dk;mk,ze,cć;ln;ts
118 | amyniwono,anonimowy,kk,żo,hr;pć,kn,ga,żt
119 | anonitowe,notowanie,kn,aa,rr,kn,żo,fl;hl;pm;tż
120 | anominywo,anonimowy,kn,ga,żt,kk,żo,hr;pć
121 | anoniwote,notowanie,kn,żo,fl;hl;pm;tż,kn,aa,rr
122 | artslamow,malarstwo,ka;ma;na;wa;wo,im,ua,po,up,sa
123 | ciuianerk,ukrainiec,kk,mo;so,na,uc;śk,ma;wa,pt
124 | ioserktar,orkiestra,kk,na,sa;se;st;sy,da,cz,ia
125 | iosamktar,amatorski,kk,ra,sa;se;st;sy,wr,rn,ia
126 | iosamttan,natomiast,kk,to,sy,wr,rn,uy
127 | ontwiaeon,notowanie,ko,kt;śt,la,rr,ał;un,sy
128 | opawonile,polowanie,kć,ia,bt,łć,oe,jk;pl;rk
129 | opanowile,polowanie,kć,zu,bt,gć,oe,nt;pł;wl
130 | orekonawi,rokowanie,ka;wk,ia,bć;dd;jć,ll;pz,ka,cć;ln;ts
131 | oretaletk,elektorat,ka;wk,se,sa,fl;hl;pm;tż,ka,ba
132 | owalameni,malowanie,kl;nk;tr,pa,cć;ln;ts,bć;kj;pk;wć,as,kl;rę
133 | owawagórn,równowaga,kl;nk;tr,ua,gy,dd;pd,ga;tz,bo
134 | ratokrsie,orkiestra,ka,my,om,gz,jś;jż,ss
135 | wiaianark,kawiarnia,kt;śt,mo;so,ja;ma,kt;śt,ma;wa,ha;ja
136 | wiaiarank,kawiarnia,kt;śt,ma;wa,ha;ja,kt;śt,mo;so,ja;ma
137 | atalekinu,aktualnie,lć,mo,ms,pć;wć,aa,jb;zp
138 | ekkrowini,kierownik,li;lo,ka,la,fe;sa;so,ia,tć
139 | okawoneri,rokowanie,ll;pz,ia,fe;sa;so,rr,so,da;de;jk;ta;to;zm
140 | okaroweni,rokowanie,ll;pz,ka,cć;ln;ts,ka;wk,ia,bć;dd;jć
141 | ustszakar,staruszka,lr;pe;py,wk,sb,ri,wk,sa;se;st;sy
142 | afirenari,rafineria,ma,aa;ia;td,ma,bk;bn;gż;kć;nz;ts;zz,aa;sa,la
143 | agirasett,strategia,ma,pa;ta,go;no,dk;mk,aa,la
144 | alewanegi,ewangelia,mć;pc;wk;zw,as,la,nt;pł;wl,fa,cć;ln;ts
145 | ariwanaki,kawiarnia,ma,as,jś;jż,dć;kł,tt,la
146 | ariwonazd,darowizna,ma,ia,ja,dć;kł,ga;pa,wa
147 | arizosent,rozstanie,ma,sa,ra,rm,ft;go,la
148 | arsnetina,starannie,mz,aa,fł,da;de;jk;ta;to;zm,aa;ia;td,uć;wć
149 | arytaletn,teatralny,mś;pż;zs,se,li,zm,ka,ty
150 | etarasinn,starannie,ml,pa;ta,wa;wy,fe;sa;so,sy,jo;jy
151 | ianakiraw,kawiarnia,mo;so,jś;jż,bo;po;py;ta,ma;wa,nz;zz,żo
152 | iaremocen,ceremonia,ma;wa,dn,oa;sa,mz;nh;no;we,js;zk,ft;go
153 | iarakaniw,kawiarnia,ma;wa,nz;zz,żo,mo;so,jś;jż,bo;po;py;ta
154 | iecameron,ceremonia,mz;nh;no;we,js;zk,ft;go,ma;wa,dn,oa;sa
155 | irkezodan,nierzadko,ma,sn,uy,ba;ky;mź,kk,ia
156 | okrrloten,kontroler,my,up,aa,pa,sp,ft;go
157 | otowaneni,notowanie,mr;pk,as,cć;ln;ts,rr,sy,gć
158 | ylipisana,sypialnia,mć,sa,kł,sć,aa;ga,pć
159 | apawoneni,panowanie,nd;zs;zł;łć,ia,cć;ln;ts,nt;pł;wl,oa,da;de;jk;ta;to;zm
160 | apanoweni,panowanie,nd;zs;zł;łć,zu,cć;ln;ts,jk;pl;rk,oa,bć;dd;jć
161 | apizemarn,przemiana,ns;nć;zs,cu,ky;me,br;kć,oa,ze;zo;zy
162 | apiwonena,panowanie,ns;nć;zs,ia,st,nt;pł;wl,oa,fł
163 | apinowena,panowanie,ns;nć;zs,zu,st,jk;pl;rk,oa,kć
164 | awelageni,ewangelia,nt;pł;wl,fa,cć;ln;ts,mć;pc;wk;zw,as,la
165 | aweponani,panowanie,nt;pł;wl,oa,da;de;jk;ta;to;zm,nd;zs;zł;łć,ia,cć;ln;ts
166 | aweponina,panowanie,nt;pł;wl,oa,fł,ns;nć;zs,ia,st
167 | awelamoni,malowanie,nt;pł;wl,pa,gć,sn;wr,as,rs
168 | awekoroni,rokowanie,nt;pł;wl,so,gć,jś;zn,ia,fe;sa;so
169 | awydaniłk,wykładnia,nk,uy,pa,ro,gt,ra
170 | erktalote,elektorat,na,se,fl;hl;pm;tż,bn,ka,sp
171 | dpironezu,uprzednio,os,ft;go,js,as,sa,ms
172 | kretlaoet,elektorat,os,as,pa,ar,on,ba;tr
173 | kretadoma,demokrata,os,so,rn,ar,ba,ml
174 | kretalote,elektorat,os,se,fl;hl;pm;tż,ar,ka,jń
175 | kretarosi,orkiestra,os,sa;se;st;sy,nć;za,ar,pa;ta,fe;sa;so
176 | poniwaean,panowanie,oa,kć,ss,uc;św,kl;nk;tr,za;zy
177 | sietanarn,starannie,om,sy,ky;me,uć;wć,ma;wa,cy;sy
178 | alitenaku,aktualnie,pć;wć,aa,jb;zp,lć,mo,ms
179 | alitasura,australia,pć;wć,pi,bk,tś,am,pć
180 | asmrlotaw,malarstwo,po,up,sa,ka;ma;na;wa;wo,im,ua
181 | ekarozind,nierzadko,po,ga;pa,wa,fe;sa;so,ia,ja
182 | ekarowoni,rokowanie,po,ka,gć,pn,ia,bć;dd;jć
183 | ekirodzna,nierzadko,pn,ba;ua;śa,uć,jy,ia,wć
184 | ekirosart,orkiestra,pn,gz,ka;ma;na;wa;wo,tz,so,la
185 | ekirostra,orkiestra,pn,gz,sż,ve,so,pć
186 | ekirowona,rokowanie,pn,ka,pd,pn,ia,kć
187 | ekirasort,orkiestra,pn,pa;ta,pa,pn,sb,la
188 | erożebina,obrażenie,pn,ay,fł,rm,aa;ia;td,rk
189 | erokonawi,rokowanie,pn,ia,bć;dd;jć,po,ka,gć
190 | erokoniwa,rokowanie,pn,ia,kć,pn,ka,pd
191 | erorasitk,orkiestra,pn,pa;ta,na,fe;sa;so,ka,bi
192 | erokarist,orkiestra,pn,sb,la,pn,pa;ta,pa
193 | erotaletk,elektorat,pn,se,sa,pr,ka,pa
194 | eteratolk,elektorat,pr,ka,pa,pn,se,sa
195 | etetarolk,elektorat,pr,sa;se;st;sy,pa,bn,se,na
196 | iotskrare,orkiestra,pr,ia,dk;mk,pć,my,ss
197 | isaokrtre,orkiestra,pć,my,ss,pr,ia,dk;mk
198 | oliwanema,malowanie,ps,as,tt,rr,pa,fł
199 | onanitowe,notowanie,pd,aa,rr,hr;pć,żo,zm
200 | onaniwote,notowanie,pd,żo,fl;hl;pm;tż,hr;pć,aa,nt;pł;wl
201 | ortkleron,kontroler,pa,sp,ft;go,my,up,aa
202 | ragorezyn,rozegrany,pa,ka;wk,sa,ga;pa,mś;pż;zs,at
203 | ragajecen,generacja,pa,nm,oa;sa,gz;pa,nm,at
204 | ragadostr,starogard,pa,rm,oo;oy,pa;ta,no,aa
205 | rasadtgor,starogard,pa;ta,no,aa,pa,rm,oo;oy
206 | utirasala,australia,pn,pa;ta,zć,bk,se,pć
207 | adiwałynk,wykładnia,ro,gt,ra,nk,uy,pa
208 | azeronist,rozstanie,rm,ft;go,la,ma,sa,ra
209 | emizieund,zdumienie,rs,dń,ra,js,ga,ba;ky;mź
210 | eżirenoba,obrażenie,rm,aa;ia;td,rk,pn,ay,fł
211 | obaniciet,obietnica,rk,mh;zz,da,gć,og;uc;zg,fo
212 | oweniotan,notowanie,rr,ał;un,sy,ko,kt;śt,la
213 | owenotina,notowanie,rr,ca,fł,gć,ia,ml
214 | owelamani,malowanie,rr,pa,da;de;jk;ta;to;zm,dr;pk,as,rs
215 | owelamina,malowanie,rr,pa,fł,ps,as,tt
216 | owekorani,rokowanie,rr,so,da;de;jk;ta;to;zm,ll;pz,ia,fe;sa;so
217 | owetanoni,notowanie,rr,sy,gć,mr;pk,as,cć;ln;ts
218 | uskzarida,arkadiusz,ri,ca;sy,wć,gk,oa,en;sj
219 | uskstazar,staruszka,ri,uć;wć,ca;sy,da;ma;ra,uć;wć,sb
220 | uskszatar,staruszka,ri,wk,sa;se;st;sy,lr;pe;py,wk,sb
221 | ynekonawi,wykonanie,rk;sk,ia,bć;dd;jć,wz,zu,cć;ln;ts
222 | alowanemi,malowanie,sn;wr,as,rs,nt;pł;wl,pa,gć
223 | eandzilic,dzielnica,ss,ge,ua,we,kć,mh;zz
224 | ekttarole,elektorat,sa,sa;se;st;sy,bć;kj;pk;wć,bn,sa,ss
225 | etktalore,elektorat,sa,se,ka;wk,bn,sa;se;st;sy,sp
226 | etktarole,elektorat,sa,sa;se;st;sy,bć;kj;pk;wć,bn,se,os
227 | kortreoln,kontroler,so,ss,dy;py;ry;we;wo;wy,ar,wd,aa;ia;td
228 | kororlnte,kontroler,so,wd,ak;ir,ia,pa,on
229 | talakunie,aktualnie,se,jb;zp,gw;śg,sy,jś;jż,bs
230 | tanakilue,aktualnie,sy,jś;jż,bs,se,jb;zp,gw;śg
231 | tanowipie,powitanie,sy,łć,uc;św,sa,bć;dd;jć,gw;śg
232 | topawinie,powitanie,sa,bć;dd;jć,gw;śg,sy,łć,uc;św
233 | tralucasj,lustracja,sż,kz,pa,as,py,ra
234 | ypalinisa,sypialnia,sć,aa;ga,pć,mć,sa,kł
235 | zlaianeże,zażalenie,sk,mo;so,lć,dń,pa,jk;pl;rk
236 | zweiasank,wskazanie,sd,pt,ha;ja,dd;dć;dł,as,da
237 | atrdytaku,dyktatura,ty,ea,jb;zp,bć;gć;nl;nć;pć;rr;zć,ea,ar
238 | atularisa,australia,tś,am,pć,pć;wć,pi,bk
239 | atulasari,australia,tś,bk;ka,ma,zć,sa;se;st;sy,dć;kć
240 | aturasali,australia,tś,pa;ta,pć;wć,bk;bn;gż;kć;nz;ts;zz,se,dć;kć
241 | erarogzna,rozegrana,tz,da;di;do;wi,uć,jy,ft;go,bż
242 | erakorist,orkiestra,tz,so,la,pn,gz,ka;ma;na;wa;wo
243 | rakznaedl,kalendarz,tt,uć,we,bg;kw;oc;oł;pd;pz,ba;wa,sa
244 | utalarisa,australia,tj,am,pć,ja,pi,bk;bn;gż;kć;nz;ts;zz
245 | utalekina,aktualnie,tj,mo,fł,ja,aa,nz;zz
246 | utarasali,australia,tj,pa;ta,pć;wć,bk,se,ba;gć;ka
247 | ylkwarome,reklamowy,to,ga;tz,dk;tk,żt,pa,os
248 | ylntedaki,delikatny,ty,wy,jś;jż,ct;pć,mo,ie
249 | ytutadark,dyktatura,tł,so,ja;ma,ct;pć,sa;se;st;sy,ba;da
250 | cieiarunk,ukrainiec,uc;śk,ma;wa,pt,kk,mo;so,na
251 | mieolawan,malowanie,uć;ść,dr;pk,as,ua,fr,ss
252 | mowilaean,malowanie,ua,fr,ss,uć;ść,dr;pk,as
253 | pieowanan,panowanie,uc;św,kl;nk;tr,za;zy,oa,kć,ss
254 | staiarenn,starannie,uć;wć,ma;wa,cy;sy,om,sy,ky;me
255 | ertkorisa,orkiestra,ve,so,pć,pn,gz,sż
256 | dowznaiar,darowizna,wa,uć,ma;wa,ge,pd,ga;tz
257 | edlazinic,dzielnica,we,kć,mh;zz,ss,ge,ua
258 | iatomaskr,amatorski,wr,rn,ia,kk,ra,sa;se;st;sy
259 | iatomastn,natomiast,wr,rn,uy,kk,to,sy
260 | idoledean,oddalenie,wk,śź,ss,bt,ił,ge;gy;my;wy
261 | ielzweynk,niezwykle,we,sd,ra,fk,pe;po;py,mo
262 | oławonide,odwołanie,wć,ia,lr;wo,łć,me;my,jk;pl;rk
263 | oławonitk,kotłownia,wć,ia,na,łć,bo;zo;zy,ha;ja
264 | ołanowide,odwołanie,wć,zu,lr;wo,gć,me;my,nt;pł;wl
265 | ołanowitk,kotłownia,wć,zu,na,gć,bo;zo;zy,da;ła
266 | ykanoweni,wykonanie,wz,zu,cć;ln;ts,rk;sk,ia,bć;dd;jć
267 | yratenang,argentyna,wz,aa,ra,ct;pć,aa;ia;td,ra
268 | yrarodont,ordynator,wz,ba;ua;śa,ko,wk,ft;go,no
269 | yroronadt,ordynator,wk,ft;go,no,wz,ba;ua;śa,ko
270 | zroiasetn,rozstanie,wk,pt,li,dń,ka,sa
271 | alatarusi,australia,zć,sa;se;st;sy,dć;kć,tś,bk;ka,ma
272 | ateratyln,teatralny,zm,ka,ty,mś;pż;zs,se,li
273 | iołenadow,odwołanie,zo,st,wa,ba;ky;mź,hr;pć,sa
274 | nowitaeon,notowanie,zu,wć,la,gw;śg,mr;pk,as
275 | owidrenot,odwrotnie,łć,as,ca,ge;gy;my;wy,zt,da
276 | owiłotank,kotłownia,łć,bo;zo;zy,ha;ja,wć,ia,na
277 | owiłodane,odwołanie,łć,me;my,jk;pl;rk,wć,ia,lr;wo
278 | owipolane,polowanie,łć,oe,jk;pl;rk,kć,ia,bt
279 | ywolamkre,reklamowy,żt,pa,os,to,ga;tz,dk;tk
280 |
--------------------------------------------------------------------------------
/src/cljs/gridlock/views.cljs:
--------------------------------------------------------------------------------
1 | (ns gridlock.views
2 | (:require
3 | [clojure.string :as string]
4 | [re-frame.core :as rf :refer [dispatch]]
5 | [reagent.core :as r]))
6 |
7 | (def % (aget "dataTransfer") (.setData "text/plain" c))
27 | (dispatch [:start-drag source])
28 | (reset! hide? true))
29 | :on-drag-end #(do (dispatch [:end-drag])
30 | (reset! hide? false))
31 | :on-touch-start #(dispatch [:tap-tile source])
32 | :class (when @hide? "tile-hidden")}
33 | (when (= source (
73 | {:class (cond corner? "diagram-item-corner"
74 | border "diagram-item-border")}
75 | (and in-area? (@highlighted-fields letter-pos)) (r/merge-props {:class "diagram-item-highlighted"})
76 | droppable? (assoc :on-drag-enter #(swap! highlighted-fields conj letter-pos)
77 | :on-drag-leave #(swap! highlighted-fields disj letter-pos)
78 | :on-drag-over #(do (.preventDefault %) (.stopPropagation %))
79 | :on-drop #(do (.preventDefault %) (swap! highlighted-fields empty) (dispatch [:drop-diagram {:diagram-number diagram-number, :letter-pos letter-pos}]))
80 | :on-touch-start #(dispatch [:tap-diagram {:diagram-number diagram-number, :letter-pos letter-pos}])))
81 | (cond corner? nil
82 | border (get-in desc [border border-pos])
83 | :else (when (and letter (not placable?))
84 | [tile {:diagram-number diagram-number, :letter-pos letter-pos} letter (not finished)]))]))))])
85 |
86 | (defn nine [{:keys [nine-number letters]}]
87 | (into
88 | [:div.nine]
89 | (for [[i letter] (map-indexed vector letters) :when (not= letter \.)]
90 | [tile {:nine-number nine-number, :letter-pos i} letter true])))
91 |
92 | (defn nines-area []
93 | (r/with-let [highlighted (r/atom 0)] ; integer, not boolean,
94 | [:div.nines-area
95 | {:on-drag-enter #(swap! highlighted inc)
96 | :on-drag-leave #(swap! highlighted dec)
97 | :on-drag-over #(do (.preventDefault %) (.stopPropagation %))
98 | :on-drop #(do (.preventDefault %) (reset! highlighted 0) (dispatch [:drop-nines]))
99 | :class (when (pos? @highlighted) "nines-area-highlighted")}
100 | (for [word (