diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index b6742a0..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-SlickDwarfFortress
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43e..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index e7bedf3..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index ec1e3be..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index ca94a49..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
deleted file mode 100644
index e96534f..0000000
--- a/.idea/uiDesigner.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index ed85699..0000000
--- a/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- SlickDwarfFortressNXT
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/ASSIGNMENT.md b/ASSIGNMENT.md
new file mode 100644
index 0000000..3bb54b3
--- /dev/null
+++ b/ASSIGNMENT.md
@@ -0,0 +1,271 @@
+[[_TOC_]]
+
+# Implementing `jq` in Haskell
+
+`jq` [(stedolan.github.io/jq)](https://stedolan.github.io/jq/) is a JSON processor.
+It's built in the spirit of Unix: doing one thing, but doing it well.
+Think of `awk`, `sed` or `grep`, but for JSON.
+And we're going to build its clone in Haskell!
+
+In this text, we provide you with a description of what we expect you to implement.
+**Please read it fully and carefully.**
+The assignment is divided into two parts: a basic part and an advanced part. To get a passing grade for the project, you only have to implement the basic part.
+Implementing the advanced part correctly will lead to a higher grade.
+However, you will only score points for the advanced part if your basic part is of acceptable quality, more details on that below.
+
+This is an *individual project*, which means you should not collaborate directly with other students.
+However, you are allowed to discuss the assignment with other students and ask general questions on TU Delft Answers.
+**Under no circumstances should you ever look at complete or partial solutions by another student, or show (part of) your code to another student.**
+See [www.tudelft.nl/en/student/legal-position/fraud-plagiarism/](https://www.tudelft.nl/en/student/legal-position/fraud-plagiarism/) for the general TU Delft policy regarding fraud.
+
+It is expected that completing the project will take you approximately 30-40 hours.
+When you have finished the project, you should hand in your final solution via Weblab before **Sunday, 23rd of April, 23:59**.
+Detailed instructions for submitting your solution will appear on Weblab.
+
+## Introducing `jq`
+
+First let's see what `jq` is all about.
+
+### Case study: counting meteorites
+You will find it in the [`JQ-CASE-STUDY.md`](./JQ-CASE-STUDY.md)
+
+### Documentation and more
+There's a [tutorial](https://stedolan.github.io/jq/tutorial/), which introduces some of the basic features of the tool.
+Then there's official [documentation](https://stedolan.github.io/jq/manual).
+And finally, you can play with `jq` in your browser on [jqplay.org](https://jqplay.org/).
+
+> **NOTE** : for some inputs that contain escaped characters,
+`jq` and `jqplay` can give different results, this has to do with escaping backslashes in terminal or powershell.
+
+## Task description
+
+You're going to implement a clone of `jq` in Haskell.
+However, it's a big and mature project, so we have to trim it down to be feasible to implement in 30-40 hours.
+Below you'll find a list of requirements for your implementation.
+Note that many of the descriptions of the features you have to implement are rather brief. In those cases it is part of the assignment that you pin down the exact semantics of jq yourself, either by consulting the documentation linked above or testing examples against the original implementation.
+
+For full formal definition of JSON take a look at:
+ * The [wiki](https://en.wikipedia.org/wiki/JSON)
+ * The [rfc](https://tools.ietf.org/rfc/rfc8259.txt)
+
+### Project structure
+
+To get you started, this repository provides a basic template for the project. The `src` folder contains all the source files needed of the program. The program is split into the library (`Jq`), which contains all the code and a an executable (`exe`), which simply runs it. The template code you are given already contains the functionality to parse `null` as an input and the identity `.` as a filter.
+
+- `JSON.hs` contains a datatype `JSON` to represent JSON data. It only has a single constructor `JNull`, so you will need to extend it with additional constructors to represent all kinds of `JSON` data. You're also required to implement by hand `Show` and `Eq` type-class isntances for this datatype.
+- `Filters.hs` contains a datatype `Filter` to represent `jq` filters. It has a single constructor for identity filter, so you will need to extend it too.
+- `Compiler.hs` contains the function `compile` that transforms a `Filter` into a function of type `JSON -> Either String [JSON]`, that can be executed on `JSON` values to produce either an error `String` or a list of results. It is currently only implemented for the `Identity` filter, so you will need to add cases for the other filters. Once you learn about monads you see that `compile` function fits the use-case of `Reader` monad. While we can't check the style-code of every submission, we highly encourage you to (re)write your `compile` function with `Reader`. The final signature would be then `Reader JSON (Either String [JSON])`
+- `CParser.hs` and `JParser.hs` contain functions `parseFilter` and `parseJSON` for parsing filters and `JSON` data, respectively. They both make use of the monadic parsing library from Chapter 13 of *Programming in Haskell (second edition)* by Graham Hutton. The code from this chapter can be found in the file `Parsing/Parsing.hs`. The functionality of `CParser.hs` and `JParser.hs` is re-exported by the module `Parser.hs`.
+- Finally, `Main.hs` contains the `main` function that collects the inputs, compiles the filter and runs it. You do not need to edit it yourself.
+- `Parsing` contains parsing library by Graham Hutton.
+
+The `test` directory contains some (extensible) tests for you to run. More information in the "Testing" section below
+
+You are free to add additional modules to your project should you need them, but we ask you to keep the existing structure intact to make grading easier.
+
+In addition to the functions from the Haskell `Prelude`, you are allowed to use
+functions from the following packages:
+
+- `containers` (https://hackage.haskell.org/package/containers)
+- `QuickCheck` (https://hackage.haskell.org/package/QuickCheck)
+
+If you want to use these packages, you should uncomment the corresponding
+line(s) in `JqClone.cabal`. Using other packages or copy-pasting code you found
+online is not allowed.
+
+### Base project
+
+This section describes the minimum functionality we expect your implementation to satisfy.
+
+*Grading*. In this section you can earn a maximum of 75 points, which constitutes 75% of your final grade for the project. "0 points" means that the feature is already implemented in the template. You don't *have* to do tasks above in any particular order, but we feel like this order corresponds to escalating difficulty in implementation.
+
+1. (0 points) Read JSON input from STDIN and filters as the first argument.
+ `echo '{"this" : "that"}' | jq '.'`
+2. (15 points) Parse and pretty-print valid JSONs.
+ This means, that your implementation should be able to handle
+ * `null`
+ * Numbers (floating-point `1.0` and E-notation included `1.0E+20`)
+ * Strings (with support for escape characters `"Hello, \"world\"!"` and unicode characters)
+ * Booleans
+ * Arrays
+ * JSON Objects
+
+ > *Hint*: Add constructors to the `JSON` type in `src/Jq/Json.hs` and define a parser for each constructor in `src/Jq/JParser.hs`
+
+ Please also note that since for grading purposes we will be test your program as whole, we have to rely heavily on the correctness of implementation for pretty-printing and parsing. So while this subtask might seem relatively easy, a big part of your grade depends on it transitively.
+
+3. (45 points total) Implement all [basic filters](https://stedolan.github.io/jq/manual/#Basicfilters).
+ In particular:
+ 1. (0 points) Identity filter `.`, which returns an object given to it.
+ 2. (2 point) Parenthesis '()', used for grouping operations.
+ 3. (5 points) Object indexing, both identifier `.field_name` and generic `.["field_name"]`.
+ If the field doesn't exist, running the filter should return `null`.
+ In this case "generic" means for all field names, as opposed to "identifier-like".
+ For fully generic field access look at the first one of the advanced tasks.
+ 4. (5 points) Optional object indexing `.field?` (and `.["field"]?`), which doesn't rise an exception if the value indexed into isn't an object.
+ 5. (5 points) Array index and slice `.[0]`, `.[0:10]`.
+ Slices behave very similarly to Python or Go. Start index (`0` here) is inclusive, while end index (`10`) is not.
+ 6. (6 points) Array/Object Value Iterator `.[]`, `.[1,2,3]`.
+ When applied to an array, the `.[]` filter iterates over its elements, and when applied on an object it iterates over its values (*not* over the keys).
+ `.[0,1,2]` returns an iterator which goes over the first, second and third elements.
+ 7. (6 points) Optional counterparts for indexing, slicing and iterators.
+ 8. (8 points) Comma operator `op1 , op2`.
+ Returns results of both `op1` and `op2` akin to iterator elements.
+ 9. (8 points) Pipe operator `op1 | op2`.
+ Passes results of `op1` into `op2`.
+
+ > *Hint*: for each basic filter, add a constructor to the `Filter` type in `src/Jq/Filters.hs`, then define parser for it in `src/Jq/CParser.hs`, and interpret the filter into Haskell code by adding a case to the `compile` function in `src/Jq/Compiler.hs`
+
+4. (10 points) Simple value constructors
+ `jq` allows you to construct values from the input elements:
+ `echo '1' | jq '{"this" : [.]}'` (this produces `{"this": [1]})`), or ignoring them:
+ `echo 'null' | jq '{"this" : [42]}'` (this produces `{"this": [42]})`).
+ For this task you're asked to implement only the "simple" ones: numbers, booleans, strings, arrays without iteration (`[1,2,.field]`, not `[.[]]`), objects.
+
+5. (5 points) [Recursive descent operator](https://stedolan.github.io/jq/manual/#RecursiveDescent:..) `..` iterates over all sub-values of the current value, including itself.
+ For example, `echo [{"a" : 1}] | jq '..'` results in
+
+ ```json
+ [
+ {
+ "a": 1
+ }
+ ]
+ {
+ "a": 1
+ }
+ 1
+ ```
+
+### Advanced tasks
+
+To get your grade to 100%, your implementation should also include some of the following
+features. The order and the number of points corresponds to the expected
+difficulty in implementation. Each point is worth 1 percent of the final grade,
+but the total grade is capped at 100%. Please note that the tasks in this
+section require the basic functionality from the previous section to be already
+implemented, so it does not make sense to start on these advanced features
+before you are confident in your implementation of the basic part.
+
+* (7 points) Generic indexing with filters.
+ A more general counterpart for object and array indexing, allowing arbitrary filters and iterators in the brackets.
+ For example: `echo '{"this" : ["that"], "that" : 1}' | jq '.[.this[]]'`, which returns `1`.
+ To keep this assignment independent from one with comparison operators below, you are asked to implement indexing with arbitrary filters, which output either numbers/iterators or strings.
+ Mind that this task also includes slices, generated with filters, e.g. `echo '[1, 2, 3, 4]' | jq '.[.[0]:.[3]]'`.
+ In order for this subtask to count your implementation should handle all JSON values, have all basic filters, and all basic constructors.
+
+* (10 points) More complex value constructors
+ This is complementary to the subtask with basic value constructors -- implement the constructors for arrays e.g. `[.items[].name]`, objects (`{user}`, `{(.[]) : null}`).
+ Be warned that this part is harder than it seems and some features interact in a non-obvious way, and not every aspect of behaviour is described precisely in the documentation.
+ In case of doubt, you can experiment with the reference implementation and follow what it does.
+ In order for this subtask to count your implementation should handle all JSON values, have all basic filters, and all object constructors.
+
+* (10 points) [Conditionals and comparisons](https://stedolan.github.io/jq/manual/#ConditionalsandComparisons):
+ * "Equal" and "not equal" operators `==`, `!=`, which take two JSON values and output a Boolean.
+ * If-then-else expression `if A then B else C end`.
+ * Comparison operators for numbers `<`, `<=`, `>`, `>=`
+ * Logic connectives: `and`, `or`, `not`.
+
+ In order for this subtask to count your implementation should handle all JSON values and have all basic filters.
+
+* (10 points) Arithmetic expressions: `+,-,*,/`, described [here](https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions).
+ Mind that these operations operate not only on numbers, but also on other JSON values such as arrays, strings, and objects.
+ In order for this subtask to count your implementation should handle all JSON values, have all basic filters, and simple object constructors.
+
+* (10 points) [Try-catch expressions](https://stedolan.github.io/jq/manual/#try-catch) `try op1 catch expr` which tries to execute `op1` and if exception appears, returns `expr`.
+ In order for this subtask to count your implementation should handle all JSON values and have all basic filters.
+
+* (12 points) [Syntactic variables](https://stedolan.github.io/jq/manual/#Variable/SymbolicBindingOperator:...as$identifier|...) `expr as $id | op`, which allow you to bind the value expr to identifier `id` before passing it further to `op`.
+ In order for this subtask to count your implementation should handle all JSON values and have all basic filters.
+
+* (15 points) [Reduction operator](https://stedolan.github.io/jq/manual/#Reduce) `reduce`, which corresponds to a fold over results returned by the previous operation.
+ In order for this subtask to count your implementation should handle all JSON values and have all basic filters.
+
+* (15 points) [Functions](https://stedolan.github.io/jq/manual/#DefiningFunctions), which allows you to define syntactical functions in jq filters.
+ In order for this subtask to count your implementation should handle all JSON values, have all basic filters, and simple object constructors.
+
+## Approaching the project
+
+### Setting up your development.
+
+1. Log in to [gitlab.ewi.tudelft.nl](https://gitlab.ewi.tudelft.nl) with your TU Delft login.
+2. Clone the `jq-clone` repository you've been given access to.
+3. Create a `dev` branch based on the `main` branch. `git branch dev main`
+4. Put your name and email in `JqClone.cabal`, commit and push the changes.
+5. Run `stack build` to build your project and `stack install` to install the `jq-clone` executable.
+6. To run your implementation use `echo "" | jq-clone ""` or `echo "" | stack run -- ""`
+ Usage of quotation marks is platform-specific: on Windows only `"` is allowed, while on *nix both `'` and `"` work.
+
+### Doing the project in parts
+
+While you're not required to submit your project earlier and can still do everything in a last-day crunch, this is not something we can recommend.
+To help you approach the task gradually we chose the following stages to provide feedback on:
+* Week **3**. Define JSON and its typeclass instances for Eq, Show.
+* Week **4**. Define some filters, start compiling programs.
+* Week **5**. Define parsers. Start implementing the rest of the base project features.
+* Week **6** and onwards. Implement features from the advanced project.
+
+### Suggested implementation order
+
+If you are unsure where to start or feeling a bit lost, you can approach the project in the following manner:
+
+1. Define a datatype for `JSON` and type class instances on week 3.
+2. Define a datatype for `Filters` in week 4. You can start small and implement only identity and field indexing initially. Write respective `compile` clauses.
+3. Implement pipe and comma operators.
+4. Implement arrays and array operations.
+5. Write a parser for numbers and strings.
+ Maybe skip floating point and escape characters for now -- you can always add them later.
+6. Extend the parsing to handle objects.
+7. Write a parser for filters.
+ At this point you should have a program that can be ran from the command-line, yay!
+8. Add value construction and make sure that composed operations have the right semantics.
+9. Implement recursive descent operator.
+10. Catch up on everything you skipped above. Write some tests, squash some bugs!
+
+#### Developing a project without parser.
+
+You probably noticed that if you follow the suggested implementation order you won't be able to test all the features you're working on from the shell until week 5.
+Our suggestion is to rely on GHCi and QuickCheck instead.
+* For QuickCheck introduction you can consult lecture slides, the [blog post](https://jesper.sikanda.be/posts/quickcheck-intro.html) and included tests for week 3 and 4.
+* For GHCi documentation you can consult the [official manual](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/ghci.html) or Chapter 2 (First steps) for Graham Hutton's book.
+ To start GHCi in the project navigate to the directory where the project is located and execute `stack ghci`(or `cabal repl`) in the shell.
+ By default this will start a REPL with the Main module loaded. You can then evaluate snippets you're interested in.
+ For example, to compile and test a filter one could use the following commands in GHCi:
+ ```
+ > import Jq.Json as J
+ > import Jq.Filters as F
+ > import Jq.Compiler as C
+ > let fil = F.Identity -- or any other filter
+ > let json = J.JNull -- or any other JSON object
+ > let res = C.run (C.compile fil) json
+ > print res
+ ```
+
+### Testing
+
+There are several test suites included in the project for you.
+Keep in mind that they are intentionally incomplete and aren't used to grade your project directly.
+They are here simply for your convenience.
+
+* Tests for weeks 3 and 4.
+ Since at the earlier stages of the project you don't have a parser yet, we came up with a few tests to help you make sure that your implementation is correct.
+ They are located in `test/week3` and `test/week4` respectively.
+ To run them type `stack test JqClone:week3` or `stack test JqClone:week4`. (or `cabal test week3` or `week4`, if you're using `cabal`)
+
+ These tests are QuickCheck-based so you are encouraged to use them as inspiration or extend them as you see fit.
+* We also provide a small "full-pipeline" test suite based on the original jq test suite.
+ Test cases are in `test/from-upstream/data/jq.test`, which you're encouraged to add your own cases to.
+ You can test your current implementation with `stack test JqClone:from-upstream` (if you're using `cabal` and `cabal test from-upstream` yields nothing run `cabal configure --enable-tests` first).
+ You have to have `jq` installed on your machine and available on your `$PATH` for this -- tests use it for pretty-printing.
+* Finally you'll also find some unit tests for different parts of the project in `test/unit-tests`.
+ These include tests for the parsers of JSON, filters and compilation units.
+
+
+### Getting help
+
+If you have questions about a part of the project, you can create a question on
+TU Delft Answers at [answers.ewi.tudelft.nl](https://answers.ewi.tudelft.nl/categories/1/tags/226).
+Remember to phrase your question in general terms and avoid including part of your code.
+Alternatively, you can ask questions to one of the teaching assistants during
+the weekly lab sessions, or send an email to
+[fp-cs-ewi@tudelft.nl](mailto:fp-cs-ewi@tudelft.nl).
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..a8a0580
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for jq-clone
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/JQ-CASE-STUDY.md b/JQ-CASE-STUDY.md
new file mode 100644
index 0000000..2572158
--- /dev/null
+++ b/JQ-CASE-STUDY.md
@@ -0,0 +1,148 @@
+# Introducing `jq`
+
+First let's see what you can actually do in it.
+
+## Case study: counting meteorites
+
+Let's find out how many [meteorites](https://xkcd.com/1723/) fell in the Netherlands!
+
+
+Alternative ways to follow this tutorial (Windows, web)
+If you're on Windows, [here's](https://gitlab.ewi.tudelft.nl/cse3100/jq-clone/-/snippets/9799) a version for PowerShell.
+
+
+While the best way to follow this part of the intro is with a shell open, we also put the data on jqplay.org for you to play with.
+It's not quite as fast as your local installation, but works in your favourite browser: [jqplay snippet](https://jqplay.org/s/McozX7_-j-).
+
+
+NASA provides a database of meteorites, as JSON object, so let's download it:
+ `⊢ curl "https://data.nasa.gov/resource/y77d-th95.json" > meteorites.json`
+
+But it's pretty hard to read, since it's compressed and pretty big for a text file.
+
+Here, judge for youself:
+
+`⊢ cat meteorites.json | head -n 3`
+
+```json
+[{"name":"Aachen","id":"1","nametype":"Valid","recclass":"L5","mass":"21","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"50.775000","reclong":"6.083330","geolocation":{"type":"Point","coordinates":[6.08333,50.775]}}
+,{"name":"Aarhus","id":"2","nametype":"Valid","recclass":"H6","mass":"720","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"56.183330","reclong":"10.233330","geolocation":{"type":"Point","coordinates":[10.23333,56.18333]}}
+,{"name":"Abee","id":"6","nametype":"Valid","recclass":"EH4","mass":"107000","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"54.216670","reclong":"-113.000000","geolocation":{"type":"Point","coordinates":[-113,54.21667]}}
+```
+
+```bash
+⊢ du -h meteorites.json
+244K meteorites.json
+```
+
+
+
+To make it easier for us to read we can pretty-print it: `jq '.' meteorites.json`.
+
+Output:
+
+```bash
+⊢ jq '.' meteorites.json | head -n 19
+[
+ {
+ "name": "Aachen",
+ "id": "1",
+ "nametype": "Valid",
+ "recclass": "L5",
+ "mass": "21",
+ "fall": "Fell",
+ "year": "1880-01-01T00:00:00.000",
+ "reclat": "50.775000",
+ "reclong": "6.083330",
+ "geolocation": {
+ "type": "Point",
+ "coordinates": [
+ 6.08333,
+ 50.775
+ ]
+ }
+ },
+```
+
+
+
+However, this does't solve the problem with the size, so let's also select just the first object in that array: `jq '.[0]' meteorites.json`
+
+Output:
+
+```bash
+⊢ jq '.[0]' meteorites.json
+{
+ "name": "Aachen",
+ "id": "1",
+ "nametype": "Valid",
+ "recclass": "L5",
+ "mass": "21",
+ "fall": "Fell",
+ "year": "1880-01-01T00:00:00.000",
+ "reclat": "50.775000",
+ "reclong": "6.083330",
+ "geolocation": {
+ "type": "Point",
+ "coordinates": [
+ 6.08333,
+ 50.775
+ ]
+ }
+}
+```
+
+
+
+Now that we understand what the schema is roughly, we can get to the fun part.
+
+We can use `.field` syntax to access object fields, `.[n]` to access array elements, and pipes `op1 | op2` to chain the results of the computations.
+
+```bash
+⊢ jq '.[0] | .geolocation' meteorites.json
+{
+ "type": "Point",
+ "coordinates": [
+ 6.08333,
+ 50.775
+ ]
+}
+```
+
+`jq` also includes a lot of other features, like comparisons `==`,`!=` and filters `select`.
+You can check the [documentation](https://stedolan.github.io/jq/manual/) and the [tutorial](https://stedolan.github.io/jq/tutorial/) for more details, for now let's play a bit more with the data.
+
+So, given a list of meteorites with all coordinates, we can list all the meteorites that fell in the Netherlands.
+Of course, checking precise bounds is going to be hard, so let's just do a bounding box from [humdata.org](https://data.humdata.org/dataset/bounding-boxes-for-countries/resource/aec5d77d-095a-4d42-8a13-5193ec18a6a9):
+Latitute: from 50.75 to 53.685
+Longtitute: from 3.113 to 7.217
+
+Then we proceed as follows:
+
+1. Filter out the entrances without latitute and longtitude.
+2. Filter out by latitute.
+3. Filter out by longtitude.
+4. Select the `name` field for those which satify the conditions above
+
+```bash
+⊢ jq '.[] | select (.reclat != null and .reclong != null) | select(.reclat | tonumber | (50.75 < .) and (. < 53.68)) | select (.reclong | tonumber | (3.13 < .) and (. < 7.21)) | .name' meteorites.json
+```
+
+Drumroll:
+
+```bash
+"Aachen"
+"Ellemeet"
+"Glanerbrug"
+"Ramsdorf"
+"St. Denis Westrem"
+```
+
+Our data suggests that there are at least five.
+However, the name of the first one seems suspiciously German and we used a bounding box, not exact border.
+And there it is, if we double-check on [https://www.lpi.usra.edu/meteor/metbull.php](https://www.lpi.usra.edu/meteor/metbull.php) it turns out that only the second and third did fall in the Netherlands (Aachen and Ramsdorf were in Germany and St. Denis Westrem in Belgium).
+
+If you want to play with `jq` a bit more, here's a couple of things to try:
+
+* Find a bounding box for the EU and run the same check with new boundaries.
+* [https://gist.github.com/graydon/11198540](https://gist.github.com/graydon/11198540) provides bounding boxes in JSON format, write a jq filter that extracts bounding box for the Netherlands.
diff --git a/JqClone.cabal b/JqClone.cabal
new file mode 100644
index 0000000..5c399f2
--- /dev/null
+++ b/JqClone.cabal
@@ -0,0 +1,146 @@
+cabal-version: >=1.10
+
+-- Initial package description 'jq-clone.cabal' generated by 'cabal init'.
+-- For further documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name: JqClone
+
+-- The package version. See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- https://pvp.haskell.org
+-- PVP summary: +-+------- breaking API changes
+-- | | +----- non-breaking API additions
+-- | | | +--- code changes with no API change
+version: 0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis: project for the FP course at TU Delft
+
+-- A longer description of the package.
+-- description:
+
+-- A URL where users can report bugs.
+-- bug-reports:
+
+-- The license under which the package is released.
+license: BSD3
+
+-- The file containing the license text.
+license-file: LICENSE
+
+-- The package author(s).
+author: Palle Maesen
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer: PMaesen@tudelft.student.nl
+
+-- A copyright notice.
+-- copyright:
+category: Development
+build-type: Simple
+
+-- Extra files to be distributed with the package, such as examples or a
+-- README.
+extra-source-files: README.md
+
+data-dir: test/from-upstream/data
+data-files: jq.test
+
+library
+ exposed-modules: Jq.Main
+ Parsing.Parsing
+ Jq.Json
+ Jq.Compiler
+ Jq.Filters
+ Jq.CParser
+ Jq.JParser
+ Jq.Parser
+
+ -- Libraries other than mentioned below aren't allowed
+ build-depends: base >=4.14 && <4.18
+ -- Uncomment if needed:
+ -- , containers >= 0.6 && < 0.7
+ -- , QuickCheck >= 2.13.2 && < 2.15
+
+ -- Directories containing source files.
+ hs-source-dirs: src
+
+ -- Base language which the package is written in.
+ default-language: Haskell2010
+
+ -- Turn all warnings on
+ ghc-options: -Wall
+
+executable jq-clone
+ main-is: Main.hs
+ build-depends: base >=4.14 && <4.18,
+ JqClone
+ hs-source-dirs: src/exe
+ default-language: Haskell2010
+
+
+-- tests below
+
+
+Test-Suite from-upstream
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: Paths_JqClone
+ build-depends: base >=4.14 && <4.18,
+ deepseq >= 1.4 && < 1.5,
+ stm >= 2.4 && < 2.6,
+ tasty >= 1.3 && < 1.5,
+ tasty-hunit >= 0.10 && < 0.11,
+ typed-process >= 0.2 && <0.3,
+ utf8-string >= 1.0 && < 1.1,
+ JqClone
+ hs-source-dirs: test/from-upstream
+ default-language: Haskell2010
+ ghc-options: -threaded
+
+Test-Suite week3
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: Paths_JqClone
+ build-depends: base >=4.14 && <4.18,
+ QuickCheck >= 2.13 && < 2.15,
+ deepseq >= 1.4.6 && <1.4.9,
+ tasty >= 1.4 && <1.5,
+ tasty-quickcheck >= 0.9 && <0.11,
+ JqClone
+ hs-source-dirs: test/week3
+ default-language: Haskell2010
+ ghc-options: -threaded
+
+Test-Suite week4
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: Paths_JqClone
+ build-depends: base >=4.14 && <4.18,
+ QuickCheck >= 2.13 && < 2.15,
+ deepseq >= 1.4.4 && <1.4.9,
+ tasty >= 1.4 && <1.5,
+ tasty-quickcheck >= 0.9 && <0.11,
+ JqClone
+ hs-source-dirs: test/week4
+ default-language: Haskell2010
+ ghc-options: -threaded
+
+Test-Suite unit-tests
+ type: exitcode-stdio-1.0
+ main-is: Main.hs
+ other-modules: JParserTest
+ CParserTest
+ CompileTest
+ build-depends: base >=4.14 && <4.18,
+ QuickCheck >= 2.13 && <2.15,
+ deepseq >= 1.4.4 && <1.4.9,
+ tasty >= 1.4 && <1.5,
+ tasty-hunit >= 0.10 && < 0.11,
+ tasty-quickcheck >= 0.9 && <0.11,
+ JqClone
+ hs-source-dirs: test/unit-tests
+ default-language: Haskell2010
+ ghc-options: -threaded
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1d67763
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2021, Bohdan
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Bohdan nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index 4903f34..684c20a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,46 @@
-# Awesome game
+# Project for FP course at TU Delft
-Copyright Hector Peeters
+A clone of `jq` in Haskell.
+
+You will find the description of the task on Brightspace.
+
+## Build
+```
+> stack build
+```
+
+## Install
+
+```
+> stack install
+```
+
+this installs your executable to `~/.local/bin` by default (on *nix), make sure it's in $PATH
+
+## Test
+
+```
+stack test
+```
+
+You will need `jq` installed and available on `$PATH` to run `from-upstream` test suite.
+
+## Use
+
+```
+> echo '{"this" : "that"}' | jq-clone '.this'
+```
+
+or
+
+```
+> echo '{"this" : "that"}' | stack run -- '.this'
+```
+
+## Test `jq` online
+
+[jqplay.org](https://jqplay.org/)
+
+## Docs
+
+[stedolan.github.io/jq/manual](https://stedolan.github.io/jq/manual)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/SlickDwarfFortressNXT.iml b/SlickDwarfFortressNXT.iml
deleted file mode 100644
index d1cec00..0000000
--- a/SlickDwarfFortressNXT.iml
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/bin/assets/Images.class b/bin/assets/Images.class
deleted file mode 100644
index 69f4a26..0000000
Binary files a/bin/assets/Images.class and /dev/null differ
diff --git a/bin/assets/Sounds.class b/bin/assets/Sounds.class
deleted file mode 100644
index 85db117..0000000
Binary files a/bin/assets/Sounds.class and /dev/null differ
diff --git a/bin/entities/Entity.class b/bin/entities/Entity.class
deleted file mode 100644
index f592bad..0000000
Binary files a/bin/entities/Entity.class and /dev/null differ
diff --git a/bin/entities/Worker.class b/bin/entities/Worker.class
deleted file mode 100644
index 5537d50..0000000
Binary files a/bin/entities/Worker.class and /dev/null differ
diff --git a/bin/entities/pathfinding/Node.class b/bin/entities/pathfinding/Node.class
deleted file mode 100644
index bf2d79d..0000000
Binary files a/bin/entities/pathfinding/Node.class and /dev/null differ
diff --git a/bin/entities/pathfinding/Pathfinder$1.class b/bin/entities/pathfinding/Pathfinder$1.class
deleted file mode 100644
index 48e56e3..0000000
Binary files a/bin/entities/pathfinding/Pathfinder$1.class and /dev/null differ
diff --git a/bin/entities/pathfinding/Pathfinder.class b/bin/entities/pathfinding/Pathfinder.class
deleted file mode 100644
index 391903f..0000000
Binary files a/bin/entities/pathfinding/Pathfinder.class and /dev/null differ
diff --git a/bin/jobSystem/Job.class b/bin/jobSystem/Job.class
deleted file mode 100644
index 0ad8399..0000000
Binary files a/bin/jobSystem/Job.class and /dev/null differ
diff --git a/bin/jobSystem/JobManager.class b/bin/jobSystem/JobManager.class
deleted file mode 100644
index b61ead5..0000000
Binary files a/bin/jobSystem/JobManager.class and /dev/null differ
diff --git a/bin/jobSystem/JobWindow$1.class b/bin/jobSystem/JobWindow$1.class
deleted file mode 100644
index ff3db9f..0000000
Binary files a/bin/jobSystem/JobWindow$1.class and /dev/null differ
diff --git a/bin/jobSystem/JobWindow.class b/bin/jobSystem/JobWindow.class
deleted file mode 100644
index 1521c0d..0000000
Binary files a/bin/jobSystem/JobWindow.class and /dev/null differ
diff --git a/bin/jobSystem/Jobs$JobType.class b/bin/jobSystem/Jobs$JobType.class
deleted file mode 100644
index 290c4a8..0000000
Binary files a/bin/jobSystem/Jobs$JobType.class and /dev/null differ
diff --git a/bin/jobSystem/Jobs.class b/bin/jobSystem/Jobs.class
deleted file mode 100644
index 821df8d..0000000
Binary files a/bin/jobSystem/Jobs.class and /dev/null differ
diff --git a/bin/math/Vector2i.class b/bin/math/Vector2i.class
deleted file mode 100644
index fc80db5..0000000
Binary files a/bin/math/Vector2i.class and /dev/null differ
diff --git a/bin/objects/Direction.class b/bin/objects/Direction.class
deleted file mode 100644
index 8bbc8b8..0000000
Binary files a/bin/objects/Direction.class and /dev/null differ
diff --git a/bin/objects/Door.class b/bin/objects/Door.class
deleted file mode 100644
index e79de2c..0000000
Binary files a/bin/objects/Door.class and /dev/null differ
diff --git a/bin/objects/WoodenWall.class b/bin/objects/WoodenWall.class
deleted file mode 100644
index 6750303..0000000
Binary files a/bin/objects/WoodenWall.class and /dev/null differ
diff --git a/bin/util/Strings.class b/bin/util/Strings.class
deleted file mode 100644
index cb8ee40..0000000
Binary files a/bin/util/Strings.class and /dev/null differ
diff --git a/bin/world/Tile.class b/bin/world/Tile.class
deleted file mode 100644
index 891184a..0000000
Binary files a/bin/world/Tile.class and /dev/null differ
diff --git a/bin/world/TileType.class b/bin/world/TileType.class
deleted file mode 100644
index cae56de..0000000
Binary files a/bin/world/TileType.class and /dev/null differ
diff --git a/bin/world/World.class b/bin/world/World.class
deleted file mode 100644
index 9ba9b78..0000000
Binary files a/bin/world/World.class and /dev/null differ
diff --git a/bin/world/WorldGenerator.class b/bin/world/WorldGenerator.class
deleted file mode 100644
index 76d59b4..0000000
Binary files a/bin/world/WorldGenerator.class and /dev/null differ
diff --git a/lib/PNGDecoder.jar b/lib/PNGDecoder.jar
deleted file mode 100644
index 86cf065..0000000
Binary files a/lib/PNGDecoder.jar and /dev/null differ
diff --git a/lib/imgscalr-lib-4.2.jar b/lib/imgscalr-lib-4.2.jar
deleted file mode 100644
index bb7a406..0000000
Binary files a/lib/imgscalr-lib-4.2.jar and /dev/null differ
diff --git a/lib/jinput.jar b/lib/jinput.jar
deleted file mode 100644
index 7c2b6b0..0000000
Binary files a/lib/jinput.jar and /dev/null differ
diff --git a/lib/lwjgl.jar b/lib/lwjgl.jar
deleted file mode 100644
index 5da88d3..0000000
Binary files a/lib/lwjgl.jar and /dev/null differ
diff --git a/lib/lwjgl_util.jar b/lib/lwjgl_util.jar
deleted file mode 100644
index d377c51..0000000
Binary files a/lib/lwjgl_util.jar and /dev/null differ
diff --git a/lib/natives-linux.jar b/lib/natives-linux.jar
deleted file mode 100644
index a543ee0..0000000
Binary files a/lib/natives-linux.jar and /dev/null differ
diff --git a/lib/natives-mac.jar b/lib/natives-mac.jar
deleted file mode 100644
index 220012b..0000000
Binary files a/lib/natives-mac.jar and /dev/null differ
diff --git a/lib/natives-windows/META-INF/LWJGL.RSA b/lib/natives-windows/META-INF/LWJGL.RSA
deleted file mode 100644
index e8fdd42..0000000
Binary files a/lib/natives-windows/META-INF/LWJGL.RSA and /dev/null differ
diff --git a/lib/natives-windows/META-INF/LWJGL.SF b/lib/natives-windows/META-INF/LWJGL.SF
deleted file mode 100644
index 7b1aadb..0000000
--- a/lib/natives-windows/META-INF/LWJGL.SF
+++ /dev/null
@@ -1,30 +0,0 @@
-Signature-Version: 1.0
-SHA-256-Digest-Manifest-Main-Attributes: 4qGIDsjmf8ZDczflwSf6tIdbOjZZq
- 9qEfMQx6QzRtnQ=
-SHA-256-Digest-Manifest: kaX5ZhdEnKSw1Ry+/1KrYEqT4o6m+ceMFqb5t4HsE+o=
-Created-By: 1.7.0_65 (Oracle Corporation)
-
-Name: OpenAL32.dll
-SHA-256-Digest: JBLWoifSMjsWesKbvbxdetxfaSSV+2SqjdybhO5Ug+w=
-
-Name: OpenAL64.dll
-SHA-256-Digest: 7joamLIRSB9nwGwslYeRfLgSwxQ24vyx1VjtMUz5yzo=
-
-Name: jinput-dx8_64.dll
-SHA-256-Digest: gqPqx0iM+EyTEiFIIjLqpap5R4F+rpngD1zDWztZqJU=
-
-Name: jinput-raw.dll
-SHA-256-Digest: 0F2MlPOLDUP+YvMJi7sZaEwZr0e+CGba2hUXY1xtRjQ=
-
-Name: jinput-raw_64.dll
-SHA-256-Digest: vAU35hZjfxoUPfOgy50IhGZeaaSCglGI3akQFZrME8Q=
-
-Name: lwjgl64.dll
-SHA-256-Digest: 9cFdQYz/TNculh/xlvLTSGT8Vg83nre0o+KMA+ETWww=
-
-Name: lwjgl.dll
-SHA-256-Digest: KYz8LiLcxob+J+XJ6aGEH7mExkpnVJnqQ9PAKUo6pU8=
-
-Name: jinput-dx8.dll
-SHA-256-Digest: bbfCaHkHLO6f+f78cbISFegwkgJ3gr8LKdnmjyx4hN4=
-
diff --git a/lib/natives-windows/META-INF/MANIFEST.MF b/lib/natives-windows/META-INF/MANIFEST.MF
deleted file mode 100644
index 3687e22..0000000
--- a/lib/natives-windows/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,28 +0,0 @@
-Manifest-Version: 1.0
-Ant-Version: Apache Ant 1.9.4
-Created-By: 1.7.0_65-b19 (Oracle Corporation)
-
-Name: OpenAL32.dll
-SHA-256-Digest: uvJ/yR3IUteIieBSz8ntK2/AknJYu1B6iVxvzVDxD+8=
-
-Name: jinput-dx8_64.dll
-SHA-256-Digest: UR3FDCAB0+JYRd1HnKgv38nUJAP5qmnGSTJXxm3fAmY=
-
-Name: OpenAL64.dll
-SHA-256-Digest: kmG2YBCoRd3vn2HV5CZv4vCKU/NgXaAC6ej40gK9vF4=
-
-Name: jinput-raw.dll
-SHA-256-Digest: D80z4AulxR8/3zYT2JxungA4H+8DtVBBLqc7yDcjfc8=
-
-Name: jinput-raw_64.dll
-SHA-256-Digest: dM101V6iDo/Op67YuXws8JbaH83j+vGD+BWk3Ok2TsM=
-
-Name: lwjgl64.dll
-SHA-256-Digest: yuBz7H5Fm5UCApdLuAETmP3r+ABUL3Ceany1tvHcmKw=
-
-Name: lwjgl.dll
-SHA-256-Digest: FNvr9Gdxercv7ynRFRKb69ctQdyx8wf+mUbx/cut0S8=
-
-Name: jinput-dx8.dll
-SHA-256-Digest: 9u4zcBv7ukgYcPSjcNcHuHAB+zIT78xgv/MlATtOIZw=
-
diff --git a/lib/natives-windows/OpenAL32.dll b/lib/natives-windows/OpenAL32.dll
deleted file mode 100644
index 1f69e94..0000000
Binary files a/lib/natives-windows/OpenAL32.dll and /dev/null differ
diff --git a/lib/natives-windows/OpenAL64.dll b/lib/natives-windows/OpenAL64.dll
deleted file mode 100644
index 6f2a2fe..0000000
Binary files a/lib/natives-windows/OpenAL64.dll and /dev/null differ
diff --git a/lib/natives-windows/jinput-dx8.dll b/lib/natives-windows/jinput-dx8.dll
deleted file mode 100644
index 6d27ad5..0000000
Binary files a/lib/natives-windows/jinput-dx8.dll and /dev/null differ
diff --git a/lib/natives-windows/jinput-dx8_64.dll b/lib/natives-windows/jinput-dx8_64.dll
deleted file mode 100644
index 6730589..0000000
Binary files a/lib/natives-windows/jinput-dx8_64.dll and /dev/null differ
diff --git a/lib/natives-windows/jinput-raw.dll b/lib/natives-windows/jinput-raw.dll
deleted file mode 100644
index ce1d162..0000000
Binary files a/lib/natives-windows/jinput-raw.dll and /dev/null differ
diff --git a/lib/natives-windows/jinput-raw_64.dll b/lib/natives-windows/jinput-raw_64.dll
deleted file mode 100644
index 3d2b3ad..0000000
Binary files a/lib/natives-windows/jinput-raw_64.dll and /dev/null differ
diff --git a/lib/natives-windows/lwjgl.dll b/lib/natives-windows/lwjgl.dll
deleted file mode 100644
index 7cca39f..0000000
Binary files a/lib/natives-windows/lwjgl.dll and /dev/null differ
diff --git a/lib/natives-windows/lwjgl64.dll b/lib/natives-windows/lwjgl64.dll
deleted file mode 100644
index 99cbd98..0000000
Binary files a/lib/natives-windows/lwjgl64.dll and /dev/null differ
diff --git a/lib/slick.jar b/lib/slick.jar
deleted file mode 100644
index 1d3d075..0000000
Binary files a/lib/slick.jar and /dev/null differ
diff --git a/res/sounds/click.wav b/res/sounds/click.wav
deleted file mode 100644
index 57aed8d..0000000
Binary files a/res/sounds/click.wav and /dev/null differ
diff --git a/res/sounds/startup.wav b/res/sounds/startup.wav
deleted file mode 100644
index 388fb1c..0000000
Binary files a/res/sounds/startup.wav and /dev/null differ
diff --git a/res/sprites/black.png b/res/sprites/black.png
deleted file mode 100644
index 3c02b21..0000000
Binary files a/res/sprites/black.png and /dev/null differ
diff --git a/res/sprites/bush.png b/res/sprites/bush.png
deleted file mode 100644
index 7964543..0000000
Binary files a/res/sprites/bush.png and /dev/null differ
diff --git a/res/sprites/cow.png b/res/sprites/cow.png
deleted file mode 100644
index 0ae66aa..0000000
Binary files a/res/sprites/cow.png and /dev/null differ
diff --git a/res/sprites/diamond_ore.png b/res/sprites/diamond_ore.png
deleted file mode 100644
index 77b8e3a..0000000
Binary files a/res/sprites/diamond_ore.png and /dev/null differ
diff --git a/res/sprites/floor.png b/res/sprites/floor.png
deleted file mode 100644
index 555128b..0000000
Binary files a/res/sprites/floor.png and /dev/null differ
diff --git a/res/sprites/grass_tile.png b/res/sprites/grass_tile.png
deleted file mode 100644
index 76b51a7..0000000
Binary files a/res/sprites/grass_tile.png and /dev/null differ
diff --git a/res/sprites/gray.png b/res/sprites/gray.png
deleted file mode 100644
index 01500a7..0000000
Binary files a/res/sprites/gray.png and /dev/null differ
diff --git a/res/sprites/guy.png b/res/sprites/guy.png
deleted file mode 100644
index 0a1bc64..0000000
Binary files a/res/sprites/guy.png and /dev/null differ
diff --git a/res/sprites/hourglas.png b/res/sprites/hourglas.png
deleted file mode 100644
index 0ae22aa..0000000
Binary files a/res/sprites/hourglas.png and /dev/null differ
diff --git a/res/sprites/inProgress.png b/res/sprites/inProgress.png
deleted file mode 100644
index a5b01f5..0000000
Binary files a/res/sprites/inProgress.png and /dev/null differ
diff --git a/res/sprites/indicator.png b/res/sprites/indicator.png
deleted file mode 100644
index 81ea4ca..0000000
Binary files a/res/sprites/indicator.png and /dev/null differ
diff --git a/res/sprites/iron_doorEW.png b/res/sprites/iron_doorEW.png
deleted file mode 100644
index 95cd34b..0000000
Binary files a/res/sprites/iron_doorEW.png and /dev/null differ
diff --git a/res/sprites/iron_doorNS.png b/res/sprites/iron_doorNS.png
deleted file mode 100644
index 006d3b7..0000000
Binary files a/res/sprites/iron_doorNS.png and /dev/null differ
diff --git a/res/sprites/iron_ore.png b/res/sprites/iron_ore.png
deleted file mode 100644
index a37abb8..0000000
Binary files a/res/sprites/iron_ore.png and /dev/null differ
diff --git a/res/sprites/iron_wall.png b/res/sprites/iron_wall.png
deleted file mode 100644
index 76fe93d..0000000
Binary files a/res/sprites/iron_wall.png and /dev/null differ
diff --git a/res/sprites/select.png b/res/sprites/select.png
deleted file mode 100644
index a997343..0000000
Binary files a/res/sprites/select.png and /dev/null differ
diff --git a/res/sprites/splash.png b/res/sprites/splash.png
deleted file mode 100644
index bce037a..0000000
Binary files a/res/sprites/splash.png and /dev/null differ
diff --git a/res/sprites/splash2.png b/res/sprites/splash2.png
deleted file mode 100644
index 6389739..0000000
Binary files a/res/sprites/splash2.png and /dev/null differ
diff --git a/res/sprites/stone.png b/res/sprites/stone.png
deleted file mode 100644
index ea4f131..0000000
Binary files a/res/sprites/stone.png and /dev/null differ
diff --git a/res/sprites/stone_tile.png b/res/sprites/stone_tile.png
deleted file mode 100644
index 6af1ea6..0000000
Binary files a/res/sprites/stone_tile.png and /dev/null differ
diff --git a/res/sprites/tree.png b/res/sprites/tree.png
deleted file mode 100644
index 13e3d03..0000000
Binary files a/res/sprites/tree.png and /dev/null differ
diff --git a/res/sprites/water_tile.png b/res/sprites/water_tile.png
deleted file mode 100644
index f27935b..0000000
Binary files a/res/sprites/water_tile.png and /dev/null differ
diff --git a/res/sprites/woodenWall.png b/res/sprites/woodenWall.png
deleted file mode 100644
index 75393e9..0000000
Binary files a/res/sprites/woodenWall.png and /dev/null differ
diff --git a/res/sprites/wooden_doorEW.png b/res/sprites/wooden_doorEW.png
deleted file mode 100644
index 214adec..0000000
Binary files a/res/sprites/wooden_doorEW.png and /dev/null differ
diff --git a/res/sprites/wooden_doorNS.png b/res/sprites/wooden_doorNS.png
deleted file mode 100644
index e2b24cf..0000000
Binary files a/res/sprites/wooden_doorNS.png and /dev/null differ
diff --git a/res/spritesheets/gray.png b/res/spritesheets/gray.png
deleted file mode 100644
index ee9792e..0000000
Binary files a/res/spritesheets/gray.png and /dev/null differ
diff --git a/saves/save_2016_02_07-11_45_26.sav b/saves/save_2016_02_07-11_45_26.sav
deleted file mode 100644
index 29a9368..0000000
--- a/saves/save_2016_02_07-11_45_26.sav
+++ /dev/null
@@ -1,34 +0,0 @@
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;
-GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
-GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;STONE;STONE;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;GRASS;
diff --git a/src/Game/Engine.java b/src/Game/Engine.java
deleted file mode 100644
index d6df6a5..0000000
--- a/src/Game/Engine.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package game;
-
-import assets.Images;
-import assets.Sounds;
-import game.states.GameState;
-import game.states.SplashState;
-import org.newdawn.slick.AppGameContainer;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.StateBasedGame;
-
-import java.io.File;
-
-public class Engine extends StateBasedGame {
-
- private static GameState gameState = new GameState();
-
- public Engine() {
- super("Dwarf Castle");
- }
-
- public static void main(String[] args) throws SlickException {
- File f = new File("natives");
- if (f.exists())
- System.setProperty("org.lwjgl.librarypath", f.getAbsolutePath());
- AppGameContainer gc = new AppGameContainer(new Engine());
- gc.setDisplayMode(Window.getWidth(), Window.getHeight(), Window.FULLSCREEN);
- gc.start();
- }
-
- @Override
- public void initStatesList(GameContainer gc) throws SlickException {
- gc.setAlwaysRender(true);
- gc.setTargetFrameRate(60);
- gc.setShowFPS(false);
-
- addState(new SplashState(Images.getImage("splash"), Sounds.getSound("startup"), 0, true));
- addState(gameState);
- }
-}
\ No newline at end of file
diff --git a/src/Game/Game.java b/src/Game/Game.java
deleted file mode 100644
index f07fc38..0000000
--- a/src/Game/Game.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package game;
-
-import entities.Worker;
-import jobSystem.JobManager;
-import jobSystem.JobWindow;
-import jobSystem.MouseManager;
-import math.Vector2i;
-import org.lwjgl.Sys;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.state.StateBasedGame;
-import rendering.Renderer;
-import world.World;
-import world.WorldGenerator;
-
-public class Game {
-
- public Renderer renderer = new Renderer();
- private Debug debug = new Debug();
-
- public void init(GameContainer gc, StateBasedGame s) {
- World.init();
- JobManager.addWorker(new Worker(new Vector2i(0, 1)));
- JobWindow.openJobWindow();
- }
-
- public void render(GameContainer gc, StateBasedGame s, Graphics g) {
- renderer.render(gc, s, g);
- MouseManager.render(gc, s, g);
- debug.renderDebug(gc, s, g);
- }
-
- public void update(GameContainer gc, StateBasedGame s, int delta) {
- MouseManager.updateMouseEvents(gc, s, delta);
- JobManager.update(gc, s, delta);
- debug.updateDebug(gc, s, delta);
- renderer.update(gc, s, delta);
- if (gc.getInput().isKeyDown(Input.KEY_Z))
- Camera.position.y ++;
- if (gc.getInput().isKeyDown(Input.KEY_S))
- Camera.position.y --;
- if (gc.getInput().isKeyDown(Input.KEY_Q))
- Camera.position.x ++;
- if (gc.getInput().isKeyDown(Input.KEY_D))
- Camera.position.x --;
- if (gc.getInput().isKeyDown(Input.KEY_A))
- Camera.zoomIn();
- if (gc.getInput().isKeyDown(Input.KEY_E))
- Camera.zoomOut();
- if (gc.getInput().isKeyPressed(Input.KEY_SPACE))
- gc.setPaused(!gc.isPaused());
- }
-}
\ No newline at end of file
diff --git a/src/Game/Window.java b/src/Game/Window.java
deleted file mode 100644
index 4e44d82..0000000
--- a/src/Game/Window.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package game;
-
-public class Window {
-
- private static int WIDTH = 960;
- private static int HEIGHT = 544;
- public static boolean FULLSCREEN = false;
-
- public static int getWidth() {
- return WIDTH;
- }
-
- public static int getHeight() {
- return HEIGHT;
- }
-
-}
\ No newline at end of file
diff --git a/src/Game/states/GameState.java b/src/Game/states/GameState.java
deleted file mode 100644
index 1ca6b50..0000000
--- a/src/Game/states/GameState.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package game.states;
-
-import game.Game;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-
-public class GameState extends BasicGameState {
-
- private Game game = new Game();
-
- @Override
- public void init(GameContainer gc, StateBasedGame s) throws SlickException {
- game.init(gc, s);
- }
-
- @Override
- public void render(GameContainer gc, StateBasedGame s, Graphics g) throws SlickException {
- game.render(gc, s, g);
- }
-
- @Override
- public void update(GameContainer gc, StateBasedGame s, int delta) throws SlickException {
- game.update(gc, s, delta);
- }
-
- @Override
- public int getID() {
- return States.GAME;
- }
-
-}
diff --git a/src/Game/states/SplashState.java b/src/Game/states/SplashState.java
deleted file mode 100644
index c0dc9fe..0000000
--- a/src/Game/states/SplashState.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package game.states;
-
-import game.Window;
-import org.newdawn.slick.*;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-
-public class SplashState extends BasicGameState {
-
- private Image splash;
- private Sound sound;
- private int elapsedTime;
- private int delay = 3000;
-
- public SplashState(Image splash, Sound sound, int delay, boolean playSound) {
- this.splash = splash;
- this.delay = delay;
- this.sound = sound;
- if (playSound)
- sound.play();
- }
-
- @Override
- public void init(GameContainer gc, StateBasedGame s) throws SlickException {
- }
-
- @Override
- public void render(GameContainer gc, StateBasedGame s, Graphics g) throws SlickException {
- g.drawImage(splash.getScaledCopy(Window.getWidth(), Window.getHeight()), 0, 0);
- }
-
- @Override
- public void update(GameContainer gc, StateBasedGame s, int delta) throws SlickException {
- elapsedTime += delta;
- if (elapsedTime >= delay) {
- sound.stop();
- s.enterState(States.GAME);
- }
- }
-
- @Override
- public int getID() {
- return States.SPLASH;
- }
-
-}
diff --git a/src/Game/states/States.java b/src/Game/states/States.java
deleted file mode 100644
index 7161474..0000000
--- a/src/Game/states/States.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package game.states;
-
-public class States {
-
- public static final int GAME = 0;
- public static final int SPLASH = 1;
-
-}
diff --git a/src/Jq/CParser.hs b/src/Jq/CParser.hs
new file mode 100644
index 0000000..afeb6b3
--- /dev/null
+++ b/src/Jq/CParser.hs
@@ -0,0 +1,251 @@
+module Jq.CParser where
+
+import Control.Monad (join)
+import Jq.Filters
+import Jq.JParser
+import Jq.Json (JSON (JDouble, JString))
+import Parsing.Parsing
+
+parseIdentity :: Parser Filter
+parseIdentity = do
+ _ <- token . char $ '.'
+ return Identity
+
+parseIndexGeneric :: Parser Filter
+parseIndexGeneric = do
+ _ <- token . char $ '.'
+ _ <- char '['
+ index <- parseFilter
+ _ <- char ']'
+ return $ Index index
+
+parseIndex :: Parser Filter
+parseIndex = do
+ _ <- token . char $ '.'
+ index <- pString <|> some (alphanum <|> char '_')
+ return $ Index (Literal (JString index))
+
+parseIndexFull :: Parser Filter
+parseIndexFull = do
+ _ <- token . char $ '.'
+ _ <- symbol "["
+ _ <- symbol "]"
+ return IterateFull
+
+parseIndexIterator :: Parser Filter
+parseIndexIterator = do
+ _ <- token . char $ '.'
+ _ <- symbol "["
+ elements <-
+ many $
+ do
+ el <- int
+ _ <- symbol ","
+ return el
+ final <- int
+ _ <- symbol "]"
+ return $ IterateIndex (map (Literal . JDouble . fromIntegral) elements ++ [Literal $ JDouble (fromIntegral final)])
+
+parseIndexSlice :: Parser Filter
+parseIndexSlice =
+ do
+ _ <- token . char $ '.'
+ do
+ _ <- symbol "["
+ from <- integer
+ _ <- symbol ":"
+ to <- integer
+ _ <- symbol "]"
+ return $ IterateSlice from to
+ <|> do
+ _ <- symbol "["
+ from <- integer
+ _ <- symbol ":"
+ _ <- symbol "]"
+ return $ IterateSlice from maxBound
+ <|> do
+ _ <- symbol "["
+ _ <- symbol ":"
+ to <- integer
+ _ <- symbol "]"
+ return $ IterateSlice 0 to
+
+parseOptionalIndex :: Parser Filter
+parseOptionalIndex = do
+ _ <- token . char $ '.'
+ index <- anystring
+ _ <- char '?'
+ return $ OptionalIndex (Literal (JString index))
+
+parseOptionalIterateFull :: Parser Filter
+parseOptionalIterateFull = do
+ _ <- token . char $ '.'
+ _ <- symbol "["
+ _ <- symbol "]"
+ _ <- symbol "?"
+ return OptionalIterateFull
+
+parseOptionalIndexGeneric :: Parser Filter
+parseOptionalIndexGeneric = do
+ _ <- token . char $ '.'
+ _ <- symbol "["
+ index <- parseFilter
+ _ <- symbol "]"
+ _ <- symbol "?"
+ return $ OptionalIndex index
+
+parseOptionalIterateIndex :: Parser Filter
+parseOptionalIterateIndex = do
+ _ <- token . char $ '.'
+ _ <- symbol "["
+ elements <-
+ many $
+ do
+ el <- parseFilter
+ _ <- symbol ","
+ return el
+ final <- parseFilter
+ _ <- symbol "]"
+ _ <- symbol "?"
+ return $ OptionalIterateIndex (elements ++ [final])
+
+parseOptionalIndexSlice :: Parser Filter
+parseOptionalIndexSlice =
+ do
+ filt <- parseIndexSlice
+ _ <- symbol "?"
+ case filt of
+ IterateSlice from to -> return (OptionalIterateSlice from to)
+
+parseRecursiveDescent :: Parser Filter
+parseRecursiveDescent =
+ do
+ _ <- symbol ".."
+ return RecursiveDescent
+
+parseJqObject :: Parser Filter
+parseJqObject = do
+ _ <- char '{'
+ elements <-
+ many $
+ do
+ name <- pString <|> many (alphanum <|> char ' ' <|> char '_')
+ _ <- symbol ":"
+ value <- parseFilter
+ _ <- symbol ","
+ return (name, value)
+
+ name <- pString <|> many (alphanum <|> char ' ' <|> char '_')
+ _ <- symbol ":"
+ value <- parseFilter
+
+ _ <- char '}'
+ return $ Object (elements ++ [(name, value)])
+
+parseJqObjectEmpty :: Parser Filter
+parseJqObjectEmpty = do
+ _ <- symbol "{"
+ _ <- symbol "}"
+ return $ Object []
+
+parseJqArray :: Parser Filter
+parseJqArray = do
+ _ <- char '['
+ elements <-
+ many $
+ do
+ el <- parseFilter
+ _ <- char ','
+ return el
+ final <- parseFilter
+ _ <- char ']'
+ return $ Array (elements ++ [final])
+
+parseJqArrayEmpty :: Parser Filter
+parseJqArrayEmpty = do
+ _ <- symbol "["
+ _ <- symbol "]"
+ return $ Array []
+
+parseLiterals :: Parser Filter
+parseLiterals = do
+ Literal <$> (token parseJNull <|> parseJDouble <|> parseScientific <|> parseJNumber <|> parseJString <|> parseBool)
+
+parseIfThenElse :: Parser Filter
+parseIfThenElse = do
+ _ <- symbol "if"
+ x <- parseFilter
+ _ <- symbol "then"
+ y <- parseFilter
+ _ <- symbol "else"
+ z <- parseFilter
+ _ <- symbol "end"
+ return $ IfThenELse x y z
+
+parseBoolUniExpr :: Parser Filter
+parseBoolUniExpr = do
+ _ <- symbol "not"
+ return Not
+
+parseParens :: Parser Filter
+parseParens = do
+ _ <- symbol "("
+ x <- parseFilter
+ _ <- symbol ")"
+ return $ Parens x
+
+parseFilterHelper :: Parser Filter
+parseFilterHelper = parseOptionalIndexGeneric <|> parseOptionalIndexSlice <|> parseOptionalIterateIndex <|> parseOptionalIterateFull <|> parseOptionalIndex <|> parseIndexIterator <|> parseIndexFull <|> parseIndexGeneric <|> parseIndexSlice <|> parseIndex <|> parseJqObjectEmpty <|> parseJqObject <|> parseJqArrayEmpty <|> parseJqArray <|> parseRecursiveDescent <|> parseIdentity <|> parseLiterals <|> parseIfThenElse <|> parseBoolUniExpr <|> parseParens
+
+parseFilter :: Parser Filter
+parseFilter = do
+ first <- parseFilterHelper
+ join
+ ( do
+ _ <- symbol ","
+ return $ Comma first <$> parseFilter
+ <|> do
+ _ <- symbol "|"
+ return $ Pipe first <$> parseFilter
+ <|> do
+ _ <- symbol "*"
+ return $ Mul first <$> parseFilter
+ <|> do
+ _ <- symbol "/"
+ return $ Div first <$> parseFilter
+ <|> do
+ _ <- symbol "%"
+ return $ Mod first <$> parseFilter
+ <|> do
+ pure . Pipe first <$> parseFilter
+ <|> do
+ _ <- symbol "+"
+ return $ Add first <$> parseFilter
+ <|> do
+ _ <- symbol "-"
+ return $ Subs first <$> parseFilter
+ <|> do
+ _ <- symbol "and"
+ return $ And first <$> parseFilter
+ <|> do
+ _ <- symbol "or"
+ return $ Or first <$> parseFilter
+ <|> do
+ _ <- symbol "=="
+ return $ Eq first <$> parseFilter
+ <|> do
+ _ <- symbol "!="
+ return $ Neq first <$> parseFilter
+ <|> do
+ return $ pure first
+ )
+
+parseConfig :: [String] -> Either String Config
+parseConfig s = case s of
+ [] -> Left "No filters provided"
+ h : _ ->
+ case parse parseFilter h of
+ [(v, out)] -> case out of
+ [] -> Right . ConfigC $ v
+ _ -> Left $ "Compilation error, leftover: " ++ out
+ e -> Left $ "Compilation error: " ++ show e
diff --git a/src/Jq/Compiler.hs b/src/Jq/Compiler.hs
new file mode 100644
index 0000000..dcc92db
--- /dev/null
+++ b/src/Jq/Compiler.hs
@@ -0,0 +1,298 @@
+module Jq.Compiler where
+
+import Data.Ratio
+import Jq.Filters
+import Jq.Json
+
+type JProgram a = JSON -> Either String a
+
+compileIndex :: Filter -> JProgram [JSON]
+compileIndex (Index _) (JArray []) = Left "Index out of range"
+compileIndex (Index (Literal (JDouble 0))) (JArray (x : _)) = return [x]
+compileIndex (Index (Literal (JDouble index))) (JArray (_ : xs)) = compile (Index (Literal (JDouble (index - 1)))) (JArray xs)
+compileIndex (Index _) (JObject []) = return [JNull]
+compileIndex (Index (Literal (JString index))) (JObject (x : _)) | fst x == index = return [snd x]
+compileIndex (Index (Literal (JString index))) (JObject (_ : xs)) = compile (Index (Literal (JString index))) (JObject xs)
+compileIndex (Index (Index x)) inp = compileRecursiveIndex (Index (Index x)) inp
+compileIndex (Index (Pipe op1 op2)) inp = compileRecursiveIndex (Index (Pipe op1 op2)) inp
+compileIndex (Index (Comma op1 op2)) inp = compileRecursiveIndex (Index (Pipe op1 op2)) inp
+compileIndex (Index _) JNull = return [JNull]
+compileIndex (Index index) x = Left ("Failed to index: " ++ show x ++ "\n" ++ show index)
+compileIndex op x = Left ("Something went horribly wrong: " ++ show x ++ "\n" ++ show op)
+
+compileRecursiveIndex :: Filter -> JProgram [JSON]
+compileRecursiveIndex (Index x) inp = case compile x inp of
+ Left err -> Left err
+ Right [] -> return [JNull]
+ Right [res] -> compile (Index (Literal res)) inp
+ Right xs -> compileIterateIndex (IterateIndex (map Literal xs)) inp
+compileRecursiveIndex _ x = Left ("Something went horribly wrong: " ++ show x)
+
+compileIndexFull :: Filter -> JProgram [JSON]
+compileIndexFull IterateFull (JArray inp) = compileIterateIndex (IterateIndex (map (Literal . JDouble . fromIntegral) [0 .. (length inp - 1)])) (JArray inp)
+compileIndexFull IterateFull (JObject []) = return []
+compileIndexFull IterateFull (JObject ((_, value) : xs)) = case compileIndexFull IterateFull (JObject xs) of
+ Left x -> Left x
+ Right x -> return (value : x)
+compileIndexFull op x = Left ("Something went horribly wrong: " ++ show x ++ "\n" ++ show op)
+
+compileComma :: Filter -> JProgram [JSON]
+compileComma (Comma op1 op2) inp =
+ case (compile op1 inp, compile op2 inp) of
+ (Right x, Right y) -> return (x ++ y)
+ (Left x, _) -> Left x
+ (_, Left y) -> Left y
+compileComma _ inp = Left ("Something went horribly wrong: " ++ show inp)
+
+compilePipe :: Filter -> JProgram [JSON]
+compilePipe (Pipe op1 op2) inp =
+ case compile op1 inp of
+ Left y -> Left y
+ Right xs -> mapPipe op2 xs []
+compilePipe op inp = Left ("Something went horribly wrong: " ++ show inp ++ "\n" ++ show op)
+
+mapPipe :: Filter -> [JSON] -> [JSON] -> Either String [JSON]
+mapPipe _ [] res = return res
+mapPipe op (x : xs) res =
+ case compile op x of
+ Left compiled -> Left compiled
+ Right compiled -> mapPipe op xs (res ++ compiled)
+
+maxi :: [Filter] -> Int -> Int
+maxi [] curr_max = curr_max
+maxi ((Literal (JDouble y)) : xs) curr_max
+ | x > curr_max = maxi xs x
+ | otherwise = maxi xs curr_max
+ where
+ x = round y
+maxi _ _ = -1
+
+compileIterateIndex :: Filter -> JProgram [JSON]
+compileIterateIndex (IterateIndex xs) (JArray ys) =
+ return
+ [ if round i < 0
+ then ys !! (length ys + round i)
+ else ys !! round i
+ | (Literal (JDouble i)) <- xs,
+ round i < length ys
+ ]
+compileIterateIndex _ inp = Left ("Something went horribly wrong: " ++ show inp)
+
+compileIndexSlice :: Filter -> JProgram [JSON]
+compileIndexSlice (IterateSlice x y) (JArray xs) | from >= 0 = return [JArray (take (to - from) (drop from xs))]
+ where
+ from = if x >= 0 then x else length xs + x
+ to = if y >= 0 then y else length xs + y
+compileIndexSlice (IterateSlice x y) (JString xs) | from >= 0 = return [JString (take (to - from) (drop from xs))]
+ where
+ from = if x >= 0 then x else length xs - x
+ to = if y >= 0 then y else length xs - y
+compileIndexSlice _ inp = Left ("Something went horribly wrong: " ++ show inp)
+
+compileOptional :: Filter -> JProgram [JSON]
+compileOptional (OptionalIndex (Literal (JString str))) (JObject xs) = compileIndex (Index (Literal (JString str))) (JObject xs)
+compileOptional _ JNull = return [JNull]
+compileOptional _ _ = return []
+
+compileOptionalIterateFull :: Filter -> JProgram [JSON]
+compileOptionalIterateFull OptionalIterateFull (JArray xs) = compileIndexFull IterateFull (JArray xs)
+compileOptionalIterateFull OptionalIterateFull (JObject xs) = compileIndexFull IterateFull (JObject xs)
+compileOptionalIterateFull _ _ = return []
+
+compileOptionalIterateSlice :: Filter -> JProgram [JSON]
+compileOptionalIterateSlice (OptionalIterateSlice x y) (JArray xs) = compileIndexSlice (IterateSlice x y) (JArray xs)
+compileOptionalIterateSlice (OptionalIterateSlice x y) (JString xs) = compileIndexSlice (IterateSlice x y) (JString xs)
+compileOptionalIterateSlice _ JNull = return [JNull]
+compileOptionalIterateSlice _ _ = return []
+
+compileArray :: Filter -> JProgram [JSON]
+compileArray (Array (x : _)) inp = case compile x inp of
+ Left res -> Left res
+ Right res -> return [JArray res]
+compileArray (Array []) _ = return [JArray []]
+compileArray _ inp = Left ("Something went horribly wrong: " ++ show inp)
+
+compileObject :: Filter -> JProgram [JSON]
+compileObject (Object ((key, x) : _)) inp = case compile x inp of
+ Left res -> Left res
+ Right res -> return [JObject [(key, head res)]]
+compileObject (Object []) _ = return [JObject []]
+compileObject _ inp = Left ("Something went horribly wrong " ++ show inp)
+
+compileOptionalIterateIndex :: Filter -> JProgram [JSON]
+compileOptionalIterateIndex (OptionalIterateIndex xs) (JArray ys) = return [if round i < 0 then ys !! (length ys + round i) else ys !! round i | (Literal (JDouble i)) <- xs, round i < length ys]
+compileOptionalIterateIndex (OptionalIterateIndex xs) (JString ys) = case compileIterateIndex (IterateIndex xs) (JString ys) of
+ Left _ -> return [JNull]
+ Right x -> return x
+compileOptionalIterateIndex (OptionalIterateIndex _) JNull = return [JNull]
+compileOptionalIterateIndex (OptionalIterateIndex _) _ = return []
+compileOptionalIterateIndex _ inp = Left ("Something went horribly wrong " ++ show inp)
+
+compileRecursiveDescent :: Filter -> JProgram [JSON]
+compileRecursiveDescent RecursiveDescent (JArray xs) = case arr of
+ Left x -> Left x
+ Right ys -> return (JArray xs : concat ys)
+ where
+ arr = traverse (compileRecursiveDescent RecursiveDescent) xs
+compileRecursiveDescent RecursiveDescent (JObject xs) = case arr of
+ Left x -> Left x
+ Right ys -> return (JObject xs : concat ys)
+ where
+ arr = traverse (compileRecursiveDescent RecursiveDescent . snd) xs
+compileRecursiveDescent RecursiveDescent x = return [x]
+compileRecursiveDescent _ inp = Left ("Something went horribly wrong " ++ show inp)
+
+compileIfThenElse :: Filter -> JProgram [JSON]
+compileIfThenElse (IfThenELse x y z) inp = case compile x inp of
+ Left res -> Left res
+ Right xs -> ifThenElse xs y z inp []
+compileIfThenElse _ inp = Left ("Something went horribly wrong " ++ show inp)
+
+ifThenElse :: [JSON] -> Filter -> Filter -> JSON -> [JSON] -> Either String [JSON]
+ifThenElse [] _ _ _ ys = Right ys
+ifThenElse (x : xs) y z inp ys | x == JNull || x == JBool False = case compile z inp of
+ Left res -> Left res
+ Right res -> ifThenElse xs y z inp (res ++ ys)
+ifThenElse (_ : xs) y z inp ys = case compile y inp of
+ Left res -> Left res
+ Right res -> ifThenElse xs y z inp (res ++ ys)
+
+compileIntExpr :: Filter -> Filter -> Filter -> JProgram [JSON]
+compileIntExpr op op1 op2 inp = case compile op1 inp of
+ Left x -> Left x
+ Right left -> case compile op2 inp of
+ Left x -> Left x
+ Right right -> case op of
+ (Add _ _) -> addArithmExpr left right []
+ (Subs _ _) -> subtArithmExpr left right []
+ (Mul _ _) -> multArithmExpr left right []
+ (Div _ _) -> divArithmExpr left right []
+ (Mod _ _) -> modArithmExpr left right []
+ _ -> Left (show op ++ " Not yet implemented")
+
+addArithmExpr :: [JSON] -> [JSON] -> [JSON] -> Either String [JSON]
+addArithmExpr [] _ res = return res
+addArithmExpr _ [] res = return res
+addArithmExpr (x : xs) ys res = addArithmExpr xs ys (map (add x) ys ++ res)
+
+add :: JSON -> JSON -> JSON
+add (JDouble x) (JDouble y) = JDouble (x + y)
+add JNull y = y
+add x JNull = x
+add (JArray xs) (JArray ys) = JArray $ xs ++ ys
+add (JObject xs) (JObject ys) = JObject $ xs ++ ys
+
+subtArithmExpr :: [JSON] -> [JSON] -> [JSON] -> Either String [JSON]
+subtArithmExpr [] _ res = return res
+subtArithmExpr _ [] res = return res
+subtArithmExpr (x : xs) ys res = subtArithmExpr xs ys (map (subt x) ys ++ res)
+
+subt :: JSON -> JSON -> JSON
+subt (JDouble x) (JDouble y) = JDouble (x - y)
+subt JNull y = y
+subt x JNull = x
+
+multArithmExpr :: [JSON] -> [JSON] -> [JSON] -> Either String [JSON]
+multArithmExpr [] _ res = return res
+multArithmExpr _ [] res = return res
+multArithmExpr (x : xs) ys res = subtArithmExpr xs ys (map (mult x) ys ++ res)
+
+mult :: JSON -> JSON -> JSON
+mult (JDouble x) (JDouble y) = JDouble (x * y)
+mult JNull y = y
+mult x JNull = x
+
+divArithmExpr :: [JSON] -> [JSON] -> [JSON] -> Either String [JSON]
+divArithmExpr [] _ res = return res
+divArithmExpr _ [] res = return res
+divArithmExpr (x : xs) ys res = subtArithmExpr xs ys (map (divi x) ys ++ res)
+
+divi :: JSON -> JSON -> JSON
+divi (JDouble x) (JDouble y) = JDouble (x / y)
+divi JNull y = y
+divi x JNull = x
+
+modArithmExpr :: [JSON] -> [JSON] -> [JSON] -> Either String [JSON]
+modArithmExpr [] _ res = return res
+modArithmExpr _ [] res = return res
+modArithmExpr (x : xs) ys res = subtArithmExpr xs ys (map (subt x) ys ++ res)
+
+modu :: JSON -> JSON -> JSON
+modu (JDouble x) (JDouble y) = JDouble $ fromInteger (mod (round x) (round y))
+modu JNull y = y
+modu x JNull = x
+
+compileBoolExpr :: Filter -> JProgram [JSON]
+compileBoolExpr (Eq x y) inp = case compile x inp of
+ Left res1 -> Left res1
+ Right res1 -> case compile y inp of
+ Left res2 -> Left res2
+ Right res2 -> return [JBool (res1 == res2)]
+compileBoolExpr Not inp = return (notExpr [inp])
+compileBoolExpr (And x y) inp = case compile x inp of
+ Left res -> Left res
+ Right xs -> andExpr xs y inp []
+compileBoolExpr (Or x y) inp = case compile x inp of
+ Left res -> Left res
+ Right xs -> orExpr xs y inp []
+compileBoolExpr (Smaller x y) inp = case compile x inp of
+ Left res1 -> Left res1
+ Right res1 -> case compile y inp of
+ Left res2 -> Left res2
+ Right res2 -> return [JBool (sort res1 res2)]
+compileBoolExpr _ inp = Left ("Something went horribly wrong " ++ show inp)
+
+andExpr :: [JSON] -> Filter -> JSON -> [JSON] -> Either String [JSON]
+andExpr [] _ _ res = return res
+andExpr (x : xs) op inp res | x == JNull || x == JBool False = andExpr xs op inp (JBool False : res)
+andExpr (_ : xs) op inp res = case compile op inp of
+ Left ys -> Left ys
+ Right ys -> andExpr xs op inp (res ++ ys)
+
+orExpr :: [JSON] -> Filter -> JSON -> [JSON] -> Either String [JSON]
+orExpr [] _ _ res = return res
+orExpr (x : xs) op inp res | x == JNull || x == JBool False = case compile op inp of
+ Left ys -> Left ys
+ Right ys -> orExpr xs op inp (res ++ ys)
+orExpr (_ : xs) op inp res = orExpr xs op inp (JBool True : res)
+
+notExpr :: [JSON] -> [JSON]
+notExpr [] = []
+notExpr (x : xs) | x == JNull || x == JBool False = JBool True : notExpr xs
+notExpr (_ : xs) = JBool False : notExpr xs
+
+sort :: [JSON] -> [JSON] -> Bool
+sort xs ys = undefined
+
+compile :: Filter -> JProgram [JSON]
+compile Identity inp = return [inp]
+compile (Index x) inp = compileIndex (Index x) inp
+compile (Comma op1 op2) inp = compileComma (Comma op1 op2) inp
+compile (Pipe op1 op2) inp = compilePipe (Pipe op1 op2) inp
+compile (IterateIndex xs) inp = compileIterateIndex (IterateIndex xs) inp
+compile (IterateSlice from to) inp = compileIndexSlice (IterateSlice from to) inp
+compile (OptionalIterateSlice from to) inp = compileOptionalIterateSlice (OptionalIterateSlice from to) inp
+compile (OptionalIndex str) inp = compileOptional (OptionalIndex str) inp
+compile IterateFull inp = compileIndexFull IterateFull inp
+compile OptionalIterateFull inp = compileOptionalIterateFull OptionalIterateFull inp
+compile (OptionalIterateIndex x) inp = compileOptionalIterateIndex (OptionalIterateIndex x) inp
+compile RecursiveDescent inp = compileRecursiveDescent RecursiveDescent inp
+compile (IfThenELse x y z) inp = compileIfThenElse (IfThenELse x y z) inp
+compile (Array xs) inp = compileArray (Array xs) inp
+compile (Object xs) inp = compileObject (Object xs) inp
+compile (Literal x) _ = return [x]
+compile (Add op1 op2) inp = compileIntExpr (Add op1 op2) op1 op2 inp
+compile (Subs op1 op2) inp = compileIntExpr (Subs op1 op2) op1 op2 inp
+compile (Mul op1 op2) inp = compileIntExpr (Mul op1 op2) op1 op2 inp
+compile (Div op1 op2) inp = compileIntExpr (Div op1 op2) op1 op2 inp
+compile (Mod op1 op2) inp = compileIntExpr (Mod op1 op2) op1 op2 inp
+compile (Neq x y) inp = compile (Pipe (Eq x y) Not) inp
+compile (Eq x y) inp = compileBoolExpr (Eq x y) inp
+compile (And x y) inp = compileBoolExpr (And x y) inp
+compile (Or x y) inp = compileBoolExpr (Or x y) inp
+compile Not inp = compileBoolExpr Not inp
+compile (Parens op) inp = compile op inp
+compile _ _ = Left "Not yet implemented"
+
+run :: JProgram [JSON] -> JSON -> Either String [JSON]
+run p j = p j
diff --git a/src/Jq/Filters.hs b/src/Jq/Filters.hs
new file mode 100644
index 0000000..5f9f425
--- /dev/null
+++ b/src/Jq/Filters.hs
@@ -0,0 +1,100 @@
+module Jq.Filters where
+
+import Jq.Json (JSON (JString), indent, prettyPrintJSON)
+
+data Filter
+ = Identity
+ | Index Filter
+ | IterateIndex [Filter]
+ | IterateSlice Int Int
+ | IterateFull
+ | OptionalIndex Filter
+ | OptionalIterateFull
+ | OptionalIterateIndex [Filter]
+ | OptionalIterateSlice Int Int
+ | RecursiveDescent
+ | Pipe Filter Filter
+ | Comma Filter Filter
+ | IfThenELse Filter Filter Filter
+ | TryCatch Filter Filter
+ | Array [Filter]
+ | Object [([Char], Filter)]
+ | Literal JSON
+ | Add Filter Filter
+ | Subs Filter Filter
+ | Div Filter Filter
+ | Mul Filter Filter
+ | Mod Filter Filter
+ | Neq Filter Filter
+ | Eq Filter Filter
+ | Smaller Filter Filter
+ | And Filter Filter
+ | Or Filter Filter
+ | Not
+ | Parens Filter
+
+instance Show Filter where
+ show Identity = "."
+ show (Index x) = ".[" ++ show x ++ "]"
+ show (IterateIndex []) = ".[]"
+ show (IterateIndex (x : xs)) = ".[" ++ show x ++ foldr (\el res -> res ++ ", " ++ show el) "" xs ++ "]"
+ show (IterateSlice x y) = ".[" ++ show x ++ ":" ++ show y ++ "]"
+ show (OptionalIterateSlice x y) = show (IterateSlice x y) ++ "?"
+ show (Pipe x y) = show x ++ " | " ++ show y
+ show (Comma x y) = show x ++ " , " ++ show y
+ show (IfThenELse x y z) = "if " ++ show x ++ " then " ++ show y ++ " else " ++ show z
+ show (TryCatch x y) = "try " ++ show x ++ " catch " ++ show y
+ show (OptionalIndex str) = ".[\"" ++ show str ++ "\"]"
+ show IterateFull = ".[]"
+ show OptionalIterateFull = ".[]?"
+ show RecursiveDescent = ".."
+ show (Literal x) = show x
+ show (Array xs) = prettyPrintJq (Array xs) ""
+ show (Object xs) = prettyPrintJq (Object xs) ""
+ show (OptionalIterateIndex xs) = show (IterateIndex xs) ++ "?"
+ show (Neq x y) = show x ++ " != " ++ show y
+ show (Eq x y) = show x ++ " == " ++ show y
+ show (Smaller x y) = show x ++ " < " ++ show y
+ show (And x y) = show x ++ " and " ++ show y
+ show (Or x y) = show x ++ " or " ++ show y
+ show Not = "not "
+ show (Add op1 op2) = show op1 ++ " + " ++ show op2
+ show (Subs op1 op2) = show op1 ++ " - " ++ show op2
+ show (Div op1 op2) = show op1 ++ " / " ++ show op2
+ show (Mul op1 op2) = show op1 ++ " * " ++ show op2
+ show (Mod op1 op2) = show op1 ++ " % " ++ show op2
+ show (Parens op) = "(" ++ show op ++ ")"
+
+instance Eq Filter where
+ Identity == Identity = True
+ (Index x) == (Index y) = x == y
+ (Pipe xop1 xop2) == (Pipe yop1 yop2) = (xop1 == yop1) && (xop2 == yop2)
+ (Comma xop1 xop2) == (Comma yop1 yop2) = (xop1 == yop1) && (xop2 == yop2)
+ -- TODO
+ _ == _ = False
+
+prettyPrintJq :: Filter -> [Char] -> [Char]
+prettyPrintJq (Array (x : xs)) ind = "[\n" ++ ind ++ " " ++ show x ++ foldl (\res i -> res ++ ",\n " ++ ind ++ prettyPrintJq (xs !! i) (indent ++ ind)) "" [0 .. length xs - 1] ++ "\n" ++ ind ++ "]"
+prettyPrintJq (Object (x : xs)) ind = "{\n" ++ indent ++ ind ++ "\"" ++ fst x ++ "\": " ++ prettyPrintJq (snd x) (ind ++ indent) ++ foldl (\res (key, value) -> res ++ ",\n" ++ indent ++ ind ++ "\"" ++ key ++ "\": " ++ prettyPrintJq value (ind ++ indent)) "" xs ++ "\n" ++ ind ++ "}"
+prettyPrintJq (Literal x) ind = prettyPrintJSON x ind
+prettyPrintJq x _ = show x
+
+data Config = ConfigC {filters :: Filter}
+
+-- Smart constructors
+-- These are included for test purposes and
+-- aren't meant to correspond one to one with actual constructors you add to Filter
+-- For the tests to succeed fill them in with functions that return correct filters
+-- Don't change the names or signatures, only the definitions
+
+filterIdentitySC :: Filter
+filterIdentitySC = Identity
+
+filterStringIndexingSC :: String -> Filter
+filterStringIndexingSC x = Index $ Literal (JString x)
+
+filterPipeSC :: Filter -> Filter -> Filter
+filterPipeSC = Pipe
+
+filterCommaSC :: Filter -> Filter -> Filter
+filterCommaSC = Comma
diff --git a/src/Jq/JParser.hs b/src/Jq/JParser.hs
new file mode 100644
index 0000000..9930a29
--- /dev/null
+++ b/src/Jq/JParser.hs
@@ -0,0 +1,117 @@
+module Jq.JParser where
+
+import Control.Monad (join)
+import Jq.Json
+import Parsing.Parsing
+
+parseJNull :: Parser JSON
+parseJNull = do
+ _ <- string "null"
+ return JNull
+
+parseJNumber :: Parser JSON
+parseJNumber = do
+ number <- integer
+ return $ JDouble $ fromIntegral number
+
+parseJDouble :: Parser JSON
+parseJDouble = do
+ first <- integer
+ _ <- char '.'
+ second <- nat
+ if second == 0 then return $ JDouble (fromIntegral first) else return $ JDouble (fromIntegral first + sign first * fromIntegral second * (10 ** order second)) -- Weird hacking dw about it
+ where
+ order x = -1 - fromIntegral (floor (logBase 10.0 (fromIntegral x)))
+ sign x = if x >= 0 then 1 else -1
+
+parseScientific :: Parser JSON
+parseScientific = do
+ first <- integer
+ _ <- char 'E'
+ do
+ second <- integer
+ return $
+ JDouble (fromIntegral first * (10 ** fromIntegral second))
+ <|> do
+ _ <- symbol "+"
+ second <- integer
+ return $
+ JDouble (fromIntegral first * (10 ** fromIntegral second))
+ <|> do
+ _ <- symbol "-"
+ second <- integer
+ return $
+ JDouble (fromIntegral first * (10 ** (-fromIntegral second)))
+
+parseJString :: Parser JSON
+parseJString = do
+ JString <$> pString
+
+parseBool :: Parser JSON
+parseBool = do
+ parseTrue <|> parseFalse
+
+parseTrue :: Parser JSON
+parseTrue = do
+ _ <- string "true"
+ return $ JBool True
+
+parseFalse :: Parser JSON
+parseFalse = do
+ _ <- string "false"
+ return $ JBool False
+
+parseArray :: Parser JSON
+parseArray = do
+ parseArrayEmpty <|> parseArrayFull
+
+parseArrayEmpty :: Parser JSON
+parseArrayEmpty = do
+ _ <- char '['
+ _ <- char ']'
+ return $ JArray []
+
+parseArrayFull :: Parser JSON
+parseArrayFull = do
+ _ <- char '['
+ elements <-
+ many $
+ do
+ el <- parseJSON
+ _ <- char ','
+ return el
+ final <- parseJSON
+ _ <- char ']'
+ return $ JArray $ elements ++ [final]
+
+parseObject :: Parser JSON
+parseObject = do
+ parseObjectEmpty <|> parseObjectFull
+
+parseObjectFull :: Parser JSON
+parseObjectFull = do
+ _ <- char '{'
+ elements <-
+ many $
+ do
+ name <- pString
+ _ <- symbol ":"
+ value <- parseJSON
+ _ <- symbol ","
+ return (name, value)
+
+ name <- pString
+ _ <- symbol ":"
+ value <- parseJSON
+
+ _ <- char '}'
+ return $ JObject (elements ++ [(name, value)])
+
+parseObjectEmpty :: Parser JSON
+parseObjectEmpty = do
+ _ <- char '{'
+ _ <- char '}'
+ return $ JObject []
+
+parseJSON :: Parser JSON
+parseJSON = token $ parseJNull <|> parseJDouble <|> parseScientific <|> parseJNumber <|> parseJString <|> parseBool <|> parseArray <|> parseObject
diff --git a/src/Jq/Json.hs b/src/Jq/Json.hs
new file mode 100644
index 0000000..3866e21
--- /dev/null
+++ b/src/Jq/Json.hs
@@ -0,0 +1,67 @@
+module Jq.Json where
+
+data JSON
+ = JNull
+ | JDouble Double
+ | JString [Char]
+ | JBool Bool
+ | JArray [JSON]
+ | JObject [([Char], JSON)]
+
+instance Show JSON where
+ show JNull = "null"
+ show (JDouble x) = if x == fromInteger (round x) then show (round x) else show x
+ show (JString x) = "\"" ++ x ++ "\""
+ show (JBool True) = "true"
+ show (JBool False) = "false"
+ show (JArray []) = "[]"
+ show (JArray (x : xs)) = prettyPrintJSON (JArray (x : xs)) ""
+ show (JObject []) = "{}"
+ show (JObject (x : xs)) = prettyPrintJSON (JObject (x : xs)) ""
+
+instance Eq JSON where
+ JNull == JNull = True
+ (JDouble x) == (JDouble y) = x == y
+ (JString x) == (JString y) = x == y
+ (JBool x) == (JBool y) = x == y
+ (JArray []) == (JArray []) = True
+ (JArray []) == (JArray _) = False
+ (JArray _) == (JArray []) = False
+ (JArray (x : xs)) == (JArray (y : ys)) = x == y && JArray xs == JArray ys
+ (JObject []) == (JObject []) = True
+ (JObject []) == (JObject _) = False
+ (JObject _) == (JObject []) = False
+ (JObject (x : xs)) == (JObject (y : ys)) = fst x == fst y && snd x == snd y && xs == ys
+ _ == _ = False
+
+prettyPrintJSON :: JSON -> String -> [Char]
+prettyPrintJSON (JArray (x : xs)) ind = "[\n" ++ ind ++ " " ++ prettyPrintJSON x (ind ++ indent) ++ foldl (\res i -> res ++ ",\n " ++ ind ++ prettyPrintJSON (xs !! i) (indent ++ ind)) "" [0 .. length xs - 1] ++ "\n" ++ ind ++ "]"
+prettyPrintJSON (JObject (x : xs)) ind = "{\n" ++ indent ++ ind ++ "\"" ++ fst x ++ "\": " ++ prettyPrintJSON (snd x) (ind ++ indent) ++ foldl (\res (key, value) -> res ++ ",\n" ++ indent ++ ind ++ "\"" ++ key ++ "\": " ++ prettyPrintJSON value (ind ++ indent)) "" xs ++ "\n" ++ ind ++ "}"
+prettyPrintJSON x _ = show x
+
+indent :: [Char]
+indent = " "
+
+-- Smart constructors
+-- These are included for test purposes and
+-- aren't meant to correspond one to one with actual constructors you add to JSON datatype
+-- For the tests to succeed fill them in with functions that return correct JSON values
+-- Don't change the names or signatures, only the definitions
+
+jsonNullSC :: JSON
+jsonNullSC = JNull
+
+jsonNumberSC :: Int -> JSON
+jsonNumberSC = JDouble . fromIntegral
+
+jsonStringSC :: String -> JSON
+jsonStringSC = JString
+
+jsonBoolSC :: Bool -> JSON
+jsonBoolSC = JBool
+
+jsonArraySC :: [JSON] -> JSON
+jsonArraySC = JArray
+
+jsonObjectSC :: [(String, JSON)] -> JSON
+jsonObjectSC = JObject
diff --git a/src/Jq/Main.hs b/src/Jq/Main.hs
new file mode 100644
index 0000000..ea92df4
--- /dev/null
+++ b/src/Jq/Main.hs
@@ -0,0 +1,38 @@
+module Jq.Main (main, process) where
+
+import Control.Arrow (left)
+import Jq.Compiler
+import Jq.Filters (filters)
+import Jq.Parser
+import System.Environment (getArgs)
+
+readInput :: IO String
+readInput = getContents
+
+process :: [String] -> String -> Either String String
+process args json = do
+ v <- parseConfig $ args
+ obj <- maybe (Left ("Couldn't parse JSON" ++ show json)) Right $ parse parseJSON $ json
+ let program = compile . filters $ v
+ res <- left ("Couldn't execute the program: " ++) $ run program obj
+ return $ concat . map ((++ "\n") . show) $ res
+
+processIO :: [String] -> String -> IO (Either String ())
+processIO c s = do
+ case (process c s) of
+ Left e -> return $ Left e
+ Right v -> do putStr v; return $ Right ()
+
+getInputs :: IO ([String], String)
+getInputs = do
+ args <- getArgs
+ toparse <- readInput
+ return $ (args, toparse)
+
+main :: IO ()
+main = do
+ (args, inp) <- getInputs
+ v <- processIO args inp
+ case v of
+ Left s -> putStrLn s
+ _ -> return ()
diff --git a/src/Jq/Parser.hs b/src/Jq/Parser.hs
new file mode 100644
index 0000000..df3de23
--- /dev/null
+++ b/src/Jq/Parser.hs
@@ -0,0 +1,10 @@
+module Jq.Parser (module Jq.JParser, module Jq.CParser, parse) where
+
+import qualified Parsing.Parsing as P (Parser, parse)
+import Jq.JParser
+import Jq.CParser
+
+parse :: P.Parser a -> String -> Maybe a
+parse p s = case (P.parse p s) of
+ [(v, "")] -> Just v
+ _ -> Nothing
diff --git a/src/Parsing/Parsing.hs b/src/Parsing/Parsing.hs
new file mode 100644
index 0000000..f4d526e
--- /dev/null
+++ b/src/Parsing/Parsing.hs
@@ -0,0 +1,201 @@
+{-# OPTIONS_GHC -w #-}
+
+-- Functional parsing library from chapter 13 of Programming in Haskell,
+-- Graham Hutton, Cambridge University Press, 2016.
+
+module Parsing.Parsing (module Parsing.Parsing, module Control.Applicative) where
+
+import Control.Applicative
+import Data.Char
+
+-- Basic definitions
+
+newtype Parser a = P (String -> [(a, String)])
+
+parse :: Parser a -> String -> [(a, String)]
+parse (P p) inp = p inp
+
+item :: Parser Char
+item =
+ P
+ ( \inp -> case inp of
+ [] -> []
+ (x : xs) -> [(x, xs)]
+ )
+
+-- Sequencing parsers
+
+instance Functor Parser where
+ -- fmap :: (a -> b) -> Parser a -> Parser b
+ fmap g p =
+ P
+ ( \inp -> case parse p inp of
+ [] -> []
+ [(v, out)] -> [(g v, out)]
+ )
+
+instance Applicative Parser where
+ -- pure :: a -> Parser a
+ pure v = P (\inp -> [(v, inp)])
+
+ -- <*> :: Parser (a -> b) -> Parser a -> Parser b
+ pg <*> px =
+ P
+ ( \inp -> case parse pg inp of
+ [] -> []
+ [(g, out)] -> parse (fmap g px) out
+ )
+
+instance Monad Parser where
+ -- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
+ p >>= f =
+ P
+ ( \inp -> case parse p inp of
+ [] -> []
+ [(v, out)] -> parse (f v) out
+ )
+
+-- Making choices
+
+instance Alternative Parser where
+ -- empty :: Parser a
+ empty = P (\inp -> [])
+
+ -- (<|>) :: Parser a -> Parser a -> Parser a
+ p <|> q =
+ P
+ ( \inp -> case parse p inp of
+ [] -> parse q inp
+ [(v, out)] -> [(v, out)]
+ )
+
+-- Derived primitives
+
+sat :: (Char -> Bool) -> Parser Char
+sat p = do
+ x <- item
+ if p x then return x else empty
+
+digit :: Parser Char
+digit = sat isDigit
+
+lower :: Parser Char
+lower = sat isLower
+
+upper :: Parser Char
+upper = sat isUpper
+
+letter :: Parser Char
+letter = sat isAlpha
+
+alphanum :: Parser Char
+alphanum = sat isAlphaNum
+
+char :: Char -> Parser Char
+char x = sat (== x)
+
+string :: String -> Parser String
+string [] = return []
+string (x : xs) = do
+ char x
+ string xs
+ return (x : xs)
+
+ident :: Parser String
+ident = do
+ x <- lower
+ xs <- many (alphanum <|> char '_')
+ return (x : xs)
+
+nat :: Parser Int
+nat = do
+ xs <- some digit
+ return (read xs)
+
+int :: Parser Int
+int =
+ do
+ char '-'
+ n <- nat
+ return (-n)
+ <|> nat
+
+-- Handling spacing
+
+space :: Parser ()
+space = do
+ many (sat isSpace)
+ return ()
+
+token :: Parser a -> Parser a
+token p = do
+ space
+ v <- p
+ space
+ return v
+
+identifier :: Parser String
+identifier = token ident
+
+natural :: Parser Int
+natural = token nat
+
+integer :: Parser Int
+integer = token int
+
+symbol :: String -> Parser String
+symbol xs = token (string xs)
+
+anystring :: Parser String
+anystring = many (alphanum <|> char '_' <|> char ' ')
+
+uni :: Int -> [Char] -> Int
+uni _ [] = 0
+uni pow (x : xs) = (digitToInt x * 16 ^ pow) + uni (pow + 1) xs
+
+parseUnicode :: Parser String
+parseUnicode =
+ do
+ string "\\u"
+ a <- alphanum
+ b <- alphanum
+ c <- alphanum
+ d <- alphanum
+ str <- parseString
+ return (toEnum (uni 0 [d, c, b, a]) : str)
+
+anystr :: Parser String
+anystr =
+ do
+ char <- item <|> char ' '
+ str <- parseString
+ return (char : str)
+
+parseString :: Parser String
+parseString =
+ do
+ parseUnicode <|> escapeString <|> closeString <|> anystr
+
+escapeString :: Parser String
+escapeString =
+ do
+ _ <- char '\\'
+ escaped <- char '\"' <|> char 'r' <|> char 'n' <|> char 't' <|> char 'b' <|> char 'f'
+ str <- parseString
+ return (['\\', escaped] ++ str)
+
+pString :: Parser String
+pString =
+ do
+ _ <- openString
+ parseString
+
+openString :: Parser ()
+openString = do
+ _ <- char '"'
+ return ()
+
+closeString :: Parser String
+closeString = do
+ _ <- char '"'
+ return []
diff --git a/src/assets/Images.java b/src/assets/Images.java
deleted file mode 100644
index 174ecb9..0000000
--- a/src/assets/Images.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package assets;
-
-import game.Camera;
-import org.newdawn.slick.Image;
-import org.newdawn.slick.SlickException;
-import util.Strings;
-import world.Tile;
-
-import java.util.HashMap;
-
-public class Images {
-
- private static HashMap images = new HashMap<>();
-
- public static Image getImage(String name) {
- String path = Strings.imagePath + name + ".png";
- if (images.containsKey(name))
- return images.get(name);
- else
- try {
- Image image = new Image(path, false, Image.FILTER_NEAREST);
- images.put(name, image);
- return image;
- } catch (SlickException e) {
- e.printStackTrace();
- }
-
- System.err.println("Image " + name + " not found");
- System.exit(-1);
- return null;
- }
-
- public static void drawImage(String name, int x, int y) {
- drawImage(getImage(name), x, y);
- }
-
- public static void drawImage(Image image, int x, int y) {
- float absX = (x + Camera.position.x) * Tile.getTileSize();
- float absY = (y + Camera.position.y) * Tile.getTileSize();
- /*boolean clip = absX < 0 || absX >= Window.getWidth() || absY < 0 || absY >= Window.getHeight();
- if (!clip) {*/
- image.draw(absX, absY, (float) (Tile.getTileSize() / image.getWidth()));
- //}
- }
-}
diff --git a/src/assets/Sounds.java b/src/assets/Sounds.java
deleted file mode 100644
index ff7ea97..0000000
--- a/src/assets/Sounds.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package assets;
-
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.Sound;
-import util.Strings;
-
-import java.util.HashMap;
-
-public class Sounds {
-
- private static HashMap sounds = new HashMap<>();
-
- public static Sound getSound(String name) {
- String path = Strings.audioPath + name + ".wav";
- if (sounds.containsKey(name))
- return sounds.get(name);
- else
- try {
- Sound audio = new Sound(path);
- sounds.put(name, audio);
- return audio;
- } catch (SlickException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-}
diff --git a/src/entities/Entity.java b/src/entities/Entity.java
deleted file mode 100644
index 7680c44..0000000
--- a/src/entities/Entity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package entities;
-
-import assets.Images;
-import math.Vector2i;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Image;
-import org.newdawn.slick.state.StateBasedGame;
-import world.Tile;
-
-public abstract class Entity {
-
- public Vector2i position;
- private Image image;
-
- public Entity(Vector2i position, String imageName) {
- this.position = position;
- this.image = Images.getImage(imageName);
- }
-
- public abstract void update(GameContainer gc, StateBasedGame s, int delta);
-
- public void render(GameContainer gc, StateBasedGame s, Graphics g) {
- Images.drawImage(image, position.x, position.y);
- }
-
-}
\ No newline at end of file
diff --git a/src/entities/Worker.java b/src/entities/Worker.java
deleted file mode 100644
index 35d2532..0000000
--- a/src/entities/Worker.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package entities;
-
-import jobSystem.Job;
-import jobSystem.JobManager;
-import math.Vector2i;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.state.StateBasedGame;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Worker extends Entity {
-
- public Job currentJob;
-
- private List pathToTarget = new ArrayList<>();
-
- public float speed = 0.0001f;
-
- public Worker(Vector2i position) {
- super(position, "guy");
- }
-
- @Override
- public void update(GameContainer gc, StateBasedGame s, int delta) {
- updateJob(gc, s, delta);
- }
-
- private int totDelta = 0;
-
- private void updateJob(GameContainer gc, StateBasedGame s, int delta) {
- totDelta += delta;
- if (totDelta >= speed * 100) {
- if (currentJob != null)
- if (currentJob.executePosition != null)
- if (pathToTarget.isEmpty()) {
- if (currentJob.executeTime <= 0) {
- if (!tryExecuteJob()) {
- JobManager.moveJovBack(currentJob);
- currentJob = null;
- }
- } else
- currentJob.executeTime -= delta;
- } else {
- position = pathToTarget.get(pathToTarget.size() - 1);
- pathToTarget.remove(pathToTarget.size() - 1);
- }
- totDelta = 0;
- }
- }
-
- private boolean tryExecuteJob() {
- if (position.equals(currentJob.executePosition)) {
- executeJob();
- return true;
- }
- return false;
- }
-
- public void setJob(Job job, List path) {
- currentJob = job;
- pathToTarget = path;
- }
-
- private void executeJob() {
- pathToTarget.clear();
- JobManager.executeJob(currentJob);
- currentJob = null;
- }
-}
\ No newline at end of file
diff --git a/src/entities/pathfinding/Node.java b/src/entities/pathfinding/Node.java
deleted file mode 100644
index 0e255db..0000000
--- a/src/entities/pathfinding/Node.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package entities.pathfinding;
-
-import math.Vector2i;
-
-public class Node {
-
- public Vector2i position;
- public Node parent;
- public double fCost, gCost, hCost;
-
- public Node(Vector2i tile, Node parent, double gCost, double hCost) {
- this.position = tile;
- this.parent = parent;
- this.gCost = gCost;
- this.hCost = hCost;
- this.fCost = this.gCost + this.hCost;
- }
-
-}
diff --git a/src/entities/pathfinding/Pathfinder.java b/src/entities/pathfinding/Pathfinder.java
deleted file mode 100644
index d9e85a6..0000000
--- a/src/entities/pathfinding/Pathfinder.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package entities.pathfinding;
-
-import entities.Entity;
-import math.Vector2i;
-import world.World;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class Pathfinder {
-
- private static Comparator nodeSorter = new Comparator() {
- @Override
- public int compare(Node n0, Node n1) {
- if (n1.fCost < n0.fCost)
- return +1;
- if (n1.fCost > n0.fCost)
- return -1;
- return 0;
- }
- };
-
- public static List findPath(Entity entity, Vector2i target) {
- return findPath(entity.position, target);
- }
-
- public static List findPath(Vector2i start, Vector2i target) {
- if (start == null || target == null)
- System.err.println("start position or target position is null");
- if (!World.isWalkable(target.x, target.y))
- return new ArrayList<>();
- List openList = new ArrayList<>();
- List closedList = new ArrayList<>();
- Node current = new Node(start, null, 0, start.distance(target));
- openList.add(current);
- while (openList.size() > 0) {
- Collections.sort(openList, nodeSorter);
- current = openList.get(0);
- if (current.position.equals(target)) {
- List path = new ArrayList<>();
- while (current.parent != null) {
- path.add(current.position);
- current = current.parent;
- }
- openList.clear();
- closedList.clear();
- return path;
- }
- openList.remove(current);
- closedList.add(current);
- for (int i = 0; i < 9; i++) {
- if (i == 4 || i == 0 || i == 2 || i == 6 || i == 8)
- continue;
- int x = current.position.x;
- int y = current.position.y;
- int xi = (i % 3) - 1;
- int yi = (i / 3) - 1;
- if (!World.isWalkable(x + xi, y + yi))
- continue;
- Vector2i a = new Vector2i(x + xi, y + yi);
- double gCost = current.gCost + current.position.distance(a);
- double hCost = a.distance(target);
- Node node = new Node(a, current, gCost, hCost);
- if (vecInList(closedList, a) && gCost >= node.gCost)
- continue;
- if (!vecInList(openList, a) || gCost < node.gCost)
- openList.add(node);
- }
- }
- closedList.clear();
- return new ArrayList<>();
- }
-
- private static boolean vecInList(List list, Vector2i vector) {
- for (Node node : list)
- if (node.position.equals(vector))
- return true;
- return false;
- }
-
-}
diff --git a/src/exe/Main.hs b/src/exe/Main.hs
new file mode 100644
index 0000000..f8b1023
--- /dev/null
+++ b/src/exe/Main.hs
@@ -0,0 +1,6 @@
+module Main where
+
+import qualified Jq.Main as J (main)
+
+main :: IO ()
+main = J.main
diff --git a/src/game/Camera.java b/src/game/Camera.java
deleted file mode 100644
index ecb2152..0000000
--- a/src/game/Camera.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package game;
-
-import math.Vector2i;
-
-public class Camera {
-
- public static Vector2i position = new Vector2i(0, 0);
- public static float zoom = 0;
- public static final float MAX_ZOOM = 20f;
- public static final float MIN_ZOOM = 0;
-
- public static void setZoom(float value) {
- if (value > MAX_ZOOM) zoom = MAX_ZOOM;
- else if (value < MIN_ZOOM) zoom = MIN_ZOOM;
- else zoom = value;
- }
-
- public static void zoomIn() {
- setZoom(zoom + 1);
- }
-
- public static void zoomOut() {
- setZoom(zoom - 1);
- }
-}
diff --git a/src/game/Debug.java b/src/game/Debug.java
deleted file mode 100644
index 1d59e3d..0000000
--- a/src/game/Debug.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package game;
-
-import jobSystem.JobManager;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.state.StateBasedGame;
-import world.World;
-
-public class Debug {
-
- private boolean enabled = false;
- private boolean stableFPS = true;
- private int delta;
-
- public void updateDebug(GameContainer gc, StateBasedGame s, int delta) {
- this.delta = delta;
- if (gc.getInput().isKeyPressed(Input.KEY_G) && gc.getInput().isKeyPressed(Input.KEY_TAB))
- enabled = !enabled;
- if (gc.getInput().isKeyPressed(Input.KEY_F) && enabled) {
- stableFPS = !stableFPS;
- gc.setTargetFrameRate(stableFPS ? 60 : 0);
- }
- }
-
- public void renderDebug(GameContainer gc, StateBasedGame s, Graphics g) {
- int yOffset = 20;
- if (enabled) {
- int y = -yOffset;
- g.drawString("FPS: " + gc.getFPS(), 0, y += yOffset);
- g.drawString("Delta: " + delta, 0, y += yOffset);
- g.drawString("Tile amount: " + World.tiles.length, 0, y += yOffset);
- g.drawString("WorldObject amount: " + World.getWorldObjectAmount(), 0, y += yOffset);
- g.drawString("Worker amount: " + JobManager.workers.size(), 0, y += yOffset);
- g.drawString("Job amount: " + JobManager.jobs.size(), 0, y += yOffset);
- }
- }
-}
diff --git a/src/jobSystem/Job.java b/src/jobSystem/Job.java
deleted file mode 100644
index 6359a00..0000000
--- a/src/jobSystem/Job.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package jobSystem;
-
-import math.Vector2i;
-import world.World;
-
-public abstract class Job {
-
- // tile of block
- public Vector2i targetPosition;
- // tile of player
- public Vector2i executePosition;
-
- public int executeTime = 200;
-
- public Job(Vector2i targetPosition, int executeTime) {
- this.targetPosition = targetPosition;
- this.executePosition = getExecutePosition(targetPosition);
- this.executeTime = executeTime;
- }
-
- public abstract boolean checkRequirements();
-
- public abstract void onCreated();
-
- public abstract void execute();
-
- public static Vector2i getExecutePosition(Vector2i pos) {
- if (World.isWalkable(pos.x, pos.y - 1))
- return new Vector2i(pos.x, pos.y - 1);
- if (World.isWalkable(pos.x + 1, pos.y))
- return new Vector2i(pos.x + 1, pos.y);
- if (World.isWalkable(pos.x, pos.y + 1))
- return new Vector2i(pos.x, pos.y + 1);
- if (World.isWalkable(pos.x - 1, pos.y))
- return new Vector2i(pos.x - 1, pos.y);
- return null;
- }
-
-}
diff --git a/src/jobSystem/JobManager.java b/src/jobSystem/JobManager.java
deleted file mode 100644
index 698bfad..0000000
--- a/src/jobSystem/JobManager.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package jobSystem;
-
-import assets.Images;
-import entities.Worker;
-import entities.pathfinding.Pathfinder;
-import math.Vector2i;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.state.StateBasedGame;
-import world.Tile;
-
-import java.util.ArrayList;
-import java.util.Stack;
-
-public class JobManager {
-
- public static Stack jobs = new Stack<>();
- public static ArrayList workers = new ArrayList<>();
-
- public static void addWorker(Worker worker) {
- workers.add(worker);
- }
-
- public static void addJob(Job job) {
- if (job.checkRequirements())
- if (!isJobAtPosition(job.targetPosition.x, job.targetPosition.y))
- jobs.add(job);
- }
-
- private static boolean isJobAtPosition(int x, int y) {
- for (Job job : jobs)
- if (job.targetPosition.x == x && job.targetPosition.y == y)
- return true;
- return false;
- }
-
- public static void update(GameContainer gc, StateBasedGame s, int delta) {
- if (!jobs.isEmpty()) {
- for (Worker worker : workers) {
- if (worker.currentJob == null) {
- Job current = getClosestJob(worker.position);
- if (current.checkRequirements()) {
- if (current.executePosition != null) {
- worker.setJob(current, Pathfinder.findPath(worker, current.executePosition));
- } else {
- jobs.remove(current);
- jobs.add(current);
- }
- }
- }
- }
- }
- updateWorkers(gc, s, delta);
- }
-
- public static void moveJovBack(Job job) {
- JobManager.jobs.remove(job);
- JobManager.jobs.add(job);
- }
-
- private static Job getClosestJob(Vector2i pos) {
- Job closest = jobs.get(0);
- for (Job job : jobs) {
- job.executePosition = Job.getExecutePosition(job.targetPosition);
- if (job.executePosition != null && pos != null && closest.executePosition != null && job.checkRequirements())
- if (pos.distance(job.executePosition) < pos.distance(closest.executePosition))
- closest = job;
- }
- return closest;
- }
-
- private static void updateWorkers(GameContainer gc, StateBasedGame s, int delta) {
- for (Worker worker : workers)
- worker.update(gc, s, delta);
- }
-
- public static void render(GameContainer gc, StateBasedGame s, Graphics g) {
- for (Worker worker : workers) {
- worker.render(gc, s, g);
- if (worker.currentJob != null) {
- Vector2i progressPos = worker.currentJob.targetPosition;
- Images.drawImage("inProgress", progressPos.x, progressPos.y);
- }
- }
- for (Job job : jobs)
- Images.drawImage("hourglas", job.targetPosition.x, job.targetPosition.y);
- }
-
- public static void removeJob(Job job) {
- jobs.remove(job);
- }
-
- public static void executeJob(Job job) {
- job.execute();
- removeJob(job);
- }
-
-}
diff --git a/src/jobSystem/JobWindow.java b/src/jobSystem/JobWindow.java
deleted file mode 100644
index d1b3d82..0000000
--- a/src/jobSystem/JobWindow.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package jobSystem;
-
-import jobSystem.Jobs.JobType;
-import math.Vector2i;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import java.awt.*;
-
-public class JobWindow extends JFrame {
- private static final long serialVersionUID = 1L;
-
- private static JComboBox comboBox;
-
- public static void openJobWindow() {
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- try {
- JobWindow frame = new JobWindow();
- frame.setVisible(true);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- public JobWindow() {
- setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
- setBounds(100, 100, 262, 98);
- JPanel contentPane = new JPanel();
- contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
- contentPane.setLayout(new BorderLayout(0, 0));
- setResizable(false);
- setContentPane(contentPane);
-
- comboBox = new JComboBox();
- comboBox.setModel(new DefaultComboBoxModel(Jobs.JobType.values()));
- contentPane.add(comboBox, BorderLayout.CENTER);
-
- JLabel lblJobs = new JLabel("Jobs");
- lblJobs.setFont(new Font("Tahoma", Font.PLAIN, 29));
- lblJobs.setHorizontalAlignment(SwingConstants.CENTER);
- contentPane.add(lblJobs, BorderLayout.NORTH);
- }
-
- public static Job getSelectedJob(Vector2i mousePos) {
- if (comboBox == null)
- openJobWindow();
- return Jobs.getJob((JobType) comboBox.getSelectedItem(), mousePos);
- }
-
-}
diff --git a/src/jobSystem/Jobs.java b/src/jobSystem/Jobs.java
deleted file mode 100644
index e834cd5..0000000
--- a/src/jobSystem/Jobs.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package jobSystem;
-
-import jobSystem.jobs.BuildJob;
-import jobSystem.jobs.ChangeTileJob;
-import jobSystem.jobs.RemoveJob;
-import jobSystem.jobs.WalkJob;
-import math.Vector2i;
-import objects.*;
-import objects.plants.Tree;
-import world.TileType;
-
-public class Jobs {
-
- public enum JobType {
- MOVE, REMOVE, BUILD_WOOD, BUILD_FLOOR, PLACE_GRASS, BUILD_STONE, BUILD_IRON_WALL, BUILD_WOODEN_DOOR, BUILD_IRON_DOOR
- }
-
- public static Job getJob(JobType job, Vector2i mousePos) {
- switch (job) {
- case MOVE:
- return new WalkJob(mousePos);
- case REMOVE:
- return new RemoveJob(mousePos);
- case BUILD_WOOD:
- return new BuildJob(mousePos, new Tree());
- case BUILD_FLOOR:
- return new ChangeTileJob(mousePos, TileType.FLOOR);
- case PLACE_GRASS:
- return new ChangeTileJob(mousePos, TileType.GRASS);
- case BUILD_STONE:
- return new BuildJob(mousePos, new Stone());
- case BUILD_IRON_WALL:
- return new BuildJob(mousePos, new IronWall());
- case BUILD_WOODEN_DOOR:
- return new BuildJob(mousePos, new WoodenDoor(Door.getDirection(mousePos)));
- case BUILD_IRON_DOOR:
- return new BuildJob(mousePos, new IronDoor(Door.getDirection(mousePos)));
- default:
- return null;
- }
- }
-}
diff --git a/src/jobSystem/MouseManager.java b/src/jobSystem/MouseManager.java
deleted file mode 100644
index 3bad489..0000000
--- a/src/jobSystem/MouseManager.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package jobSystem;
-
-import assets.Images;
-import game.Camera;
-import math.Vector2i;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.state.StateBasedGame;
-import world.Tile;
-import world.World;
-
-public class MouseManager {
-
- public static boolean dragging = false;
- public static Vector2i startPos;
- public static Vector2i endPos;
-
- public static void updateMouseEvents(GameContainer gc, StateBasedGame s, int delta) {
- Input input = gc.getInput();
- Vector2i mousePos = new Vector2i((int) (input.getMouseX() / Tile.getTileSize()), (int) (input.getMouseY() / Tile.getTileSize()));
- if (!dragging && input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
- dragging = true;
- startPos = mousePos.add(Camera.position.getInverted());
- }
- if (dragging)
- endPos = mousePos.add(Camera.position.getInverted()).add(1);
- if (dragging && !input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
- dragging = false;
- for (int x = startPos.x; x < endPos.x; x++)
- for (int y = startPos.y; y < endPos.y; y++) {
- if (x < 0 || x >= World.WORLD_WIDTH || y < 0 || y >= World.WORLD_HEIGHT)
- continue;
- JobManager.addJob(JobWindow.getSelectedJob(new Vector2i(x, y)));
- }
- startPos = null;
- endPos = null;
- }
- }
-
- public static void render(GameContainer gc, StateBasedGame s, Graphics g) {
- if (startPos != null && endPos != null && dragging) {
- for (int x = startPos.x; x < endPos.x; x++) {
- for (int y = startPos.y; y < endPos.y; y++) {
- Images.drawImage("select", x, y);
- }
- }
- }
- }
-
-}
diff --git a/src/jobSystem/jobs/BuildJob.java b/src/jobSystem/jobs/BuildJob.java
deleted file mode 100644
index 6848b92..0000000
--- a/src/jobSystem/jobs/BuildJob.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package jobSystem.jobs;
-
-import jobSystem.Job;
-import math.Vector2i;
-import objects.templates.WorldObject;
-import resources.ResourceManager;
-import world.World;
-
-public class BuildJob extends Job {
-
- private final WorldObject worldObject;
-
- public BuildJob(Vector2i targetPosition, WorldObject worldObject) {
- super(targetPosition, worldObject.destroyTime);
- this.worldObject = worldObject;
- }
-
- @Override
- public boolean checkRequirements() {
- if (World.getTile(targetPosition.x, targetPosition.y).worldObject != null)
- return false;
- for (String s : worldObject.getResources())
- if (!ResourceManager.contains(s))
- return false;
- return true;
- }
-
- @Override
- public void onCreated() {
-
- }
-
- @Override
- public void execute() {
- for (String s : worldObject.getResources())
- ResourceManager.addResource(s, -1);
- World.getTile(targetPosition.x, targetPosition.y).setWorldObject(worldObject);
- }
-
-}
diff --git a/src/jobSystem/jobs/ChangeTileJob.java b/src/jobSystem/jobs/ChangeTileJob.java
deleted file mode 100644
index 9e4d23f..0000000
--- a/src/jobSystem/jobs/ChangeTileJob.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package jobSystem.jobs;
-
-import jobSystem.Job;
-import math.Vector2i;
-import world.TileType;
-import world.World;
-
-public class ChangeTileJob extends Job {
-
- private final TileType tileType;
-
- public ChangeTileJob(Vector2i targetPosition, TileType tileType) {
- super(targetPosition, 0);
- this.tileType = tileType;
- }
-
- @Override
- public boolean checkRequirements() {
- return World.isWalkable(targetPosition.x, targetPosition.y) && World.getTile(targetPosition.x, targetPosition.y).tileType != tileType;
- }
-
- @Override
- public void onCreated() {
-
- }
-
- @Override
- public void execute() {
- World.getTile(targetPosition.x, targetPosition.y).tileType = tileType;
- }
-
-}
diff --git a/src/jobSystem/jobs/RemoveJob.java b/src/jobSystem/jobs/RemoveJob.java
deleted file mode 100644
index 5b231fd..0000000
--- a/src/jobSystem/jobs/RemoveJob.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package jobSystem.jobs;
-
-import jobSystem.Job;
-import math.Vector2i;
-import resources.ResourceManager;
-import world.Tile;
-import world.World;
-
-public class RemoveJob extends Job {
-
- public RemoveJob(Vector2i targetPosition) {
- super(targetPosition, getRemoveTime(targetPosition));
- }
-
- public static int getRemoveTime(Vector2i targetPosition) {
- if (World.getTile(targetPosition.x, targetPosition.y).worldObject != null)
- return World.getTile(targetPosition.x, targetPosition.y).worldObject.destroyTime;
- return 0;
- }
-
- @Override
- public boolean checkRequirements() {
- return World.getTile(targetPosition.x, targetPosition.y) != null && World.getTile(targetPosition.x, targetPosition.y).worldObject != null;
- }
-
- @Override
- public void onCreated() {
-
- }
-
- @Override
- public void execute() {
- Tile tile = World.getTile(targetPosition.x, targetPosition.y);
- for (String s : tile.worldObject.getResources())
- ResourceManager.addResource(s, 1);
- tile.worldObject = null;
- }
-
-}
diff --git a/src/jobSystem/jobs/WalkJob.java b/src/jobSystem/jobs/WalkJob.java
deleted file mode 100644
index 7af9ede..0000000
--- a/src/jobSystem/jobs/WalkJob.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package jobSystem.jobs;
-
-import jobSystem.Job;
-import math.Vector2i;
-import world.World;
-
-public class WalkJob extends Job {
-
- public WalkJob(Vector2i targetPosition) {
- super(targetPosition, 0);
- }
-
- @Override
- public boolean checkRequirements() {
- return World.isWalkable(targetPosition.x, targetPosition.y);
- }
-
- @Override
- public void onCreated() {
- executePosition = targetPosition;
- }
-
- @Override
- public void execute() {
- }
-
-}
diff --git a/src/math/Vector2i.java b/src/math/Vector2i.java
deleted file mode 100644
index 3789740..0000000
--- a/src/math/Vector2i.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package math;
-
-public class Vector2i {
-
- public int x, y;
-
- public Vector2i(int x, int y) {
- this.x = x;
- this.y = y;
- }
-
- public Vector2i(int i) {
- this.x = i;
- this.y = i;
- }
-
- public Vector2i getInverted() {
- Vector2i result = new Vector2i(x, y);
- result.x = -x;
- result.y = -y;
- return result;
- }
-
- public Vector2i add(Vector2i other) {
- return new Vector2i(x + other.x, y + other.y);
- }
-
- public Vector2i sub(Vector2i other) {
- return new Vector2i(x - other.x, y - other.y);
- }
-
- public Vector2i div(Vector2i other) {
- return new Vector2i(x / other.x, y / other.y);
- }
-
- public Vector2i mul(Vector2i other) {
- return new Vector2i(x * other.x, y * other.y);
- }
-
- public Vector2i add(int other) {
- return new Vector2i(x + other, y + other);
- }
-
- public Vector2i sub(int other) {
- return new Vector2i(x - other, y - other);
- }
-
- public Vector2i div(int other) {
- return new Vector2i(x / other, y / other);
- }
-
- public Vector2i mul(int other) {
- return new Vector2i(x * other, y * other);
- }
-
- public float distance(Vector2i other) {
- return (float) Math.sqrt(Math.pow(x - other.x, 2) + Math.pow(y - other.y, 2));
- }
-
- public boolean equals(Object object) {
- if (!(object instanceof Vector2i))
- return false;
- Vector2i vec = (Vector2i) object;
- return vec.x == x && vec.y == y;
- }
-
- public String toString() {
- return "vector2i: " + x + ", " + y;
- }
-
-}
diff --git a/src/objects/Direction.java b/src/objects/Direction.java
deleted file mode 100644
index 1f6289b..0000000
--- a/src/objects/Direction.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package objects;
-
-public enum Direction {
- NORTH, EAST, SOUTH, WEST
-}
diff --git a/src/objects/Door.java b/src/objects/Door.java
deleted file mode 100644
index 9e9c111..0000000
--- a/src/objects/Door.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package objects;
-
-import math.Vector2i;
-import objects.templates.WorldObject;
-import world.World;
-
-public abstract class Door extends WorldObject {
-
- public Door(String NS, String EW, Direction direction, int destoryTime) {
- super(getCorrectSprite(NS, EW, direction), true, false, destoryTime);
-
- }
-
- private static String getCorrectSprite(String NS, String EW, Direction direction) {
- if (direction.equals(Direction.NORTH) || direction.equals(Direction.SOUTH))
- return NS;
- return EW;
- }
-
- public static Direction getDirection(Vector2i pos) {
- if (!World.isWalkable(pos.x, pos.y - 1))
- return Direction.NORTH;
- if (!World.isWalkable(pos.x + 1, pos.y))
- return Direction.EAST;
- if (!World.isWalkable(pos.x, pos.y - 1))
- return Direction.SOUTH;
- if (!World.isWalkable(pos.x - 1, pos.y))
- return Direction.WEST;
- return Direction.NORTH;
- }
-
-
-}
diff --git a/src/objects/IronDoor.java b/src/objects/IronDoor.java
deleted file mode 100644
index b41bb52..0000000
--- a/src/objects/IronDoor.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package objects;
-
-public class IronDoor extends Door {
-
- public IronDoor(Direction direction) {
- super("iron_doorNS", "iron_doorEW", direction, 5000);
- }
-
- public String[] getResources() {
- return new String[]{"Tree", "Iron"};
- }
-
-}
diff --git a/src/objects/IronWall.java b/src/objects/IronWall.java
deleted file mode 100644
index 86bece8..0000000
--- a/src/objects/IronWall.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects;
-
-import objects.templates.WorldObject;
-
-public class IronWall extends WorldObject {
-
- public IronWall() {
- super("iron_wall", false, true, 2000);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Iron"};
- }
-
-}
diff --git a/src/objects/Stone.java b/src/objects/Stone.java
deleted file mode 100644
index 557d61c..0000000
--- a/src/objects/Stone.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects;
-
-import objects.templates.WorldObject;
-
-public class Stone extends WorldObject {
-
- public Stone() {
- super("Stone", false, true, 150);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Stone"};
- }
-
-}
diff --git a/src/objects/WoodenDoor.java b/src/objects/WoodenDoor.java
deleted file mode 100644
index 6d7fb43..0000000
--- a/src/objects/WoodenDoor.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package objects;
-
-public class WoodenDoor extends Door {
-
- public WoodenDoor(Direction direction) {
- super("wooden_doorNS", "wooden_doorEW", direction, 1000);
- }
-
- public String[] getResources() {
- return new String[]{"Tree"};
- }
-
-}
diff --git a/src/objects/WoodenWall.java b/src/objects/WoodenWall.java
deleted file mode 100644
index a8b01c0..0000000
--- a/src/objects/WoodenWall.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects;
-
-import objects.templates.WorldObject;
-
-public class WoodenWall extends WorldObject {
-
- public WoodenWall() {
- super("woodenWall", false, true, 150);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Tree"};
- }
-
-}
diff --git a/src/objects/ores/DiamondOre.java b/src/objects/ores/DiamondOre.java
deleted file mode 100644
index a341a4c..0000000
--- a/src/objects/ores/DiamondOre.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects.ores;
-
-import objects.templates.WorldObject;
-
-public class DiamondOre extends WorldObject {
-
- public DiamondOre() {
- super("diamond_ore", false, true, 3000);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Diamond"};
- }
-
-}
diff --git a/src/objects/ores/IronOre.java b/src/objects/ores/IronOre.java
deleted file mode 100644
index 4d91151..0000000
--- a/src/objects/ores/IronOre.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects.ores;
-
-import objects.templates.WorldObject;
-
-public class IronOre extends WorldObject {
-
- public IronOre() {
- super("iron_ore", false, true, 2000);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Iron"};
- }
-
-}
diff --git a/src/objects/plants/Bush.java b/src/objects/plants/Bush.java
deleted file mode 100644
index e32bf47..0000000
--- a/src/objects/plants/Bush.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package objects.plants;
-
-import objects.templates.Plant;
-
-public class Bush extends Plant {
-
- public Bush() {
- super("bush", false, 100);
- }
-
- public String[] getResources() {
- return new String[]{"Bush"};
- }
-
-}
diff --git a/src/objects/plants/Tree.java b/src/objects/plants/Tree.java
deleted file mode 100644
index 614a063..0000000
--- a/src/objects/plants/Tree.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package objects.plants;
-
-import objects.templates.Plant;
-
-public class Tree extends Plant {
-
- public Tree() {
- super("tree", true, 300);
- }
-
- @Override
- public String[] getResources() {
- return new String[]{"Tree"};
- }
-
-}
diff --git a/src/objects/templates/Plant.java b/src/objects/templates/Plant.java
deleted file mode 100644
index dbeca02..0000000
--- a/src/objects/templates/Plant.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package objects.templates;
-
-public abstract class Plant extends WorldObject {
-
- public Plant(String name, boolean isSolid, int destoryTime) {
- super(name, false, isSolid, destoryTime);
- }
-
-}
diff --git a/src/objects/templates/WorldObject.java b/src/objects/templates/WorldObject.java
deleted file mode 100644
index 670ee86..0000000
--- a/src/objects/templates/WorldObject.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package objects.templates;
-
-import assets.Images;
-import org.newdawn.slick.Image;
-
-public abstract class WorldObject {
-
- public Image image;
- public boolean isWalkable;
- public boolean isSolid;
- public int destroyTime;
-
- public WorldObject(Image image, boolean isWalkable, boolean isSolid, int destroyTime) {
- this.image = image;
- this.isWalkable = isWalkable;
- this.isSolid = isSolid;
- this.destroyTime = destroyTime;
- }
-
- public WorldObject(String name, boolean isWalkable, boolean isSolid, int destroyTime) {
- image = Images.getImage(name);
- this.isWalkable = isWalkable;
- this.isSolid = isSolid;
- this.destroyTime = destroyTime;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-
- public abstract String[] getResources();
-
-}
diff --git a/src/rendering/Renderer.java b/src/rendering/Renderer.java
deleted file mode 100644
index 061d919..0000000
--- a/src/rendering/Renderer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package rendering;
-
-import jobSystem.JobManager;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.state.StateBasedGame;
-import world.Tile;
-import world.World;
-
-public class Renderer {
-
- public void render(GameContainer gc, StateBasedGame s, Graphics g) {
- for (int y = 0; y < World.WORLD_HEIGHT; y++)
- for (int x = 0; x < World.WORLD_WIDTH; x++) {
- Tile current = World.getTile(x, y);
- if (current.brightness != 0)
- if (current.worldObject == null)
- World.renderTile(gc, x, y);
- else if (current.worldObject.isSolid)
- World.renderObject(gc, x, y);
- else {
- World.renderTile(gc, x, y);
- World.renderObject(gc, x, y);
- }
- }
- JobManager.render(gc, s, g);
- }
-
- public void update(GameContainer gc, StateBasedGame s, int delta) {
- updateWorldLight();
- }
-
- public void updateWorldLight() {
- for (int y = 0; y < World.WORLD_HEIGHT; y++)
- for (int x = 0; x < World.WORLD_WIDTH; x++) {
- Tile current = World.getTile(x, y);
- boolean dark = true;
- if (!World.isSolid(x, y + 1))
- dark = false;
- if (!World.isSolid(x, y - 1))
- dark = false;
- if (!World.isSolid(x + 1, y))
- dark = false;
- if (!World.isSolid(x - 1, y))
- dark = false;
- if (dark)
- current.brightness = 0f;
- else
- current.brightness = 1f;
- }
- }
-}
\ No newline at end of file
diff --git a/src/resources/ResourceManager.java b/src/resources/ResourceManager.java
deleted file mode 100644
index 2f85b98..0000000
--- a/src/resources/ResourceManager.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package resources;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class ResourceManager {
-
- public static Map resources = new HashMap<>();
-
- private static boolean windowCreated;
-
- public static void addResource(String resource, int amount) {
- if (!windowCreated) {
- ResourceWindow.createWindow();
- windowCreated = true;
- }
- if (resources.containsKey(resource))
- resources.put(resource, resources.get(resource) + amount);
- else
- resources.put(resource, amount);
- ResourceWindow.updateList(resources);
- }
-
- public static int getAmount(String resource) {
- if (!resources.containsKey(resource))
- return 0;
- return resources.get(resource);
- }
-
- public static boolean contains(String resource) {
- return resources.containsKey(resource) && resources.get(resource) > 0;
- }
-}
diff --git a/src/resources/ResourceWindow.java b/src/resources/ResourceWindow.java
deleted file mode 100644
index 882bead..0000000
--- a/src/resources/ResourceWindow.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package resources;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.Map;
-
-public class ResourceWindow extends JPanel {
- private static final long serialVersionUID = 1L;
-
- private static JList list;
-
- private static DefaultListModel model;
-
- public ResourceWindow() {
- setLayout(new BorderLayout());
- model = new DefaultListModel();
- list = new JList(model);
- JScrollPane pane = new JScrollPane(list);
- JLabel label = new JLabel("Resources");
- label.setFont(new Font("Tahoma", Font.PLAIN, 29));
- label.setHorizontalAlignment(SwingConstants.CENTER);
- add(label, BorderLayout.NORTH);
- add(pane, BorderLayout.CENTER);
- }
-
- public static void createWindow() {
- JFrame frame = new JFrame();
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setContentPane(new ResourceWindow());
- frame.setSize(200, 400);
- frame.setLocation(1200, 200);
- frame.setVisible(true);
- }
-
- public static void updateList(Map resources) {
- model.clear();
- for (Map.Entry resource : resources.entrySet())
- model.addElement(resource.getValue() + ": " + resource.getKey());
- }
-}
diff --git a/src/save/GameManager.java b/src/save/GameManager.java
deleted file mode 100644
index 4a0d81a..0000000
--- a/src/save/GameManager.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package save;
-
-import util.TimeUtils;
-import world.TileType;
-import world.World;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.List;
-
-public class GameManager {
-
- public static void saveGame() {
- try {
- File file = new File("saves/save_" + TimeUtils.getTimeAndDate() + ".sav");
- PrintWriter writer = new PrintWriter(file, "UTF-8");
- for (int y = 0; y < World.WORLD_HEIGHT; y++) {
- for (int x = 0; x < World.WORLD_WIDTH; x++)
- writer.print(World.getTile(x, y).toString() + ";");
- writer.println();
- }
- writer.flush();
- writer.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- public static String[] getAllSaves() {
- File folder = new File("saves");
- File[] listOfFiles = folder.listFiles();
- List saves = new ArrayList<>();
- for (File listOfFile : listOfFiles)
- if (listOfFile.isFile())
- saves.add(listOfFile.getName());
- String[] result = new String[saves.size()];
- for (int i = 0; i < result.length; i++)
- result[i] = saves.get(i);
- return result;
- }
-
- public static void loadLatestGame() {
- String[] saves = getAllSaves();
- if (saves.length > 0)
- loadGame(saves[saves.length - 1]);
- }
-
- public static void loadGame(String saveName) {
- try {
- BufferedReader br = new BufferedReader(new FileReader("saves/" + saveName));
- String line = br.readLine();
- int lineNum = 0;
- while (line != null) {
- String[] split = line.split(";");
- for (int i = 0; i < split.length; i++)
- World.getTile(i, lineNum).tileType = TileType.valueOf(split[i]);
- line = br.readLine();
- lineNum++;
- }
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/src/util/Strings.java b/src/util/Strings.java
deleted file mode 100644
index 750ec71..0000000
--- a/src/util/Strings.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package util;
-
-public class Strings {
-
- public static final String resPath = "res/";
-
- public static final String imagePath = resPath + "sprites/";
- public static final String audioPath = resPath + "sounds/";
- public static final String spriteSheetPath = resPath + "spritesheets/";
-
-}
diff --git a/src/util/TimeUtils.java b/src/util/TimeUtils.java
deleted file mode 100644
index b5bf9cf..0000000
--- a/src/util/TimeUtils.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package util;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class TimeUtils {
-
- public static String getTimeAndDate() {
- DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
- Date date = new Date();
- return dateFormat.format(date);
- }
-
-}
diff --git a/src/world/Tile.java b/src/world/Tile.java
deleted file mode 100644
index bc9192a..0000000
--- a/src/world/Tile.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package world;
-
-import game.Camera;
-import objects.templates.WorldObject;
-
-public class Tile {
-
- public static float TILE_SIZE = 15;
-
- public TileType tileType;
- public WorldObject worldObject;
- public float brightness = 1f;
-
- public Tile(TileType tileType) {
- this.tileType = tileType;
- }
-
- public void setWorldObject(WorldObject worldObject) {
- this.worldObject = worldObject;
- }
-
- public boolean isWalkable() {
- return worldObject == null || worldObject.isWalkable;
- }
-
- @Override
- public String toString() {
- return tileType.toString();
- }
-
- public static float getTileSize() {
- return TILE_SIZE + Camera.zoom;
- }
-
-}
diff --git a/src/world/TileType.java b/src/world/TileType.java
deleted file mode 100644
index 99ae6fb..0000000
--- a/src/world/TileType.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package world;
-
-import assets.Images;
-import org.newdawn.slick.Image;
-
-public enum TileType {
-
- GRASS("grass_tile"), STONE("stone_tile"), FLOOR("floor");
-
- public Image image;
-
- TileType(String name) {
- image = Images.getImage(name);
- }
-
-}
\ No newline at end of file
diff --git a/src/world/World.java b/src/world/World.java
deleted file mode 100644
index 99bb5d6..0000000
--- a/src/world/World.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package world;
-
-import assets.Images;
-import org.newdawn.slick.GameContainer;
-
-public class World {
-
- public static final int WORLD_WIDTH = 50;
- public static final int WORLD_HEIGHT = 50;
-
- public static Tile[] tiles = new Tile[WORLD_WIDTH * WORLD_HEIGHT];
-
- public static void init() {
- for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++)
- tiles[i] = new Tile(TileType.GRASS);
- WorldGenerator.addTileType(TileType.GRASS);
- WorldGenerator.addTileType(TileType.STONE);
- WorldGenerator.generateWorld();
- }
-
- public static void renderTile(GameContainer gc, int x, int y) {
- Tile currentTile = getTile(x, y);
- Images.drawImage(currentTile.tileType.image, x, y);
- }
-
- public static void renderObject(GameContainer gc, int x, int y) {
- Tile currentTile = getTile(x, y);
- if (currentTile.worldObject != null)
- Images.drawImage(currentTile.worldObject.image, x, y);
- }
-
- public static boolean isTileType(int x, int y, TileType tileType) {
- return !(x < 0 || x >= World.WORLD_WIDTH || y < 0 || y >= World.WORLD_HEIGHT) && getTile(x, y).tileType.equals(tileType);
- }
-
- public static boolean isWalkable(int x, int y) {
- return !(x >= WORLD_WIDTH || x < 0 || y >= WORLD_HEIGHT || y < 0) && getTile(x, y).isWalkable();
- }
-
- public static boolean isSolid(int x, int y) {
- return !(x >= WORLD_WIDTH || x < 0 || y >= WORLD_HEIGHT || y < 0) && getTile(x, y).worldObject != null && getTile(x, y).worldObject.isSolid;
- }
-
- public static Tile getTile(int x, int y) {
- if (x >= WORLD_WIDTH || x < 0 || y >= WORLD_HEIGHT || y < 0)
- return null;
- return tiles[x + y * WORLD_WIDTH];
- }
-
- public static int getWorldObjectAmount() {
- int amount = 0;
- for (int x = 0; x < WORLD_WIDTH; x++)
- for (int y = 0; y < WORLD_HEIGHT; y++)
- if (getTile(x, y).worldObject != null)
- amount++;
- return amount;
- }
-}
\ No newline at end of file
diff --git a/src/world/WorldGenerator.java b/src/world/WorldGenerator.java
deleted file mode 100644
index 0e657d2..0000000
--- a/src/world/WorldGenerator.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package world;
-
-import math.Vector2i;
-import objects.Stone;
-import objects.ores.DiamondOre;
-import objects.ores.IronOre;
-import objects.plants.Bush;
-import objects.plants.Tree;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-public class WorldGenerator {
-
- private static final int ITERATIONS = 5;
- private static Random random = new Random();
- private static List tilesToUse = new ArrayList<>();
-
- public static void addTileType(TileType tileType) {
- tilesToUse.add(tileType);
- }
-
- public static void generateWorld() {
- generateRandomTiles();
- for (int i = 0; i < ITERATIONS; i++)
- generateUsingRules();
- placeAccesories();
- }
-
- public static void placeAccesories() {
- for (int y = 0; y < World.WORLD_HEIGHT; y++) {
- for (int x = 0; x < World.WORLD_WIDTH; x++) {
- Tile current = World.getTile(x, y);
- if (current.tileType.equals(TileType.STONE))
- current.worldObject = new Stone();
- if (current.tileType.equals(TileType.GRASS) && random.nextInt(30) == 1)
- current.worldObject = new Tree();
- if (current.tileType.equals(TileType.GRASS) && random.nextInt(50) == 1)
- current.worldObject = new Bush();
- if (current.tileType.equals(TileType.STONE) && random.nextInt(40) == 1)
- current.worldObject = new IronOre();
- if (current.tileType.equals(TileType.STONE) && random.nextInt(100) == 1)
- current.worldObject = new DiamondOre();
- }
- }
- }
-
- public static void generateUsingRules() {
- for (int x = 0; x < World.WORLD_WIDTH; x++)
- for (int y = 0; y < World.WORLD_HEIGHT; y++) {
- Tile tile = World.getTile(x, y);
- if (tile.tileType.equals(TileType.STONE)) {
- if (getSurroundingTileAmount(new Vector2i(x, y), TileType.STONE) < 4)
- tile.tileType = TileType.GRASS;
-
- } else if (tile.tileType.equals(TileType.GRASS)) {
-
- if (getSurroundingTileAmount(new Vector2i(x, y), TileType.STONE) >= 5)
- tile.tileType = TileType.STONE;
- }
- }
- }
-
- private static int getSurroundingTileAmount(Vector2i pos, TileType tileType) {
- int x = pos.x;
- int y = pos.y;
- int amount = 0;
- if (checkTile(x, y + 1, tileType))
- amount++;
- if (checkTile(x + 1, y + 1, tileType))
- amount++;
- if (checkTile(x + 1, y, tileType))
- amount++;
- if (checkTile(x + 1, y - 1, tileType))
- amount++;
- if (checkTile(x, y - 1, tileType))
- amount++;
- if (checkTile(x - 1, y - 1, tileType))
- amount++;
- if (checkTile(x - 1, y, tileType))
- amount++;
- if (checkTile(x - 1, y + 1, tileType))
- amount++;
- return amount;
- }
-
- private static boolean checkTile(int x, int y, TileType tileType) {
- return World.isTileType(x, y, tileType);
- }
-
- private static void generateRandomTiles() {
- for (int i = 0; i < World.WORLD_WIDTH * World.WORLD_HEIGHT; i++)
- World.tiles[i].tileType = tilesToUse.get(random.nextInt(tilesToUse.size()));
- }
-}
diff --git a/stack.yaml b/stack.yaml
new file mode 100644
index 0000000..de75da5
--- /dev/null
+++ b/stack.yaml
@@ -0,0 +1,3 @@
+resolver: lts-20.11
+packages:
+- .
diff --git a/test/from-upstream/Main.hs b/test/from-upstream/Main.hs
new file mode 100644
index 0000000..f1c6e2e
--- /dev/null
+++ b/test/from-upstream/Main.hs
@@ -0,0 +1,142 @@
+module Main (main) where
+
+import Parsing.Parsing
+import Jq.Main as Jq (process)
+
+import Paths_JqClone
+
+import Control.Concurrent.STM (atomically)
+import System.Process.Typed ( setStdin
+ , setStdout
+ , byteStringInput
+ , byteStringOutput
+ , shell
+ , withProcessWait_
+ , getStdout
+ , waitExitCodeSTM)
+import Control.DeepSeq (force)
+import Control.Exception (handle, evaluate, SomeException, ErrorCall)
+import Data.ByteString.Lazy.UTF8 ( fromString
+ , toString)
+
+import Data.Maybe (isJust, fromJust)
+
+import System.Exit (ExitCode(..), exitFailure, exitSuccess)
+
+import Test.Tasty
+import Test.Tasty.Runners (consoleTestReporter)
+import Test.Tasty.HUnit
+
+data JTestInstance = JTestInstance {program :: String, input :: String, output :: [String]} deriving Show
+
+data JTest = JTestOne JTestInstance
+ | JTestGroup { groupName :: String
+ , groupTests :: [JTest]}
+ deriving (Show)
+
+comment :: Parser ()
+comment = fmap (const ()) $ char '\n'
+ <|> do char '#'
+ many (sat (/='\n'))
+ char '\n'
+
+test :: Parser JTestInstance
+test = do
+ p <- some (sat (/='\n'))
+ char '\n'
+ i <- some (sat (/='\n'))
+ char '\n'
+ o <- tillemptyline
+ return $ JTestInstance p i o
+ where
+ tillemptyline = do
+ h <- some (sat (/='\n'))
+ (char '\n') <|> return '\n'
+ t <- (tillemptyline <|> return [])
+ return $ h : t
+
+testsAndComments :: Parser [JTestInstance]
+testsAndComments =
+ fmap (map fromJust . filter isJust) . many $ (fmap (const Nothing) comment)
+ <|> (fmap Just test)
+
+testfile :: Parser JTest
+testfile = do
+ ts <- testsAndComments
+ return $ JTestGroup "Input-output tests" (map JTestOne ts)
+
+
+toparse :: IO String
+toparse = do
+ file <- getDataFileName "jq.test"
+ r <- readFile file
+ return r
+
+alltests :: IO JTest
+alltests = do
+ t <- toparse
+ case (parse testfile t) of
+ [(ts, [])] -> return ts
+ [] -> do putStrLn "couldn't parse tests"
+ exitFailure
+ [(_, tail)] -> do putStrLn "couldn't parse tests"
+ putStrLn "leftover: "
+ putStrLn (take 30 tail)
+ exitFailure
+
+type Program = (String -> String -> IO (ExitCode,String))
+
+getProgram :: Maybe String -> Program
+getProgram Nothing filter i = do
+ r <- handle someh $ return $ force $ Jq.process [filter] i
+ return $ case r of
+ Left s -> (ExitFailure 2, s)
+ Right out -> (ExitSuccess, out)
+ where
+ someh :: SomeException -> IO (Either String String)
+ someh _ = return $ Left "caught some exception"
+
+getProgram (Just s) filter i = do
+ let sc = setStdin (byteStringInput (fromString i))
+ $ setStdout byteStringOutput
+ $ (shell $ s ++ " '" ++ filter ++ "'")
+ (e, bv) <- withProcessWait_ sc (\p -> do o <- atomically (getStdout p)
+ e <- atomically (waitExitCodeSTM p)
+ return (e, o))
+ return $ (e, toString bv)
+
+prettifyJSON :: String -> IO String
+prettifyJSON s = do
+ let jqconfig = setStdin (byteStringInput (fromString s))
+ $ setStdout byteStringOutput
+ $ (shell "jq --sort-keys -M \".\"")
+ bv <- withProcessWait_ jqconfig (\ p -> atomically (getStdout p))
+ return $ toString bv
+
+createTestInstance :: Program -> JTestInstance -> TestTree
+createTestInstance program t = localOption (mkTimeout 10000000) $ testCase name res
+ where
+ name = "filter: `" ++ p ++ "`\tinput: `" ++ i ++ "`"
+ JTestInstance p i o = t
+ res = do
+ (exitcode, out) <- program p i
+ assertEqual ("Program terminated abnormally with error: " ++ out)
+ ExitSuccess exitcode
+ op <- fmap concat $ traverse prettifyJSON o
+ assertEqual "The outputs don't match " op out
+
+createTest :: Program -> JTest -> TestTree
+createTest p (JTestOne j) =
+ createTestInstance p j
+createTest p (JTestGroup name gt) =
+ testGroup name (map (createTest p) gt)
+
+main :: IO ()
+main = do
+ -- to test the testsuite
+ -- let program = getProgram (Just "jq --sort-keys -M")
+ -- to test the submission
+ let program = getProgram Nothing
+ ts <- alltests
+ defaultMainWithIngredients [consoleTestReporter] $
+ createTest program ts
diff --git a/test/from-upstream/data/jq.test b/test/from-upstream/data/jq.test
new file mode 100644
index 0000000..70c191a
--- /dev/null
+++ b/test/from-upstream/data/jq.test
@@ -0,0 +1,109 @@
+# Tests are groups of three lines: program, input, expected output
+# Blank lines and lines starting with # are ignored
+
+#
+# Simple value tests to check parser. Input is irrelevant
+#
+
+.
+null
+null
+
+#
+# Field access, piping
+#
+
+.foo
+{"foo": 42, "bar": 43}
+42
+
+.foo | .bar
+{"foo": {"bar": 42}, "bar": "badvalue"}
+42
+
+.foo.bar
+{"foo": {"bar": 42}, "bar": "badvalue"}
+42
+
+.foo_bar
+{"foo_bar": 2}
+2
+
+.["foo"].bar
+{"foo": {"bar": 42}, "bar": "badvalue"}
+42
+
+."foo"."bar"
+{"foo": {"bar": 20}}
+20
+
+
+# Arrays
+
+[.[]|.foo?]
+[1,[2],{"foo":3,"bar":4},{},{"foo":5}]
+[3,null,5]
+
+[.[]|.foo?.bar?]
+[1,[2],[],{"foo":3},{"foo":{"bar":4}},{}]
+[4,null]
+
+[.[]|.[]?]
+[1,null,[],[1,[2,[[3]]]],[{}],[{"a":[1,[2]]}]]
+[1,[2,[[3]]],{},{"a":[1,[2]]}]
+
+[.[]|.[1:3]?]
+[1,null,true,false,"abcdef",{},{"a":1,"b":2},[],[1,2,3,4,5],[1,2]]
+[null,"bc",[],[2,3],[2]]
+
+# Value construction
+
+true
+null
+true
+
+false
+null
+false
+
+null
+42
+null
+
+1
+null
+1
+
+
+-1
+null
+-1
+
+{}
+null
+{}
+
+[]
+null
+[]
+
+{x: -1}
+null
+{"x": -1}
+
+
+#
+# Dictionary construction syntax
+#
+
+{a: 1}
+null
+{"a":1}
+
+{a,b,(.d):.a,e:.b}
+{"a":1, "b":2, "c":3, "d":"c"}
+{"a":1, "b":2, "c":1, "e":2}
+
+{"a",b,"a$2"}
+{"a":1, "b":2, "c":3, "a$2":4}
+{"a":1, "b":2, "a$2":4}
diff --git a/test/unit-tests/CParserTest.hs b/test/unit-tests/CParserTest.hs
new file mode 100644
index 0000000..d4185e1
--- /dev/null
+++ b/test/unit-tests/CParserTest.hs
@@ -0,0 +1,30 @@
+module CParserTest (cParserTests) where
+
+import Jq.CParser (parseFilter)
+import Jq.Filters (Filter (..))
+import Jq.Json (JSON (JInt, JString))
+import Parsing.Parsing (parse)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (Assertion, assertEqual, assertFailure, testCase)
+import Prelude hiding (fail)
+
+cParserTests :: TestTree
+cParserTests =
+ testGroup
+ "CParser tests"
+ [ testCase "identityTest" $ "." `parseTo` Identity,
+ testCase "indexGenericNumber" $ ".[3]" `parseTo` Index (Literal $ JInt 3),
+ testCase "commaTest" $ ".[\"foo_bar\"] , ." `parseTo` Comma (Index $ Literal $ JString "foo_bar") Identity,
+ testCase "failure" $ fail ""
+ ]
+
+parseTo :: String -> Filter -> Assertion
+parseTo s j = case parse parseFilter s of
+ [(v, "")] -> assertEqual ("Expected:\n" ++ show j ++ "\ngot:\n" ++ show v) j v
+ [(v, s)] -> assertFailure $ "Parsed:\n" ++ show v ++ "\nwith remainder:\n" ++ show s
+ _ -> assertFailure "Parsing failed"
+
+fail :: String -> Assertion
+fail s = case parse parseFilter s of
+ [(v, "")] -> assertFailure $ "Parsing should fail but succeeded with:\n" ++ show v
+ _ -> return ()
diff --git a/test/unit-tests/CompileTest.hs b/test/unit-tests/CompileTest.hs
new file mode 100644
index 0000000..cf68ae6
--- /dev/null
+++ b/test/unit-tests/CompileTest.hs
@@ -0,0 +1,24 @@
+module CompileTest (compileTests) where
+
+import Jq.CParser (parseFilter)
+import Jq.Compiler (compile, run)
+import Jq.Filters (Filter (..))
+import Jq.Json (JSON (..))
+import Parsing.Parsing (parse)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (Assertion, assertEqual, assertFailure, testCase)
+import Prelude hiding (fail)
+
+compileTests :: TestTree
+compileTests = testGroup "Compile tests" [
+ testCase "identityNullTest" $ (Identity, JNull) `compileTo` [JNull]]
+
+compileTo :: (Filter, JSON) -> [JSON] -> Assertion
+compileTo (f, j) o = case run (compile f) j of
+ Left s -> assertFailure $ "Compilation failed with:\n" ++ s
+ Right v -> assertEqual ("Expected:\n" ++ show o ++ "\ngot:\n" ++ show v) o v
+
+fail :: Filter -> JSON -> Assertion
+fail f j = case run (compile f) j of
+ Right v -> assertFailure $ "Compilation should fail but succeeded with:\n" ++ show v
+ _ -> return ()
diff --git a/test/unit-tests/JParserTest.hs b/test/unit-tests/JParserTest.hs
new file mode 100644
index 0000000..a448ffa
--- /dev/null
+++ b/test/unit-tests/JParserTest.hs
@@ -0,0 +1,40 @@
+module JParserTest (jParserTests) where
+
+import Jq.JParser (parseJSON)
+import Jq.Json (JSON (..))
+import Parsing.Parsing (parse)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (Assertion, assertEqual, assertFailure, testCase)
+import Prelude hiding (fail)
+
+jParserTests :: TestTree
+jParserTests =
+ testGroup
+ "JParser tests"
+ [ testCase "nullTest" $ "null" `parseTo` JNull,
+ testCase "integerTest" $ "3" `parseTo` JInt 3,
+ testCase "doubleTest" $ "3.14" `parseTo` JDouble 3.14,
+ testCase "scientificTest" $ "3E-2" `parseTo` JDouble 0.03,
+ testCase "stringTest" $ "\"hello\"" `parseTo` JString "hello",
+ testCase "singleCharString" $ "\"h\"" `parseTo` JString "h",
+ testCase "failure" $ fail "tnull",
+ testCase "boolTrue" $ "true" `parseTo` JBool True,
+ testCase "boolFalse" $ "false" `parseTo` JBool False,
+ testCase "ArrayEmpty" $ "[]" `parseTo` JArray [],
+ testCase "ArrayOne" $ "[3]" `parseTo` JArray [JInt 3],
+ testCase "ArrayMul" $ "[3, 3, 3]" `parseTo` JArray [JInt 3, JInt 3, JInt 3],
+ testCase "ObjectEmpty" $ "{}" `parseTo` JObject [],
+ testCase "ObjectOne" $ "{\"hello\": 1}" `parseTo` JObject [("hello", JInt 1)],
+ testCase "ObjectMul" $ "{\"hello\": 1, \"hi\": 2}" `parseTo` JObject [("hello", JInt 1), ("hi", JInt 2)]
+ ]
+
+parseTo :: String -> JSON -> Assertion
+parseTo s j = case parse parseJSON s of
+ [(v, "")] -> assertEqual ("Expected:\n" ++ show j ++ "\ngot:\n" ++ show v) j v
+ [(v, s)] -> assertFailure $ "Parsed:\n" ++ show v ++ "\nwith remainder:\n" ++ show s
+ _ -> assertFailure "Parsing failed"
+
+fail :: String -> Assertion
+fail s = case parse parseJSON s of
+ [(v, "")] -> assertFailure $ "Parsing should fail but succeeded with:\n" ++ show v
+ _ -> return ()
diff --git a/test/unit-tests/Main.hs b/test/unit-tests/Main.hs
new file mode 100644
index 0000000..df0f4f2
--- /dev/null
+++ b/test/unit-tests/Main.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import Test.Tasty ( defaultMain, testGroup, TestTree)
+import Test.Tasty.HUnit ( testCase, assertFailure, assertEqual, Assertion )
+
+import JParserTest ( jParserTests )
+import CParserTest (cParserTests)
+import CompileTest (compileTests)
+
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "unitTests" [jParserTests, cParserTests, compileTests]
diff --git a/test/week3/Main.hs b/test/week3/Main.hs
new file mode 100644
index 0000000..8ea982b
--- /dev/null
+++ b/test/week3/Main.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE StandaloneDeriving #-}
+module Main where
+
+import Control.DeepSeq
+import Control.Monad
+import Data.Char
+import Data.List
+import GHC.Generics (Generic, Generic1)
+import System.Exit
+import Test.Tasty (defaultMain, testGroup)
+import Test.Tasty.QuickCheck (testProperty)
+import Test.QuickCheck
+
+import Jq.Json as Json
+
+{--
+ It can be that one (or both) of these two derivation fail.
+ Especially if you introduce some non-trivial constructors
+ or if your definition of filter is mutually recursive with
+ some other definition.
+ This doesn't necessarily mean that you're doing anything wrong.
+ You can try fixing it yourself by adding
+ `deriving instance Generic X` and
+ `deriving instance NFData X` below for the missing classes.
+ In case this doesn't work reach out to the course team.
+--}
+deriving instance Generic JSON
+deriving instance NFData JSON
+
+arbitrary' :: Int -> Gen JSON
+arbitrary' 0 = frequency [ (1, arbitraryNull), (10, arbitraryNumber), (10, arbitraryString), (1, arbitraryBool) ]
+arbitrary' x = frequency [ (1, arbitraryNull), (10, arbitraryNumber), (10, arbitraryString), (1, arbitraryBool), (40, arbitraryArray x), (40, arbitraryObject x)]
+
+arbitraryNull = return $ jsonNullSC
+arbitraryNumber = choose (-4294967296, 4294967295) >>= return . jsonNumberSC
+arbitraryString = choose (2, 20) >>= \n -> replicateM n (fmap chr $ choose (0,127)) >>= return . jsonStringSC
+arbitraryBool = arbitrary >>= return . jsonBoolSC
+
+arbitraryArray :: Int -> Gen JSON
+arbitraryArray 0 = return $ jsonArraySC []
+arbitraryArray x = frequency [
+ (1, return $ jsonArraySC []),
+ (1, choose (1,4) >>= \x -> replicateM x (arbitrary' (x-1)) >>= return . jsonArraySC)
+ ]
+
+arbitraryObject :: Int -> Gen JSON
+arbitraryObject 0 = return $ jsonObjectSC []
+arbitraryObject x = frequency [
+ (1, return $ jsonObjectSC []),
+ (1, do {
+ x <- choose (1, 4);
+ xs <- replicateM x $ choose (2,20) >>= \x -> replicateM x arbitrary;
+ ys <- replicateM x $ arbitrary' (x-1);
+ return $ jsonObjectSC (zip xs ys)
+ })
+ ]
+
+instance Arbitrary JSON where
+ arbitrary = arbitrary' 10
+
+main = defaultMain tests
+
+prop_computes_null = total $ jsonNullSC
+prop_computes_number n = total $ jsonNumberSC n
+prop_computes_string s = total $ jsonStringSC s
+prop_computes_bool b = total $ jsonBoolSC b
+prop_computes_array xs = total $ jsonArraySC xs
+prop_computes_object xs = total $ jsonObjectSC xs
+
+prop_null_refl = jsonNullSC == jsonNullSC
+prop_number_refl n = jsonNumberSC n == jsonNumberSC n
+prop_string_refl s = jsonStringSC s == jsonStringSC s
+prop_bool_refl b = jsonBoolSC b == jsonBoolSC b
+prop_array_refl xs = jsonArraySC xs == jsonArraySC xs
+prop_object_refl xs = jsonObjectSC xs == jsonObjectSC xs
+
+prop_null_not_equals_number n = jsonNullSC /= jsonNumberSC n
+prop_null_not_equals_string s = jsonNullSC /= jsonStringSC s
+prop_null_not_equals_bool b = jsonNullSC /= jsonBoolSC b
+prop_null_not_equals_array xs = jsonNullSC /= jsonArraySC xs
+prop_null_not_equals_object xs = jsonNullSC /= jsonObjectSC xs
+
+prop_number_not_equals_null n = jsonNumberSC n /= jsonNullSC
+prop_number_not_equals_string n s = jsonNumberSC n /= jsonStringSC s
+prop_number_not_equals_bool n b = jsonNumberSC n /= jsonBoolSC b
+prop_number_not_equals_array n xs = jsonNumberSC n /= jsonArraySC xs
+prop_number_not_equals_object n xs = jsonNumberSC n /= jsonObjectSC xs
+
+prop_string_not_equals_null s = jsonStringSC s /= jsonNullSC
+prop_string_not_equals_number s n = jsonStringSC s /= jsonNumberSC n
+prop_string_not_equals_bool s b = jsonStringSC s /= jsonBoolSC b
+prop_string_not_equals_array s xs = jsonStringSC s /= jsonArraySC xs
+prop_string_not_equals_object s xs = jsonStringSC s /= jsonObjectSC xs
+
+prop_bool_not_equals_null b = jsonBoolSC b /= jsonNullSC
+prop_bool_not_equals_number b n = jsonBoolSC b /= jsonNumberSC n
+prop_bool_not_equals_string b s = jsonBoolSC b /= jsonStringSC s
+prop_bool_not_equals_array b xs = jsonBoolSC b /= jsonArraySC xs
+prop_bool_not_equals_object b xs = jsonBoolSC b /= jsonObjectSC xs
+
+prop_array_not_equals_null xs = jsonArraySC xs /= jsonNullSC
+prop_array_not_equals_number xs n = jsonArraySC xs /= jsonNumberSC n
+prop_array_not_equals_string xs s = jsonArraySC xs /= jsonStringSC s
+prop_array_not_equals_bool xs b = jsonArraySC xs /= jsonBoolSC b
+prop_array_not_equals_object xs ys = jsonArraySC xs /= jsonObjectSC ys
+
+prop_object_not_equals_null xs = jsonObjectSC xs /= jsonNullSC
+prop_object_not_equals_number xs n = jsonObjectSC xs /= jsonNumberSC n
+prop_object_not_equals_string xs s = jsonObjectSC xs /= jsonStringSC s
+prop_object_not_equals_bool xs b = jsonObjectSC xs /= jsonBoolSC b
+prop_object_not_equals_array xs ys = jsonObjectSC xs /= jsonArraySC ys
+
+prop_show_null = show jsonNullSC == "null"
+prop_show_number n = show (jsonNumberSC n) == show n
+prop_show_string s = show (jsonStringSC s) == '\"' : s ++ "\""
+prop_show_bool_true = show (jsonBoolSC True) == "true"
+prop_show_bool_false = show (jsonBoolSC False) == "false"
+prop_show_empty_array = show (jsonArraySC []) == "[]"
+prop_show_array_one_element = show (jsonArraySC [jsonNullSC]) == "[\n null\n]"
+prop_show_empty_object = show (jsonObjectSC []) == "{}"
+prop_show_object_one_element = show (jsonObjectSC [("key", jsonNullSC)]) == "{\n \"key\": null\n}"
+
+tests = testGroup "Week 3 tests" [
+ testGroup "Constructors are defined" [
+ testProperty "Constructor for null computes" prop_computes_null
+ , testProperty "Constructor for numbers computes" prop_computes_number
+ , testProperty "Constructor for strings computes" prop_computes_string
+ , testProperty "Constructor for booleans computes" prop_computes_bool
+ , testProperty "Constructor for array computes" prop_computes_array
+ , testProperty "Constructor for objects computes" prop_computes_object
+ ],
+ testGroup "Reflection instances" [
+ testProperty "Reflection null" prop_null_refl
+ , testProperty "Reflection number" prop_number_refl
+ , testProperty "Reflection string" prop_string_refl
+ , testProperty "Reflection bool" prop_bool_refl
+ , testProperty "Reflection array" prop_array_refl
+ , testProperty "Reflection object" prop_object_refl
+ ],
+ testGroup "Inequality null" [
+ testProperty "Inequality null number" prop_null_not_equals_number
+ , testProperty "Inequality null string" prop_null_not_equals_string
+ , testProperty "Inequality null bool" prop_null_not_equals_bool
+ , testProperty "Inequality null array" prop_null_not_equals_array
+ , testProperty "Inequality null object" prop_null_not_equals_object
+ ],
+ testGroup "Inequality number" [
+ testProperty "Inequality number null" prop_number_not_equals_null
+ , testProperty "Inequality number string" prop_number_not_equals_string
+ , testProperty "Inequality number bool" prop_number_not_equals_bool
+ , testProperty "Inequality number array" prop_number_not_equals_array
+ , testProperty "Inequality number object" prop_number_not_equals_object
+ ],
+ testGroup "Inequality string" [
+ testProperty "Inequality string null" prop_string_not_equals_null
+ , testProperty "Inequality string number" prop_string_not_equals_number
+ , testProperty "Inequality string bool" prop_string_not_equals_bool
+ , testProperty "Inequality string array" prop_string_not_equals_array
+ , testProperty "Inequality string object" prop_string_not_equals_object
+ ],
+ testGroup "Inequality bool" [
+ testProperty "Inequality bool null" prop_bool_not_equals_null
+ , testProperty "Inequality bool number" prop_bool_not_equals_number
+ , testProperty "Inequality bool string" prop_bool_not_equals_string
+ , testProperty "Inequality bool array" prop_bool_not_equals_array
+ , testProperty "Inequality bool object" prop_bool_not_equals_object
+ ],
+ testGroup "Inequality array" [
+ testProperty "Inequality array null" prop_array_not_equals_null
+ , testProperty "Inequality array number" prop_array_not_equals_number
+ , testProperty "Inequality array string" prop_array_not_equals_string
+ , testProperty "Inequality array bool" prop_array_not_equals_bool
+ , testProperty "Inequality array object" prop_array_not_equals_object
+ ],
+ testGroup "Inequality object" [
+ testProperty "Inequality object null" prop_object_not_equals_null
+ , testProperty "Inequality object number" prop_object_not_equals_number
+ , testProperty "Inequality object string" prop_object_not_equals_string
+ , testProperty "Inequality object bool" prop_object_not_equals_bool
+ , testProperty "Inequality object array" prop_object_not_equals_array
+ ],
+ testGroup "Show instances" [
+ testProperty "Show null" prop_show_null
+ , testProperty "Show number" prop_show_number
+ , testProperty "Show string" prop_show_string
+ , testProperty "Show true" prop_show_bool_true
+ , testProperty "Show false" prop_show_bool_false
+ , testProperty "Show empty array" prop_show_empty_array
+ , testProperty "Show array one element" prop_show_array_one_element
+ , testProperty "Show empty object" prop_show_empty_object
+ , testProperty "Show object one element" prop_show_object_one_element
+ ]]
diff --git a/test/week4/Main.hs b/test/week4/Main.hs
new file mode 100644
index 0000000..8eb48d3
--- /dev/null
+++ b/test/week4/Main.hs
@@ -0,0 +1,189 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE StandaloneDeriving #-}
+
+module Main where
+
+import Control.DeepSeq
+import Control.Monad
+import Data.Either (fromRight, isLeft, isRight)
+import Data.List
+import GHC.Generics (Generic, Generic1)
+import Jq.Compiler
+ ( compile,
+ run,
+ )
+import Jq.Filters
+ ( Filter (..),
+ filterCommaSC,
+ filterIdentitySC,
+ filterPipeSC,
+ filterStringIndexingSC,
+ )
+import Jq.Json
+ ( JSON (..),
+ jsonArraySC,
+ jsonBoolSC,
+ jsonNullSC,
+ jsonNumberSC,
+ jsonObjectSC,
+ jsonStringSC,
+ )
+import System.Exit
+import Test.QuickCheck
+import Test.Tasty (defaultMain, testGroup)
+import Test.Tasty.QuickCheck (testProperty)
+
+{--
+ It can be that one (or both) of these two derivation fail.
+ Especially if you introduce some non-trivial constructors
+ or if your definition of filter is mutually recursive with
+ some other definition.
+ This doesn't necessarily mean that you're doing anything wrong.
+ You can try fixing it yourself by adding
+ `deriving instance Generic X` and
+ `deriving instance NFData X` below for the missing classes.
+ In case this doesn't work reach out to the course team.
+--}
+deriving instance Generic JSON
+
+deriving instance NFData JSON
+
+instance Arbitrary JSON where
+ arbitrary = do
+ n <- arbitrary :: Gen Int
+ s <- arbitrary :: Gen String
+ b <- arbitrary :: Gen Bool
+ xs <- frequency [(1, return []), (5, do x <- arbitrary; return [x])]
+ ys <- frequency [(1, return []), (5, do x <- arbitrary; s <- arbitrary; return [(s, x)])]
+
+ elements [jsonNullSC, jsonNumberSC n, jsonStringSC s, jsonBoolSC b, jsonArraySC xs, jsonObjectSC ys]
+
+deriving instance Generic Filter
+
+deriving instance NFData Filter
+
+instance Arbitrary Filter where
+ arbitrary = do
+ id <- arbitrary :: Gen String
+ f <- arbitrary
+ frequency [(5, return filterIdentitySC), (5, return (filterStringIndexingSC id)), (1, return (filterPipeSC f f)), (1, return (filterCommaSC f f))]
+
+main = defaultMain tests
+
+tests =
+ testGroup
+ "Week 4 tests"
+ [ testGroup
+ "Constructors are defined"
+ [ testProperty "Constructor for identity computes" prop_computes_identity,
+ testProperty "Constructor for indexing computes" prop_computes_indexing,
+ testProperty "Constructor for pipe computes" prop_computes_pipe,
+ testProperty "Constructor for comma computes" prop_computes_comma
+ ],
+ testGroup
+ "Reflection instances"
+ [ testProperty "Reflection identity" prop_identity_refl,
+ testProperty "Reflection indexing" prop_indexing_refl,
+ testProperty "Reflection pipe" prop_pipe_refl,
+ testProperty "Reflection comma" prop_comma_refl
+ ],
+ testGroup
+ "Identity"
+ [ testProperty "Identity functionality" prop_identity
+ ],
+ testGroup
+ "Indexing"
+ [ testProperty "Indexing existing keys" prop_index_existent,
+ testProperty "Indexing non-existing keys" prop_index_non_existent,
+ testProperty "Indexing null" prop_index_null,
+ testProperty "Indexing numbers" prop_index_number,
+ testProperty "Indexing strings" prop_index_string,
+ testProperty "Indexing booleans" prop_index_bool,
+ testProperty "Indexing arrays" prop_index_array
+ ],
+ testGroup
+ "Pipe"
+ [ testProperty "Pipe with identity on the right" prop_pipe_identity_right,
+ testProperty "Pipe with identity on the left" prop_pipe_identity_left,
+ testProperty "An error on the left of the pipe leads to an error" prop_pipe_carries_error
+ ],
+ testGroup
+ "Comma"
+ [ testProperty "Comma with identical filters leads to duplicate output" prop_comma_duplicates,
+ testProperty "An error on the left of the comma leads to an error" prop_comma_carries_error,
+ testProperty "Comma with two identities duplcates the input" prop_comma_identity
+ ]
+ ]
+
+prop_computes_identity = total $ filterIdentitySC
+
+prop_computes_indexing id = total $ filterStringIndexingSC id
+
+prop_computes_pipe f g = total $ filterPipeSC f g
+
+prop_computes_comma f g = total $ filterCommaSC f g
+
+prop_identity_refl = filterIdentitySC == filterIdentitySC
+
+prop_indexing_refl f g =
+ f
+ == g
+ ==> filterStringIndexingSC f
+ == filterStringIndexingSC g
+
+prop_pipe_refl e f g h =
+ e
+ == g
+ && f
+ == h
+ ==> filterPipeSC e f
+ == filterPipeSC g h
+
+prop_comma_refl e f g h =
+ e
+ == g
+ && f
+ == h
+ ==> filterCommaSC e f
+ == filterCommaSC g h
+
+prop_identity j = run (compile filterIdentitySC) j == Right [j]
+
+prop_index_existent s j = run (compile $ filterStringIndexingSC s) (jsonObjectSC [(s, j)]) == Right [j]
+
+prop_index_non_existent s t j =
+ s
+ /= t
+ ==> run (compile $ filterStringIndexingSC t) (jsonObjectSC [(s, j)])
+ == Right [jsonNullSC]
+
+prop_index_null s = run (compile $ filterStringIndexingSC s) jsonNullSC == Right [jsonNullSC]
+
+prop_index_number n s = isLeft $ run (compile $ filterStringIndexingSC s) (jsonNumberSC n)
+
+prop_index_string s t = isLeft $ run (compile $ filterStringIndexingSC s) (jsonStringSC t)
+
+prop_index_bool b s = isLeft $ run (compile $ filterStringIndexingSC s) (jsonBoolSC b)
+
+prop_index_array j s = isLeft $ run (compile $ filterStringIndexingSC s) (jsonArraySC [j])
+
+prop_pipe_identity_right f j = run (compile $ filterPipeSC f filterIdentitySC) j == compile f j
+
+prop_pipe_identity_left f j = run (compile $ filterPipeSC filterIdentitySC f) j == compile f j
+
+prop_pipe_carries_error f g j =
+ isLeft (run (compile f) j)
+ ==> isLeft (run (compile $ filterPipeSC f g) j)
+
+prop_comma_duplicates f j =
+ let res = run (compile f) j
+ in isRight res
+ ==> run (compile $ filterCommaSC f f) j
+ == Right (fromRight [] res ++ fromRight [] res)
+
+prop_comma_carries_error f g j =
+ isLeft (run (compile f) j)
+ ==> isLeft (run (compile $ filterCommaSC f g) j)
+
+prop_comma_identity j = run (compile $ filterCommaSC filterIdentitySC filterIdentitySC) j == Right [j, j]