{"id":26159872,"url":"https://github.com/spamegg1/tarski","last_synced_at":"2026-04-02T14:54:56.859Z","repository":{"id":273403874,"uuid":"867752089","full_name":"spamegg1/tarski","owner":"spamegg1","description":"Tarski's world: semantics of first-order logic","archived":false,"fork":false,"pushed_at":"2026-03-27T09:40:31.000Z","size":845,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-27T19:49:27.606Z","etag":null,"topics":["first-order-logic","logic","scala3","tarski","world"],"latest_commit_sha":null,"homepage":"https://spamegg1.github.io/tarski's-world/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spamegg1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-10-04T16:44:52.000Z","updated_at":"2026-03-27T09:40:35.000Z","dependencies_parsed_at":"2025-09-01T22:10:22.798Z","dependency_job_id":"d31f0028-eb06-41cb-92c7-2ee070fbf812","html_url":"https://github.com/spamegg1/tarski","commit_stats":null,"previous_names":["spamegg1/tarski"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/spamegg1/tarski","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spamegg1%2Ftarski","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spamegg1%2Ftarski/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spamegg1%2Ftarski/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spamegg1%2Ftarski/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spamegg1","download_url":"https://codeload.github.com/spamegg1/tarski/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spamegg1%2Ftarski/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31308448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["first-order-logic","logic","scala3","tarski","world"],"created_at":"2025-03-11T11:37:01.206Z","updated_at":"2026-04-02T14:54:56.854Z","avatar_url":"https://github.com/spamegg1.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tarski's world\n\nAn educational tool for the semantics of\n[first-order logic](https://en.wikipedia.org/wiki/First-order_logic)\n\n\u003chttps://github.com/user-attachments/assets/3b1d3352-e1f1-436e-ac52-5110b62c98c3\u003e\n\n## About\n\nAttempting to recreate Barwise and Etchemendy's\n[Tarski's world](https://www.gradegrinder.net/Products/tw-index.html)\nin [Doodle's Reactor](https://github.com/creativescala/doodle)\nusing [Scala 3](https://www.scala-lang.org).\n(I might switch to ScalaFX later.)\n\nThey use 3D objects (cube, tetrahedron, dodecahedron) but I'm going with 2D as in\n[Epp's book](https://github.com/spamegg1/Epp-Discrete-Math-5th-solutions/).\n\n## Acknowledgements\n\nThanks a lot to [Noel Welsh](https://github.com/noelwelsh) for his awesome Doodle library\nand all the help on Discord.\n\nThanks to Jon Barwise (1942-2000) and John Etchemendy for their awesome idea and book\non Tarski's world.\n\n## Dev Blog\n\nSee my adventures in bad design on my\n[Github Pages](https://spamegg1.github.io/tarski's-world/)\n\n## Info\n\nThis is a [Scala-cli](https://scala-cli.virtuslab.org/) project.\nWith Scala 3.5.0 and above, you can simply run `scala compile .` and `scala test .`.\n\n## Module dependency\n\n```scala\n//     main\n//       |\n//     view   testing\n//       |     /\n//    controller\n//       |\n//     model\n//       |\n//    constants\n```\n\nYou can read more about each module at:\n\n- [Constants](constants/README.md)\n- [Model](model/README.md)\n- [Controller](controller/README.md)\n- [View](view/README.md)\n- [Test](test/README.md)\n- [Main](main/README.md)\n\n## Installation\n\nCurrent version is 0.2.7 (Mar 28, 2026). Released for Scala 3 only.\n\nYou will need a JVM, and Scala 3. [This](https://www.scala-lang.org/download/)\nshould give you everything you need.\n\nAlso you'll need an IDE:\n\n- [Metals](https://scalameta.org/metals/) extension on\n  [Visual Studio Code](https://code.visualstudio.com/)\n- [IntelliJ](https://www.jetbrains.com/idea/download/) with Scala plugin\n\nFor Scala-cli (or just plain `scala`), add to your `project.scala` (or any file):\n\n```scala\n//\u003e using dep io.github.spamegg1::tarski:0.2.7\n```\n\nFor SBT, add to your `build.sbt`:\n\n```scala\nlibraryDependencies += \"io.github.spamegg1\" %% \"tarski\" % \"0.2.7\"\n```\n\n## API Docs and artifacts\n\nDocs can be found at [Javadoc](https://javadoc.io/doc/io.github.spamegg1/tarski_3/latest/index.html)\n\nArtifacts at [Maven Central](https://repo1.maven.org/maven2/io/github/spamegg1/tarski_3/)\n\n## Usage\n\nTo get a quick look and feel, you can execute `tarski.main.Example.runExample`.\n\nTo play a quick game, you can execute `tarski.main.Example.playGame`.\nSee below for more on game mode.\n\n*Note:* In Scala 3.8.2+ you can run the example directly from the Scala REPL.\nJust `:dep io.github.spamegg1::tarski:0.2.7` then `tarski.main.Example.runExample`.\n\nTarski's world is intended to be used interactively inside an IDE\nsuch as IntelliJ or Visual Studio Code.\n\nGenerally, in an educational setting, a world and a list of formulas are given to you.\nThen you run the program to evaluate the formulas, move or change the blocks,\nadd or change the formulas if necessary, based on what you are asked to do in exercises.\nOf course, you can write your own worlds and formulas too.\n\n### Running: an example\n\nThen run it with `tarski.main.runWorld` to start interacting.\nYou will see the interactive window like the one above in the video.\nHere are the details:\n\n```scala\n//\u003e using dep io.github.spamegg1::tarski:0.2.7\n\nimport tarski.main.*, Shape.*, Sizes.*, Tone.*\n\nval grid: Grid = Map(\n  (1, 2) -\u003e Block(Sml, Tri, Lim, \"a\"),\n  (4, 3) -\u003e Block(Mid, Tri, Blu),\n  (5, 6) -\u003e Block(Big, Cir, Red, \"d\"),\n  (6, 3) -\u003e Block(Sml, Sqr, Blu)\n)\n\nval formulas = Seq(\n  fof\"¬(∃x Big(x))\",\n  fof\"∀x Sqr(x)\",\n  fof\"∀x ¬ Cir(x)\",\n  fof\"¬(∀x Sml(x))\",\n  fof\"∃x Tri(x)\",\n  fof\"∀x (¬(Shp(c, x) ∨ Les(x, c)) → ¬Ton(x, c))\",\n  fof\"∃x Cir(x)\",\n  fof\"a = b\",\n  fof\"∀x ∃y Mor(x, y)\",\n  fof\"c != d\",\n  fof\"∀x (Squ(x) → Tri(x))\",\n  fof\"∃x (Tri(x) ↔ Mid(x))\",\n  fof\"¬(∃x (Cir(x) ∧ Sml(x)))\",\n)\n\n// The interface is 1600x800 by default.\n// if the interface is too small or too large, try a different scale factor than 1.0:\n@main\ndef run = runWorld(grid, formulas, 1.0)\n```\n\nYou can add or remove blocks interactively.\nTo edit the formulas, close the window, edit them in your IDE, then restart.\n\n### Imports\n\nAll you need is to `import tarski.main.*`.\nOptionally you can also `import Shape.*, Sizes.*, Tone.*`\nto avoid repeatedly writing `Shape.`, `Sizes.` or `Tone.`.\n\n### Blocks\n\nBlocks have 3 attributes, each of which has 3 possible values:\n\n|Attr | 1 | 2 | 3 |\n|:----|:--|:--|:--|\n|Tone |Blu|Lim|Red|\n|Shape|Tri|Sqr|Cir|\n|Sizes|Sml|Mid|Big|\n\nBlocks can also have an optional name, only one of: `a, b, c, d, e, f`.\nOther names are not allowed. Formulas can then refer to these names as constants.\n\n### Grids\n\nThen you can write a `Grid`, a map of positions `Pos` to `Block`s, to define the board.\nIt's an 8x8 standard chess board; coordinates are 0-indexed.\nSee above for details and an example.\n\n### Formulas\n\nThen you can write a list of first-order logic formulas, `FOLFormula`\n(courtesy of [Gapt](https://github.com/gapt/gapt)).\n\nThe formulas use a special string interpolator `fof\"...\"`,\nand can use the Unicode symbols or their ASCII equivalents for logical connectives:\n\n|Connective   |ASCII|Unicode|\n|:------------|:----|:------|\n|and          |`\u0026`  |`∧`    |\n|or           |`\\|` |`∨`    |\n|not          |`-`  |`¬`    |\n|implies      |`-\u003e` |`→`    |\n|biconditional|`\u003c-\u003e`|`↔`    |\n|forall       |`!`  |`∀`    |\n|exists       |`?`  |`∃`    |\n\n### Predicates for atomic formulas\n\n**NOTE:** Many of these predicate names are shortened from their normal spellings\n(like Small -\u003e `Sml`, Right -\u003e `Rgt`) in order to fit longer formulas on the screen.\nPlease study them carefully. Apologies for any confusion!\n\nThe following predicates are supported:\n\n#### Unary\n\n|Syntax  |Semantics        |\n|:-------|:----------------|\n|`Tri(x)`|x is a triangle  |\n|`Sqr(x)`|x is a square    |\n|`Cir(x)`|x is a circle    |\n|`Blu(x)`|x has color blue |\n|`Lim(x)`|x has color lime |\n|`Red(x)`|x has color red  |\n|`Sml(x)`|x has small size |\n|`Mid(x)`|x has medium size|\n|`Big(x)`|x has big size   |\n\n#### Binary\n\n|Syntax     |Semantics                                    |\n|:----------|:--------------------------------------------|\n|`Lft(x, y)`|x is to the left of y                        |\n|`Rgt(x, y)`|x is to the right of y                       |\n|`Bel(x, y)`|x is below y                                 |\n|`Abv(x, y)`|x is above y                                 |\n|`Adj(x, y)`|x is adjacent (but not diagonally) to y      |\n|`Les(x, y)`|x is smaller in size than y                  |\n|`Mor(x, y)`|x is bigger in size than y                   |\n|`Row(x, y)`|x is on the same row as y                    |\n|`Col(x, y)`|x is on the same column as y                 |\n|`Siz(x, y)`|x has the same size as y                     |\n|`Shp(x, y)`|x has the same shape as y                    |\n|`Ton(x, y)`|x has the same tone as y                     |\n|`Eq(x, y)` |x is equal to y (in size, shape and tone)    |\n|`x = y`    |x and y are at the same location on the board|\n\n#### Ternary\n\n|Syntax        |Semantics                                                          |\n|:-------------|:------------------------------------------------------------------|\n|`Btw(x, y, z)`|\"x is between y and z (vertically, horizontally or 45° diagonally)\"|\n\n##### Note on equality\n\nNormally in first-order logic, equality is interpreted as \"reference equality\",\nmeaning, `x = y` if both `x` and `y` refer to the same object (number, set, etc.)\n\nThe original Tarski's World app lets you assign multiple names to the same block,\nwhich makes it possible for `x = y` reference equality to be true with 1 block.\nHere we do not allow that, because having multiple names is a bit confusing.\nOur blocks can only have up to 1 name, so `x = y` is always false\nunder reference equality whenever `x` and `y` refer to separate blocks.\n\nWe interpret `=` as reference equality, where `x = y` if\n`x` and `y` are at the same location (row and column) on the board,\ntherefore they represent the same block.\nThis allows us to express things like \"there are exactly four blocks\" kind of sentences.\n\nHowever reference equality is not always desirable.\nSo we have another binary predicate `Eq` as \"value equality\",\nwhere two separate blocks can be equal\nif they have all the same attributes (size, shape, tone).\n\nSo we have both kinds of equality available to us 😄\n\n## Game mode\n\n\u003chttps://github.com/user-attachments/assets/b9b08a2d-42dd-4ec4-882c-3fd1d41cf307\u003e\n\nYou can play a game against Tarski's world to defend your position\nabout the truth of a formula in a world.\nYou need a grid and a formula, then run `playGame` with them:\n\n```scala\n//\u003e using dep io.github.spamegg1::tarski:0.2.7\n\nimport tarski.main.*, Shape.*, Sizes.*, Tone.*\n\nval grid: Grid = Map(\n  (1, 2) -\u003e Block(Sml, Tri, Lim, \"a\"),\n  (4, 3) -\u003e Block(Mid, Tri, Blu),\n  (5, 6) -\u003e Block(Big, Cir, Red, \"d\"),\n  (6, 3) -\u003e Block(Sml, Sqr, Blu)\n)\n\nval formula = fof\"∀x ∃y (Mor(x, y) ∨ Abv(y, x))\"\n\n// The interface is 1600x800 by default.\n// if the interface is too small or too large, try a different scale factor than 1.0:\n@main\ndef run = playGame(grid, formula, 1.0)\n```\n\n## Exercises\n\nYou can work through the examples in the\n[companion repository](https://github.com/spamegg1/tarski-examples)\n\n## Work in progress\n\nStay tuned!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspamegg1%2Ftarski","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspamegg1%2Ftarski","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspamegg1%2Ftarski/lists"}