├── apps ├── game │ ├── test │ │ ├── test_helper.exs │ │ └── game_test.exs │ ├── lib │ │ ├── hive.ex │ │ ├── tile.ex │ │ ├── tree.ex │ │ ├── honey_drop.ex │ │ ├── viewport.ex │ │ ├── field.ex │ │ ├── bear.ex │ │ ├── player.ex │ │ ├── bee.ex │ │ └── game_server.ex │ ├── .formatter.exs │ ├── README.md │ ├── .gitignore │ ├── mix.exs │ └── config │ │ └── config.exs ├── bear_necessities │ ├── README.md │ ├── priv │ │ └── repo │ │ │ ├── migrations │ │ │ └── .formatter.exs │ │ │ └── seeds.exs │ ├── test │ │ ├── test_helper.exs │ │ └── support │ │ │ └── data_case.ex │ ├── lib │ │ ├── bear_necessities │ │ │ ├── repo.ex │ │ │ └── application.ex │ │ └── bear_necessities.ex │ ├── .formatter.exs │ ├── config │ │ ├── config.exs │ │ ├── prod.exs │ │ ├── dev.exs │ │ └── test.exs │ ├── .gitignore │ └── mix.exs └── bear_necessities_web │ ├── assets │ ├── .babelrc │ ├── static │ │ ├── favicon.ico │ │ ├── images │ │ │ ├── bear │ │ │ │ ├── up.gif │ │ │ │ ├── dead.gif │ │ │ │ ├── down.gif │ │ │ │ ├── left.gif │ │ │ │ ├── right.gif │ │ │ │ ├── up-claw.gif │ │ │ │ ├── up-idle.gif │ │ │ │ ├── down-claw.gif │ │ │ │ ├── down-idle.gif │ │ │ │ ├── left-claw.gif │ │ │ │ ├── left-idle.gif │ │ │ │ ├── right-claw.gif │ │ │ │ └── right-idle.gif │ │ │ ├── bees │ │ │ │ ├── bees.gif │ │ │ │ └── bees-1.gif │ │ │ ├── honey │ │ │ │ └── drop.gif │ │ │ ├── trees │ │ │ │ ├── tree-1.gif │ │ │ │ └── treehive.gif │ │ │ └── terain │ │ │ │ ├── grass-1.gif │ │ │ │ ├── grass-2.gif │ │ │ │ ├── grass-3.gif │ │ │ │ ├── grass-4.gif │ │ │ │ └── nothing.gif │ │ ├── sound │ │ │ └── game-sound.mp3 │ │ └── robots.txt │ ├── postcss.config.js │ ├── css │ │ ├── base.css │ │ ├── app.css │ │ ├── game │ │ │ ├── lobby.css │ │ │ ├── scoreboard.css │ │ │ └── game.css │ │ └── form.css │ ├── js │ │ ├── app.js │ │ └── socket.js │ ├── package.json │ └── webpack.config.js │ ├── test │ ├── test_helper.exs │ ├── bear_necessities_web │ │ └── views │ │ │ ├── layout_view_test.exs │ │ │ ├── error_view_test.exs │ │ │ └── playfield_test.exs │ └── support │ │ ├── channel_case.ex │ │ └── conn_case.ex │ ├── .formatter.exs │ ├── lib │ ├── bear_necessities_web │ │ ├── views │ │ │ ├── layout_view.ex │ │ │ ├── error_view.ex │ │ │ ├── playfield.ex │ │ │ └── error_helpers.ex │ │ ├── templates │ │ │ ├── playfield │ │ │ │ ├── scoreboard.html.leex │ │ │ │ └── template.html.leex │ │ │ └── layout │ │ │ │ └── app.html.eex │ │ ├── router.ex │ │ ├── gettext.ex │ │ ├── application.ex │ │ ├── channels │ │ │ └── user_socket.ex │ │ ├── endpoint.ex │ │ └── live │ │ │ └── game.ex │ └── bear_necessities_web.ex │ ├── config │ ├── test.exs │ ├── config.exs │ ├── dev.exs │ └── prod.exs │ ├── README.md │ ├── .gitignore │ ├── mix.exs │ └── priv │ └── gettext │ ├── en │ └── LC_MESSAGES │ │ └── errors.po │ └── errors.pot ├── Procfile ├── elixir_buildpack.config ├── .formatter.exs ├── artwork ├── back.aseprite ├── death.aseprite ├── front.aseprite ├── grave.aseprite ├── rotate.aseprite ├── side.aseprite ├── back-attack.aseprite ├── side-attack.aseprite └── front-attack.aseprite ├── config ├── prod.exs ├── test.exs ├── dev.exs └── config.exs ├── phoenix_static_buildpack.config ├── .gitignore ├── mix.exs ├── README.md ├── circle.yml └── mix.lock /apps/game/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: mix phx.server 2 | release: POOL_SIZE=2 mix ecto.migrate 3 | -------------------------------------------------------------------------------- /apps/bear_necessities/README.md: -------------------------------------------------------------------------------- 1 | # BearNecessities 2 | 3 | **TODO: Add description** 4 | -------------------------------------------------------------------------------- /apps/game/lib/hive.ex: -------------------------------------------------------------------------------- 1 | defmodule Hive do 2 | defstruct hp: nil, honey: nil 3 | end 4 | -------------------------------------------------------------------------------- /apps/game/lib/tile.ex: -------------------------------------------------------------------------------- 1 | defmodule Tile do 2 | defstruct [:type, :texture] 3 | end 4 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /elixir_buildpack.config: -------------------------------------------------------------------------------- 1 | erlang_version=21.1.4 2 | elixir_version=1.8.1 3 | always_rebuild=true 4 | -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: ["mix.exs", "config/*.exs"], 3 | subdirectories: ["apps/*"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/game/lib/tree.ex: -------------------------------------------------------------------------------- 1 | defmodule Tree do 2 | defstruct pos_x: nil, pos_y: nil, hive: nil 3 | end 4 | -------------------------------------------------------------------------------- /apps/game/lib/honey_drop.ex: -------------------------------------------------------------------------------- 1 | defmodule HoneyDrop do 2 | defstruct pos_x: nil, pos_y: nil, honey: 1 3 | end 4 | -------------------------------------------------------------------------------- /artwork/back.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/back.aseprite -------------------------------------------------------------------------------- /artwork/death.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/death.aseprite -------------------------------------------------------------------------------- /artwork/front.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/front.aseprite -------------------------------------------------------------------------------- /artwork/grave.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/grave.aseprite -------------------------------------------------------------------------------- /artwork/rotate.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/rotate.aseprite -------------------------------------------------------------------------------- /artwork/side.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/side.aseprite -------------------------------------------------------------------------------- /artwork/back-attack.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/back-attack.aseprite -------------------------------------------------------------------------------- /artwork/side-attack.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/side-attack.aseprite -------------------------------------------------------------------------------- /config/prod.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | 3 | # Do not print debug messages in production 4 | config :logger, level: :info 5 | -------------------------------------------------------------------------------- /config/test.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | 3 | # Print only warnings and errors during test 4 | config :logger, level: :warn 5 | -------------------------------------------------------------------------------- /apps/bear_necessities/priv/repo/migrations/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:ecto_sql], 3 | inputs: ["*.exs"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/bear_necessities/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | Ecto.Adapters.SQL.Sandbox.mode(BearNecessities.Repo, :manual) 3 | -------------------------------------------------------------------------------- /artwork/front-attack.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/artwork/front-attack.aseprite -------------------------------------------------------------------------------- /apps/bear_necessities_web/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | Ecto.Adapters.SQL.Sandbox.mode(BearNecessities.Repo, :manual) 3 | -------------------------------------------------------------------------------- /apps/game/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:phoenix], 3 | inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /phoenix_static_buildpack.config: -------------------------------------------------------------------------------- 1 | node_version=10.15.3 2 | yarn_version=1.15.0 3 | phoenix_relative_path=/apps/bear_necessities_web/ 4 | remove_node=true 5 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/views/layout_view.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.LayoutView do 2 | use BearNecessitiesWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/favicon.ico -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/up.gif -------------------------------------------------------------------------------- /apps/game/lib/viewport.ex: -------------------------------------------------------------------------------- 1 | defmodule ViewPort do 2 | defstruct fields: [] 3 | 4 | def get_viewport(id) do 5 | GenServer.call(Game, {:get_viewport, id}) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/dead.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/dead.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/down.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/left.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bees/bees.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bees/bees.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/sound/game-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/sound/game-sound.mp3 -------------------------------------------------------------------------------- /apps/bear_necessities_web/test/bear_necessities_web/views/layout_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.LayoutViewTest do 2 | use BearNecessitiesWeb.ConnCase, async: true 3 | end 4 | -------------------------------------------------------------------------------- /apps/bear_necessities/lib/bear_necessities/repo.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessities.Repo do 2 | use Ecto.Repo, 3 | otp_app: :bear_necessities, 4 | adapter: Ecto.Adapters.Postgres 5 | end 6 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/right.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/up-claw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/up-claw.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/up-idle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/up-idle.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bees/bees-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bees/bees-1.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/honey/drop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/honey/drop.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/trees/tree-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/trees/tree-1.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/down-claw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/down-claw.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/down-idle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/down-idle.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/left-claw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/left-claw.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/left-idle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/left-idle.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/terain/grass-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/terain/grass-1.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/terain/grass-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/terain/grass-2.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/terain/grass-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/terain/grass-3.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/terain/grass-4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/terain/grass-4.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/terain/nothing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/terain/nothing.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/trees/treehive.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/trees/treehive.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/right-claw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/right-claw.gif -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/images/bear/right-idle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefactoSoftware/BearNecessities/HEAD/apps/bear_necessities_web/assets/static/images/bear/right-idle.gif -------------------------------------------------------------------------------- /apps/bear_necessities/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:ecto], 3 | inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"], 4 | subdirectories: ["priv/*/migrations"] 5 | ] 6 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ident: "postcss", 3 | plugins: { 4 | "postcss-preset-env": { 5 | stage: 0 6 | }, 7 | "postcss-import": {}, 8 | "postcss-nested": {} 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /apps/bear_necessities/lib/bear_necessities.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessities do 2 | @moduledoc """ 3 | BearNecessities keeps the contexts that define your domain 4 | and business logic. 5 | 6 | Contexts are also responsible for managing your data, regardless 7 | if it comes from the database, an external API or others. 8 | """ 9 | end 10 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/css/base.css: -------------------------------------------------------------------------------- 1 | @import "../node_modules/normalize.css/normalize.css"; 2 | 3 | body { 4 | background: #363636; 5 | color: white; 6 | font-family: "Press Start 2P", Courier, monospace; 7 | font-size: 16px; 8 | margin: 0; 9 | text-shadow: 2px 2px rgba(0, 0, 0, 0.8); 10 | } 11 | 12 | h1 { 13 | text-shadow: 6px 6px rgba(0, 0, 0, 0.8); 14 | } 15 | -------------------------------------------------------------------------------- /apps/bear_necessities/config/config.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | config :bear_necessities, 8 | ecto_repos: [BearNecessities.Repo] 9 | 10 | import_config "#{Mix.env()}.exs" 11 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/css/app.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Press+Start+2P"); 2 | @import "../../../../deps/phoenix_live_view/assets/css/live_view.css"; 3 | 4 | @import "./base.css"; 5 | @import "./form.css"; 6 | @import "./game/lobby.css"; 7 | @import "./game/scoreboard.css"; 8 | @import "./game/game.css"; 9 | 10 | .preload-images { 11 | height: 0; 12 | width: 0; 13 | z-index: -1; 14 | } 15 | -------------------------------------------------------------------------------- /apps/bear_necessities/priv/repo/seeds.exs: -------------------------------------------------------------------------------- 1 | # Script for populating the database. You can run it as: 2 | # 3 | # mix run priv/repo/seeds.exs 4 | # 5 | # Inside the script, you can read and write to any of your 6 | # repositories directly: 7 | # 8 | # BearNecessities.Repo.insert!(%BearNecessities.SomeSchema{}) 9 | # 10 | # We recommend using the bang functions (`insert!`, `update!` 11 | # and so on) as they will fail if something goes wrong. 12 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/css/game/lobby.css: -------------------------------------------------------------------------------- 1 | .lobby { 2 | background: #44d873 url("/images/terain/grass-1.gif"); 3 | color: white; 4 | text-align: center; 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | bottom: 0; 9 | right: 0; 10 | image-rendering: pixelated; 11 | background-size: 20%; 12 | padding: 30px; 13 | 14 | h1 { 15 | font-size: 3em; 16 | } 17 | 18 | .player-image { 19 | width: 200px; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/dev.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | 3 | # Do not include metadata nor timestamps in development logs 4 | config :logger, :console, format: "[$level] $message\n" 5 | 6 | # Initialize plugs at runtime for faster development compilation 7 | config :phoenix, :plug_init_mode, :runtime 8 | 9 | # Set a higher stacktrace during development. Avoid configuring such 10 | # in production as building large stacktraces may be expensive. 11 | config :phoenix, :stacktrace_depth, 20 12 | -------------------------------------------------------------------------------- /apps/bear_necessities/lib/bear_necessities/application.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessities.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | def start(_type, _args) do 9 | children = [ 10 | BearNecessities.Repo, 11 | Game 12 | ] 13 | 14 | Supervisor.start_link(children, strategy: :one_for_one, name: BearNecessities.Supervisor) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /apps/bear_necessities/config/prod.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # Configure your database 8 | config :bear_necessities, BearNecessities.Repo, 9 | url: System.get_env("DATABASE_URL"), 10 | pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), 11 | ssl: true 12 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/config/test.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities_web application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # We don't run a server during test. If one is required, 8 | # you can enable the server option below. 9 | config :bear_necessities_web, BearNecessitiesWeb.Endpoint, 10 | http: [port: 4002], 11 | server: false 12 | -------------------------------------------------------------------------------- /apps/bear_necessities/config/dev.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # Configure your database 8 | config :bear_necessities, BearNecessities.Repo, 9 | username: "postgres", 10 | password: "postgres", 11 | database: "bear_necessities_dev", 12 | hostname: "localhost", 13 | pool_size: 10 14 | -------------------------------------------------------------------------------- /apps/bear_necessities/config/test.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # Configure your database 8 | config :bear_necessities, BearNecessities.Repo, 9 | username: "postgres", 10 | password: "postgres", 11 | database: "bear_necessities_test", 12 | hostname: "localhost", 13 | pool: Ecto.Adapters.SQL.Sandbox 14 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/templates/playfield/scoreboard.html.leex: -------------------------------------------------------------------------------- 1 |
<%= flash_info %>
13 | <% end %> 14 | <%= if flash_error = get_flash(@conn, :error) do %> 15 |<%= flash_error %>
16 | <% end %> 17 | 18 | <%= render @view_module, @view_template, assigns %> 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /apps/bear_necessities/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | bear_necessities-*.tar 24 | 25 | # Files matching config/*.secret.exs pattern contain sensitive 26 | # data and you should not commit them into version control. 27 | # 28 | # Alternatively, you may comment the line below and commit the 29 | # secrets files as long as you replace their contents by environment 30 | # variables. 31 | /config/*.secret.exs 32 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "repository": {}, 3 | "license": "MIT", 4 | "scripts": { 5 | "deploy": "webpack --mode production", 6 | "watch": "webpack --mode development --watch" 7 | }, 8 | "dependencies": { 9 | "normalize.css": "^8.0.1", 10 | "phoenix": "file:../../../deps/phoenix", 11 | "phoenix_html": "file:../../../deps/phoenix_html", 12 | "phoenix_live_view": "file:../../../deps/phoenix_live_view" 13 | }, 14 | "devDependencies": { 15 | "@babel/core": "^7.0.0", 16 | "@babel/preset-env": "^7.0.0", 17 | "babel-loader": "^8.0.0", 18 | "copy-webpack-plugin": "^4.5.0", 19 | "css-loader": "^2.1.1", 20 | "mini-css-extract-plugin": "^0.4.0", 21 | "optimize-css-assets-webpack-plugin": "^4.0.0", 22 | "postcss-import": "^12.0.1", 23 | "postcss-loader": "^3.0.0", 24 | "postcss-nested": "^4.1.2", 25 | "postcss-preset-env": "^6.6.0", 26 | "uglifyjs-webpack-plugin": "^1.2.4", 27 | "webpack": "4.4.0", 28 | "webpack-cli": "^2.0.10" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/application.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | def start(_type, _args) do 9 | # List all child processes to be supervised 10 | children = [ 11 | # Start the endpoint when the application starts 12 | BearNecessitiesWeb.Endpoint 13 | # Starts a worker by calling: BearNecessitiesWeb.Worker.start_link(arg) 14 | # {BearNecessitiesWeb.Worker, arg}, 15 | ] 16 | 17 | # See https://hexdocs.pm/elixir/Supervisor.html 18 | # for other strategies and supported options 19 | opts = [strategy: :one_for_one, name: BearNecessitiesWeb.Supervisor] 20 | Supervisor.start_link(children, opts) 21 | end 22 | 23 | # Tell Phoenix to update the endpoint configuration 24 | # whenever the application is updated. 25 | def config_change(changed, _new, removed) do 26 | BearNecessitiesWeb.Endpoint.config_change(changed, removed) 27 | :ok 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # By default, the umbrella project as well as each child 6 | # application will require this configuration file, as 7 | # configuration and dependencies are shared in an umbrella 8 | # project. While one could configure all applications here, 9 | # we prefer to keep the configuration of each individual 10 | # child application in their own app, but all other 11 | # dependencies, regardless if they belong to one or multiple 12 | # apps, should be configured in the umbrella to avoid confusion. 13 | import_config "../apps/*/config/config.exs" 14 | 15 | # Configures Elixir's Logger 16 | config :logger, :console, 17 | format: "$time $metadata[$level] $message\n", 18 | metadata: [:request_id] 19 | 20 | # Use Jason for JSON parsing in Phoenix 21 | config :phoenix, :json_library, Jason 22 | 23 | # Import environment specific config. This must remain at the bottom 24 | # of this file so it overrides the configuration defined above. 25 | import_config "#{Mix.env()}.exs" 26 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/config/config.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities_web application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # General application configuration 8 | config :bear_necessities_web, 9 | ecto_repos: [BearNecessities.Repo], 10 | generators: [context_app: :bear_necessities] 11 | 12 | # Configures the endpoint 13 | config :bear_necessities_web, BearNecessitiesWeb.Endpoint, 14 | url: [host: "localhost"], 15 | secret_key_base: "XGyIQiCWhwimCTtX1G470XJdDMgNqYBgjETuYNYeqbYLHj1ATH2IaTtM2Z5iF8JN", 16 | render_errors: [view: BearNecessitiesWeb.ErrorView, accepts: ~w(html json)], 17 | live_view: [signing_salt: "0nq3UJ4Q"], 18 | pubsub: [name: BearNecessitiesWeb.PubSub, adapter: Phoenix.PubSub.PG2] 19 | 20 | # Import environment specific config. This must remain at the bottom 21 | # of this file so it overrides the configuration defined above. 22 | import_config "#{Mix.env()}.exs" 23 | 24 | config :phoenix, 25 | template_engines: [leex: Phoenix.LiveView.Engine] 26 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/test/support/channel_case.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.ChannelCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | channel tests. 5 | 6 | Such tests rely on `Phoenix.ChannelTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | it cannot be async. For this reason, every test runs 12 | inside a transaction which is reset at the beginning 13 | of the test unless the test case is marked as async. 14 | """ 15 | 16 | use ExUnit.CaseTemplate 17 | 18 | using do 19 | quote do 20 | # Import conveniences for testing with channels 21 | use Phoenix.ChannelTest 22 | 23 | # The default endpoint for testing 24 | @endpoint BearNecessitiesWeb.Endpoint 25 | end 26 | end 27 | 28 | setup tags do 29 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(BearNecessities.Repo) 30 | 31 | unless tags[:async] do 32 | Ecto.Adapters.SQL.Sandbox.mode(BearNecessities.Repo, {:shared, self()}) 33 | end 34 | 35 | :ok 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BearNecessities.Umbrella 2 | 3 | | Front | Side | Back | 4 | | - | - | -| 5 | |  |  |  | 6 | |  |  |  | 7 | 8 | | Death | 9 | | - | 10 | |  | 11 | 12 | ## Install 13 | 14 | * Run `mix deps.get` in the main dir 15 | * Run `mix ecto.create` in the main dir 16 | * Run `yarn` in `apps/bear_necessities_web/assets` 17 | 18 | ## Running 19 | 20 | Start with mix phx.server, go to https://localhost:4000/ and wait for the assets to compile 21 | -------------------------------------------------------------------------------- /apps/game/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for 9 | # third-party users, it should be done in your "mix.exs" file. 10 | 11 | # You can configure your application as: 12 | # 13 | # config :game, key: :value 14 | # 15 | # and access this configuration in your application as: 16 | # 17 | # Application.get_env(:game, :key) 18 | # 19 | # You can also configure a third-party app: 20 | # 21 | # config :logger, level: :info 22 | # 23 | 24 | # It is also possible to import configuration files, relative to this 25 | # directory. For example, you can emulate configuration per environment 26 | # by uncommenting the line below and defining dev.exs, test.exs and such. 27 | # Configuration from the imported file will override the ones defined 28 | # here (which is why it is important to import them last). 29 | # 30 | # import_config "#{Mix.env()}.exs" 31 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/channels/user_socket.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.UserSocket do 2 | use Phoenix.Socket 3 | 4 | ## Channels 5 | # channel "room:*", BearNecessitiesWeb.RoomChannel 6 | 7 | # Socket params are passed from the client and can 8 | # be used to verify and authenticate a user. After 9 | # verification, you can put default assigns into 10 | # the socket that will be set for all channels, ie 11 | # 12 | # {:ok, assign(socket, :user_id, verified_user_id)} 13 | # 14 | # To deny connection, return `:error`. 15 | # 16 | # See `Phoenix.Token` documentation for examples in 17 | # performing token verification on connect. 18 | def connect(_params, socket, _connect_info) do 19 | {:ok, socket} 20 | end 21 | 22 | # Socket id's are topics that allow you to identify all sockets for a given user: 23 | # 24 | # def id(socket), do: "user_socket:#{socket.assigns.user_id}" 25 | # 26 | # Would allow you to broadcast a "disconnect" event and terminate 27 | # all active sockets and channels for a given user: 28 | # 29 | # BearNecessitiesWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) 30 | # 31 | # Returning `nil` makes this socket anonymous. 32 | def id(_socket), do: nil 33 | end 34 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | it cannot be async. For this reason, every test runs 12 | inside a transaction which is reset at the beginning 13 | of the test unless the test case is marked as async. 14 | """ 15 | 16 | use ExUnit.CaseTemplate 17 | 18 | using do 19 | quote do 20 | # Import conveniences for testing with connections 21 | use Phoenix.ConnTest 22 | alias BearNecessitiesWeb.Router.Helpers, as: Routes 23 | 24 | # The default endpoint for testing 25 | @endpoint BearNecessitiesWeb.Endpoint 26 | end 27 | end 28 | 29 | setup tags do 30 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(BearNecessities.Repo) 31 | 32 | unless tags[:async] do 33 | Ecto.Adapters.SQL.Sandbox.mode(BearNecessities.Repo, {:shared, self()}) 34 | end 35 | 36 | {:ok, conn: Phoenix.ConnTest.build_conn()} 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const glob = require("glob"); 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 4 | const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); 5 | const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); 6 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 7 | 8 | module.exports = (env, options) => ({ 9 | optimization: { 10 | minimizer: [ 11 | new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }), 12 | new OptimizeCSSAssetsPlugin({}) 13 | ] 14 | }, 15 | entry: { 16 | "./js/app.js": ["./js/app.js"].concat(glob.sync("./vendor/**/*.js")) 17 | }, 18 | output: { 19 | filename: "app.js", 20 | path: path.resolve(__dirname, "../priv/static/js") 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.js$/, 26 | exclude: /node_modules/, 27 | use: { 28 | loader: "babel-loader" 29 | } 30 | }, 31 | { 32 | test: /\.css$/, 33 | use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"] 34 | } 35 | ] 36 | }, 37 | plugins: [ 38 | new MiniCssExtractPlugin({ filename: "../css/app.css" }), 39 | new CopyWebpackPlugin([{ from: "static/", to: "../" }]) 40 | ] 41 | }); 42 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | bear_necessities_web-*.tar 24 | 25 | # If NPM crashes, it generates a log, let's ignore it too. 26 | npm-debug.log 27 | 28 | # The directory NPM downloads your dependencies sources to. 29 | /assets/node_modules/ 30 | 31 | # Since we are building assets from web/static, 32 | # we ignore priv/static. You may want to comment 33 | # this depending on your deployment strategy. 34 | /priv/static/ 35 | 36 | # Files matching config/*.secret.exs pattern contain sensitive 37 | # data and you should not commit them into version control. 38 | # 39 | # Alternatively, you may comment the line below and commit the 40 | # secrets files as long as you replace their contents by environment 41 | # variables. 42 | /config/*.secret.exs 43 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/css/form.css: -------------------------------------------------------------------------------- 1 | .button, 2 | .input { 3 | position: relative; 4 | font-size: 20px; 5 | padding: 15px; 6 | } 7 | .input { 8 | border: 6px solid #363636; 9 | box-shadow: inset -0.25em -0.25em 0px 0px #a9a9a9; 10 | } 11 | .button { 12 | background: #f6f6f6; 13 | box-shadow: inset -0.25em -0.25em 0px 0px #a9a9a9; 14 | color: #363636; 15 | text-align: center; 16 | text-decoration: none; 17 | cursor: pointer; 18 | } 19 | 20 | .button::before, 21 | .button::after { 22 | content: ""; 23 | position: absolute; 24 | width: 100%; 25 | height: 100%; 26 | box-sizing: content-box; 27 | } 28 | 29 | .button:before { 30 | top: -6px; 31 | left: 0; 32 | border-top: 6px #363636 solid; 33 | border-bottom: 6px #363636 solid; 34 | } 35 | 36 | .button::after { 37 | left: -6px; 38 | top: 0; 39 | border-left: 6px #363636 solid; 40 | border-right: 6px #363636 solid; 41 | } 42 | 43 | .button.red { 44 | color: white; 45 | background: #e76e55; 46 | box-shadow: inset -0.25em -0.25em 0px 0px #8c2022; 47 | } 48 | .button.red:hover, 49 | .button.red:focus { 50 | background: #ce372b; 51 | box-shadow: inset -0.35em -0.35em 0px 0px #8c2022; 52 | } 53 | 54 | .button.green { 55 | color: white; 56 | background: #92cd41; 57 | box-shadow: inset -0.25em -0.25em 0px 0px #4aa52e; 58 | } 59 | .button.green:hover, 60 | .button.green:focus { 61 | background: #76c442; 62 | box-shadow: inset -0.35em -0.35em 0px 0px #4aa52e; 63 | } 64 | 65 | .button.small { 66 | font-size: 12px; 67 | padding: 7px; 68 | } 69 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/views/playfield.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.Playfield do 2 | use BearNecessitiesWeb, :view 3 | 4 | def tile_class(tile) do 5 | case tile do 6 | %Tile{type: :grass, texture: texture} -> "grass-#{texture}" 7 | %Tile{type: :nothing} -> "nothing" 8 | end 9 | end 10 | 11 | def item_class(item, player_id) do 12 | case item do 13 | %Bear{id: id, direction: direction, moving: moving, clawing: clawing, dead: nil} = bear 14 | when id == player_id -> 15 | ["bear", "self", direction] 16 | |> bear_action_class(moving, clawing) 17 | |> Enum.join(" ") 18 | 19 | %Bear{id: id, direction: direction, dead: _} when id == player_id -> 20 | "bear dead" 21 | 22 | %Bear{direction: direction, moving: moving, clawing: clawing, dead: nil} -> 23 | ["bear", "opponent", direction] 24 | |> bear_action_class(moving, clawing) 25 | |> Enum.join(" ") 26 | 27 | %Bear{direction: direction, dead: _dead} -> 28 | "bear opponent dead" 29 | 30 | %Bee{} -> 31 | "bee" 32 | 33 | %Tree{hive: %Hive{}} -> 34 | "tree hive" 35 | 36 | %Tree{} -> 37 | "tree" 38 | 39 | %HoneyDrop{} -> 40 | "honey" 41 | 42 | nil -> 43 | nil 44 | end 45 | end 46 | 47 | defp bear_action_class(classes, false, false), do: ["idle" | classes] 48 | defp bear_action_class(classes, _, true), do: ["clawing" | classes] 49 | defp bear_action_class(classes, _, _), do: classes 50 | end 51 | -------------------------------------------------------------------------------- /apps/game/lib/bear.ex: -------------------------------------------------------------------------------- 1 | defmodule Bear do 2 | defstruct id: nil, 3 | pos_x: nil, 4 | pos_y: nil, 5 | dead: nil, 6 | honey: nil, 7 | display_name: nil, 8 | started: false, 9 | direction: :down, 10 | moving: false, 11 | clawing: false 12 | 13 | def create_bear(%{height: height, width: width}, id, display_name, started) do 14 | pos_x = Enum.random(0..height) 15 | pos_y = Enum.random(0..width) 16 | 17 | %Bear{ 18 | id: id, 19 | pos_x: 5, 20 | pos_y: 5, 21 | honey: 10, 22 | display_name: display_name, 23 | started: started 24 | } 25 | end 26 | 27 | @doc """ 28 | Tries to change the position of a bear , up, left, down or right. 29 | The game will decide if the action is permitted and returns the 30 | actual state of the bear. 31 | """ 32 | def move(id, action) do 33 | id 34 | |> Game.get_bear() 35 | |> _move(action) 36 | end 37 | 38 | defp _move(bear, :down), do: Game.move(bear, :down, to: {bear.pos_x + 1, bear.pos_y}) 39 | defp _move(bear, :up), do: Game.move(bear, :up, to: {bear.pos_x - 1, bear.pos_y}) 40 | defp _move(bear, :left), do: Game.move(bear, :left, to: {bear.pos_x, bear.pos_y - 1}) 41 | defp _move(bear, :right), do: Game.move(bear, :right, to: {bear.pos_x, bear.pos_y + 1}) 42 | 43 | def stop(id) do 44 | GenServer.call(Game, {:stop, id}) 45 | end 46 | 47 | def claw(id) do 48 | id 49 | |> Game.get_bear() 50 | |> Game.claw() 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :bear_necessities_web 3 | 4 | socket "/socket", BearNecessitiesWeb.UserSocket, 5 | websocket: [timeout: 45_000], 6 | longpoll: false 7 | 8 | socket "/live", Phoenix.LiveView.Socket 9 | 10 | # Serve at "/" the static files from "priv/static" directory. 11 | # 12 | # You should set gzip to true if you are running phx.digest 13 | # when deploying your static files in production. 14 | plug Plug.Static, 15 | at: "/", 16 | from: :bear_necessities_web, 17 | gzip: false, 18 | only: ~w(css fonts images js favicon.ico robots.txt sound) 19 | 20 | # Code reloading can be explicitly enabled under the 21 | # :code_reloader configuration of your endpoint. 22 | if code_reloading? do 23 | socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket 24 | plug Phoenix.LiveReloader 25 | plug Phoenix.CodeReloader 26 | end 27 | 28 | plug Plug.RequestId 29 | plug Plug.Logger 30 | 31 | plug Plug.Parsers, 32 | parsers: [:urlencoded, :multipart, :json], 33 | pass: ["*/*"], 34 | json_decoder: Phoenix.json_library() 35 | 36 | plug Plug.MethodOverride 37 | plug Plug.Head 38 | 39 | # The session will be stored in the cookie and signed, 40 | # this means its contents can be read but not tampered with. 41 | # Set :encryption_salt if you would also like to encrypt it. 42 | plug Plug.Session, 43 | store: :cookie, 44 | key: "_bear_necessities_web_key", 45 | signing_salt: "jPBIZGYu" 46 | 47 | plug BearNecessitiesWeb.Router 48 | end 49 | -------------------------------------------------------------------------------- /apps/game/test/game_test.exs: -------------------------------------------------------------------------------- 1 | defmodule GameTest do 2 | use ExUnit.Case 3 | 4 | test "greets the world" do 5 | Game.start_link([]) 6 | end 7 | 8 | test "create_bear" do 9 | Game.start_link([]) 10 | Player.start("fatboypunk", "phx-1") 11 | 12 | assert %Bear{ 13 | clawing: false, 14 | dead: nil, 15 | direction: :down, 16 | display_name: "fatboypunk", 17 | honey: 10, 18 | id: "phx-1", 19 | moving: false, 20 | pos_x: 5, 21 | pos_y: 5, 22 | started: true 23 | } = Game.get_bear("phx-1") 24 | end 25 | 26 | describe "move_player" do 27 | setup do 28 | Game.start_link([]) 29 | {player_pid, bear} = Player.start("fatboypunk", "phx-1") 30 | 31 | {:ok, player_pid: player_pid, bear: bear} 32 | end 33 | 34 | test "move to a working place", %{player_pid: player_pid} do 35 | Player.move(player_pid, "phx-1", :up_arrow) 36 | end 37 | end 38 | 39 | describe "#try_to_sting/2" do 40 | test "the bee successfully stings the bear when next to it" do 41 | bee = %Bee{id: "bee-1", pos_x: 2, pos_y: 3} 42 | bear = %Bear{id: "bear-1", pos_x: 3, pos_y: 3, honey: 10} 43 | 44 | assert [%Bear{honey: 9}] = Bee.try_to_sting(bee, [bear]) 45 | end 46 | 47 | test "the bee is unsuccessful when diagonal from a bear" do 48 | bee = %Bee{id: "bee-1", pos_x: 4, pos_y: 4} 49 | bear = %Bear{id: "bear-1", pos_x: 3, pos_y: 3, honey: 10} 50 | 51 | assert [%Bear{honey: 10}] = Bee.try_to_sting(bee, [bear]) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /apps/bear_necessities/test/support/data_case.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessities.DataCase do 2 | @moduledoc """ 3 | This module defines the setup for tests requiring 4 | access to the application's data layer. 5 | 6 | You may define functions here to be used as helpers in 7 | your tests. 8 | 9 | Finally, if the test case interacts with the database, 10 | it cannot be async. For this reason, every test runs 11 | inside a transaction which is reset at the beginning 12 | of the test unless the test case is marked as async. 13 | """ 14 | 15 | use ExUnit.CaseTemplate 16 | 17 | using do 18 | quote do 19 | alias BearNecessities.Repo 20 | 21 | import Ecto 22 | import Ecto.Changeset 23 | import Ecto.Query 24 | import BearNecessities.DataCase 25 | end 26 | end 27 | 28 | setup tags do 29 | :ok = Ecto.Adapters.SQL.Sandbox.checkout(BearNecessities.Repo) 30 | 31 | unless tags[:async] do 32 | Ecto.Adapters.SQL.Sandbox.mode(BearNecessities.Repo, {:shared, self()}) 33 | end 34 | 35 | :ok 36 | end 37 | 38 | @doc """ 39 | A helper that transforms changeset errors into a map of messages. 40 | 41 | assert {:error, changeset} = Accounts.create_user(%{password: "short"}) 42 | assert "password is too short" in errors_on(changeset).password 43 | assert %{password: ["password is too short"]} = errors_on(changeset) 44 | 45 | """ 46 | def errors_on(changeset) do 47 | Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> 48 | Enum.reduce(opts, message, fn {key, value}, acc -> 49 | String.replace(acc, "%{#{key}}", to_string(value)) 50 | end) 51 | end) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web/views/error_helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.ErrorHelpers do 2 | @moduledoc """ 3 | Conveniences for translating and building error messages. 4 | """ 5 | 6 | use Phoenix.HTML 7 | 8 | @doc """ 9 | Generates tag for inlined form input errors. 10 | """ 11 | def error_tag(form, field) do 12 | Enum.map(Keyword.get_values(form.errors, field), fn error -> 13 | content_tag(:span, translate_error(error), class: "help-block") 14 | end) 15 | end 16 | 17 | @doc """ 18 | Translates an error message using gettext. 19 | """ 20 | def translate_error({msg, opts}) do 21 | # When using gettext, we typically pass the strings we want 22 | # to translate as a static argument: 23 | # 24 | # # Translate "is invalid" in the "errors" domain 25 | # dgettext("errors", "is invalid") 26 | # 27 | # # Translate the number of files with plural rules 28 | # dngettext("errors", "1 file", "%{count} files", count) 29 | # 30 | # Because the error messages we show in our forms and APIs 31 | # are defined inside Ecto, we need to translate them dynamically. 32 | # This requires us to call the Gettext module passing our gettext 33 | # backend as first argument. 34 | # 35 | # Note we use the "errors" domain, which means translations 36 | # should be written to the errors.po file. The :count option is 37 | # set by Ecto and indicates we should also apply plural rules. 38 | if count = opts[:count] do 39 | Gettext.dngettext(BearNecessitiesWeb.Gettext, "errors", msg, msg, count, opts) 40 | else 41 | Gettext.dgettext(BearNecessitiesWeb.Gettext, "errors", msg, opts) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /apps/bear_necessities/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule BearNecessities.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :bear_necessities, 7 | version: "0.1.0", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.5", 13 | elixirc_paths: elixirc_paths(Mix.env()), 14 | start_permanent: Mix.env() == :prod, 15 | aliases: aliases(), 16 | deps: deps() 17 | ] 18 | end 19 | 20 | # Configuration for the OTP application. 21 | # 22 | # Type `mix help compile.app` for more information. 23 | def application do 24 | [ 25 | mod: {BearNecessities.Application, []}, 26 | extra_applications: [:logger, :runtime_tools] 27 | ] 28 | end 29 | 30 | # Specifies which paths to compile per environment. 31 | defp elixirc_paths(:test), do: ["lib", "test/support"] 32 | defp elixirc_paths(_), do: ["lib"] 33 | 34 | # Specifies your project dependencies. 35 | # 36 | # Type `mix help deps` for examples and options. 37 | defp deps do 38 | [ 39 | {:ecto_sql, "~> 3.0"}, 40 | {:postgrex, ">= 0.0.0"}, 41 | {:jason, "~> 1.0"} 42 | ] 43 | end 44 | 45 | # Aliases are shortcuts or tasks specific to the current project. 46 | # For example, to create, migrate and run the seeds file at once: 47 | # 48 | # $ mix ecto.setup 49 | # 50 | # See the documentation for `Mix` for more info on aliases. 51 | defp aliases do 52 | [ 53 | "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], 54 | "ecto.reset": ["ecto.drop", "ecto.setup"], 55 | test: ["ecto.create --quiet", "ecto.migrate", "test"] 56 | ] 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :bear_necessities_web, 7 | version: "0.1.0", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.5", 13 | elixirc_paths: elixirc_paths(Mix.env()), 14 | compilers: [:phoenix, :gettext] ++ Mix.compilers(), 15 | start_permanent: Mix.env() == :prod, 16 | aliases: aliases(), 17 | deps: deps() 18 | ] 19 | end 20 | 21 | # Configuration for the OTP application. 22 | # 23 | # Type `mix help compile.app` for more information. 24 | def application do 25 | [ 26 | mod: {BearNecessitiesWeb.Application, []}, 27 | extra_applications: [:logger, :runtime_tools] 28 | ] 29 | end 30 | 31 | # Specifies which paths to compile per environment. 32 | defp elixirc_paths(:test), do: ["lib", "test/support"] 33 | defp elixirc_paths(_), do: ["lib"] 34 | 35 | # Specifies your project dependencies. 36 | # 37 | # Type `mix help deps` for examples and options. 38 | defp deps do 39 | [ 40 | {:bear_necessities, in_umbrella: true}, 41 | {:gettext, "~> 0.11"}, 42 | {:jason, "~> 1.0"}, 43 | {:game, in_umbrella: true}, 44 | {:phoenix, "~> 1.4.3"}, 45 | {:phoenix_pubsub, "~> 1.1"}, 46 | {:phoenix_ecto, "~> 4.0"}, 47 | {:phoenix_html, "~> 2.11"}, 48 | {:phoenix_live_reload, "~> 1.2", only: :dev}, 49 | {:phoenix_live_view, "~> 0.2.0"}, 50 | {:plug_cowboy, "~> 2.0"} 51 | ] 52 | end 53 | 54 | # Aliases are shortcuts or tasks specific to the current project. 55 | # For example, we extend the test task to create and migrate the database. 56 | # 57 | # See the documentation for `Mix` for more info on aliases. 58 | defp aliases do 59 | [test: ["ecto.create --quiet", "ecto.migrate", "test"]] 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/config/dev.exs: -------------------------------------------------------------------------------- 1 | # Since configuration is shared in umbrella projects, this file 2 | # should only configure the :bear_necessities_web application itself 3 | # and only for organization purposes. All other config goes to 4 | # the umbrella root. 5 | use Mix.Config 6 | 7 | # For development, we disable any cache and enable 8 | # debugging and code reloading. 9 | # 10 | # The watchers configuration can be used to run external 11 | # watchers to your application. For example, we use it 12 | # with webpack to recompile .js and .css sources. 13 | config :bear_necessities_web, BearNecessitiesWeb.Endpoint, 14 | http: [port: 4000], 15 | debug_errors: true, 16 | code_reloader: true, 17 | check_origin: false, 18 | watchers: [ 19 | node: [ 20 | "node_modules/webpack/bin/webpack.js", 21 | "--mode", 22 | "development", 23 | "--watch-stdin", 24 | cd: Path.expand("../assets", __DIR__) 25 | ] 26 | ] 27 | 28 | # ## SSL Support 29 | # 30 | # In order to use HTTPS in development, a self-signed 31 | # certificate can be generated by running the following 32 | # Mix task: 33 | # 34 | # mix phx.gen.cert 35 | # 36 | # Note that this task requires Erlang/OTP 20 or later. 37 | # Run `mix help phx.gen.cert` for more information. 38 | # 39 | # The `http:` config above can be replaced with: 40 | # 41 | # https: [ 42 | # port: 4001, 43 | # cipher_suite: :strong, 44 | # keyfile: "priv/cert/selfsigned_key.pem", 45 | # certfile: "priv/cert/selfsigned.pem" 46 | # ], 47 | # 48 | # If desired, both `http:` and `https:` keys can be 49 | # configured to run both http and https servers on 50 | # different ports. 51 | 52 | # Watch static and templates for browser reloading. 53 | config :bear_necessities_web, BearNecessitiesWeb.Endpoint, 54 | live_reload: [ 55 | patterns: [ 56 | ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", 57 | ~r"priv/gettext/.*(po)$", 58 | ~r"lib/bear_necessities_web/{live,views}/.*(ex)$", 59 | ~r"lib/bear_necessities_web/templates/.*(eex)$" 60 | ] 61 | ], 62 | live_view: [ 63 | signing_salt: "Z+5xU1Ed8BLzDuUjoyNwUsjVFef0dI+F" 64 | ] 65 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/lib/bear_necessities_web.ex: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb do 2 | @moduledoc """ 3 | The entrypoint for defining your web interface, such 4 | as controllers, views, channels and so on. 5 | 6 | This can be used in your application as: 7 | 8 | use BearNecessitiesWeb, :controller 9 | use BearNecessitiesWeb, :view 10 | 11 | The definitions below will be executed for every view, 12 | controller, etc, so keep them short and clean, focused 13 | on imports, uses and aliases. 14 | 15 | Do NOT define functions inside the quoted expressions 16 | below. Instead, define any helper function in modules 17 | and import those modules here. 18 | """ 19 | 20 | def controller do 21 | quote do 22 | use Phoenix.Controller, namespace: BearNecessitiesWeb 23 | import Plug.Conn 24 | import BearNecessitiesWeb.Gettext 25 | alias BearNecessitiesWeb.Router.Helpers, as: Routes 26 | end 27 | end 28 | 29 | def view do 30 | quote do 31 | use Phoenix.View, 32 | root: "lib/bear_necessities_web/templates", 33 | namespace: BearNecessitiesWeb 34 | 35 | # Import convenience functions from controllers 36 | import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1] 37 | import Phoenix.LiveView, only: [live_render: 2, live_render: 3] 38 | 39 | # Use all HTML functionality (forms, tags, etc) 40 | use Phoenix.HTML 41 | 42 | import BearNecessitiesWeb.ErrorHelpers 43 | import BearNecessitiesWeb.Gettext 44 | alias BearNecessitiesWeb.Router.Helpers, as: Routes 45 | end 46 | end 47 | 48 | def router do 49 | quote do 50 | use Phoenix.Router 51 | import Plug.Conn 52 | import Phoenix.Controller 53 | import Phoenix.LiveView.Router 54 | end 55 | end 56 | 57 | def channel do 58 | quote do 59 | use Phoenix.Channel 60 | import BearNecessitiesWeb.Gettext 61 | end 62 | end 63 | 64 | @doc """ 65 | When used, dispatch to the appropriate controller/view/etc. 66 | """ 67 | defmacro __using__(which) when is_atom(which) do 68 | apply(__MODULE__, which, []) 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /apps/game/lib/player.ex: -------------------------------------------------------------------------------- 1 | defmodule Player do 2 | use GenServer 3 | require Logger 4 | 5 | @claw_time_ms 1000 6 | 7 | @enforce_keys [:id] 8 | defstruct [:id, :claw, :timer_pid] 9 | 10 | def start_link(default) when is_list(default) do 11 | GenServer.start_link(__MODULE__, default) 12 | end 13 | 14 | @impl true 15 | def init(id: id) do 16 | {:ok, %Player{id: id}} 17 | end 18 | 19 | @impl true 20 | def handle_call({:action, user_input, id}, _pid, state) do 21 | bear = 22 | case user_input do 23 | :up_arrow -> 24 | Bear.move(id, :up) 25 | 26 | :down_arrow -> 27 | Bear.move(id, :down) 28 | 29 | :left_arrow -> 30 | Bear.move(id, :left) 31 | 32 | :right_arrow -> 33 | Bear.move(id, :right) 34 | end 35 | 36 | {:reply, bear, state} 37 | end 38 | 39 | @impl true 40 | def handle_call({:claw, id}, _pid, state) do 41 | bear = Bear.claw(id) 42 | {:ok, timer_pid} = :timer.send_interval(50, self(), :update_claw) 43 | state = %{state | claw: @claw_time_ms, timer_pid: timer_pid} 44 | 45 | {:reply, bear, state} 46 | end 47 | 48 | @impl true 49 | def handle_info(:update_claw, %{claw: nil} = state) do 50 | {:noreply, state} 51 | end 52 | 53 | @impl true 54 | def handle_info(:update_claw, %{claw: claw_time} = state) when claw_time > 0 do 55 | state = %{state | claw: claw_time - 50} 56 | 57 | {:noreply, state} 58 | end 59 | 60 | @impl true 61 | def handle_info(:update_claw, %{id: id, claw: claw_time, timer_pid: timer_pid} = state) 62 | when claw_time < 1 do 63 | :timer.cancel(timer_pid) 64 | state = %{state | claw: nil, timer_pid: nil} 65 | Bear.stop(id) 66 | 67 | {:noreply, state} 68 | end 69 | 70 | @impl true 71 | def handle_info(:update_claw, state) do 72 | {:noreply, state} 73 | end 74 | 75 | def move(pid, player_id, way) do 76 | GenServer.call(pid, {:action, way, player_id}) 77 | end 78 | 79 | def claw(pid, player_id) do 80 | GenServer.call(pid, {:claw, player_id}) 81 | end 82 | 83 | def start(display_name, id) do 84 | {:ok, pid} = Player.start_link(id: id) 85 | bear = Game.create_bear(display_name: display_name, id: id, started: true) 86 | 87 | {pid, bear} 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | parallelism: 1 5 | docker: 6 | - image: defactosoftware/elixir 7 | MIX_ENV: test 8 | - image: circleci/postgres:10.1-alpine 9 | environment: 10 | POSTGRES_USER: postgres 11 | POSTGRES_DB: bear_necessities_test 12 | POSTGRES_PASSWORD: postgres 13 | steps: 14 | - checkout 15 | - restore_cache: 16 | paths: 17 | - /root/.mix/archives 18 | keys: 19 | - v1-hex-archive 20 | - v1-mix-deps-{{ checksum "mix.lock" }} 21 | - run: 22 | name: Install node 23 | command: | 24 | set +e 25 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash 26 | export NVM_DIR="/root/.nvm" 27 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 28 | nvm install 29 | 30 | # Each step uses the same `$BASH_ENV`, so need to modify it 31 | echo 'export NVM_DIR="/root/.nvm"' >> $BASH_ENV 32 | echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV 33 | - run: 34 | name: Create local hex archive 35 | command: mix local.hex --force 36 | - run: 37 | name: Create local rebar 38 | command: mix local.rebar --force 39 | - run: 40 | name: Installing Elixir dependencies 41 | command: mix deps.get 42 | - run: 43 | name: Compile the Phoenix app 44 | command: mix compile 45 | - run: 46 | name: Phoenix digest 47 | command: mix phx.digest 48 | - run: 49 | name: Creating Postgres database 50 | command: mix ecto.create 51 | - run: 52 | name: Running Elixir tests 53 | command: mix test 54 | - save_cache: 55 | key: v1-hex-archive 56 | paths: 57 | - /root/.mix/archives 58 | - save_cache: 59 | key: v1-mix-deps-{{ checksum "mix.lock" }} 60 | paths: 61 | - "deps" 62 | - "_build" 63 | - save_cache: 64 | key: v1-yarn-deps-{{ checksum "yarn.lock" }} 65 | paths: 66 | - "node_modules" 67 | experimental: 68 | notify: 69 | branches: 70 | only: 71 | - master 72 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/assets/js/socket.js: -------------------------------------------------------------------------------- 1 | // NOTE: The contents of this file will only be executed if 2 | // you uncomment its entry in "assets/js/app.js". 3 | 4 | // To use Phoenix channels, the first step is to import Socket, 5 | // and connect at the socket path in "lib/web/endpoint.ex". 6 | // 7 | // Pass the token on params as below. Or remove it 8 | // from the params if you are not using authentication. 9 | import {Socket} from "phoenix" 10 | 11 | let socket = new Socket("/socket", {params: {token: window.userToken}}) 12 | 13 | // When you connect, you'll often need to authenticate the client. 14 | // For example, imagine you have an authentication plug, `MyAuth`, 15 | // which authenticates the session and assigns a `:current_user`. 16 | // If the current user exists you can assign the user's token in 17 | // the connection for use in the layout. 18 | // 19 | // In your "lib/web/router.ex": 20 | // 21 | // pipeline :browser do 22 | // ... 23 | // plug MyAuth 24 | // plug :put_user_token 25 | // end 26 | // 27 | // defp put_user_token(conn, _) do 28 | // if current_user = conn.assigns[:current_user] do 29 | // token = Phoenix.Token.sign(conn, "user socket", current_user.id) 30 | // assign(conn, :user_token, token) 31 | // else 32 | // conn 33 | // end 34 | // end 35 | // 36 | // Now you need to pass this token to JavaScript. You can do so 37 | // inside a script tag in "lib/web/templates/layout/app.html.eex": 38 | // 39 | // 40 | // 41 | // You will need to verify the user token in the "connect/3" function 42 | // in "lib/web/channels/user_socket.ex": 43 | // 44 | // def connect(%{"token" => token}, socket, _connect_info) do 45 | // # max_age: 1209600 is equivalent to two weeks in seconds 46 | // case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do 47 | // {:ok, user_id} -> 48 | // {:ok, assign(socket, :user, user_id)} 49 | // {:error, reason} -> 50 | // :error 51 | // end 52 | // end 53 | // 54 | // Finally, connect to the socket: 55 | socket.connect() 56 | 57 | // Now that you are connected, you can join channels with a topic: 58 | let channel = socket.channel("topic:subtopic", {}) 59 | channel.join() 60 | .receive("ok", resp => { console.log("Joined successfully", resp) }) 61 | .receive("error", resp => { console.log("Unable to join", resp) }) 62 | 63 | export default socket 64 | -------------------------------------------------------------------------------- /apps/bear_necessities_web/test/bear_necessities_web/views/playfield_test.exs: -------------------------------------------------------------------------------- 1 | defmodule BearNecessitiesWeb.PlayfieldTest do 2 | use BearNecessitiesWeb.ConnCase 3 | import Phoenix.LiveViewTest 4 | 5 | test "Start with a player name", %{conn: conn} do 6 | conn = get(conn, "/") 7 | assert html_response(conn, 200) =~ "What is Your Name?" 8 | 9 | {:ok, view, _html} = live(conn) 10 | 11 | template = render_submit(view, "start", %{player: %{display_name: "PhoenixPlayer"}}) 12 | 13 | assert template =~ "Use the Spacebar to claw.
60 |Arrow keys to move.
61 |