diff --git a/app/assets/javascripts/games.js.coffee b/app/assets/javascripts/games.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/games.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/players.js.coffee b/app/assets/javascripts/players.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/players.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/stylesheets/games.css.scss b/app/assets/stylesheets/games.css.scss
new file mode 100644
index 00000000..3e6a7ecc
--- /dev/null
+++ b/app/assets/stylesheets/games.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Games controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb
new file mode 100644
index 00000000..8e355b36
--- /dev/null
+++ b/app/controllers/games_controller.rb
@@ -0,0 +1,66 @@
+class GamesController < ApplicationController
+ before_action :set_game, only: [:show, :edit, :update, :destroy]
+
+ respond_to :html
+
+ def index
+ @games = Game.all
+ respond_with(@games)
+ end
+
+ def show
+ respond_with(@game)
+ end
+
+ def new
+ @game = Game.new
+ respond_with(@game)
+ end
+
+ def edit
+ end
+
+ def create
+ @game = Game.new(title: game_params[:title])
+ if game_params[:player_ids]
+ game_params[:player_ids].each do |user_id|
+ @game.players.new(user_id: user_id)
+ end
+ end
+ @game.save
+ respond_with(@game)
+ end
+
+ def update
+ @game.update(game_params)
+ respond_with(@game)
+ end
+
+ def destroy
+ @game.destroy
+ respond_with(@game)
+ end
+
+ def join
+ @game = Game.find(params[:game_id])
+ @game.add_player_from_user(current_user)
+ flash[:notice] = "Successfully joined game..."
+ redirect_to(@game)
+ end
+
+ def start
+ @game = Game.find(params[:game_id])
+ @status = 'Game Started' if @game.is_startable?
+ redirect_to(@game)
+ end
+
+ private
+
+ def set_game
+ @game = Game.find(params[:id])
+ end
+
+ def game_params
+ params.require(:game).permit(:title, player_ids: [])
+ end
+end
diff --git a/app/controllers/players_controller.rb b/app/controllers/players_controller.rb
new file mode 100644
index 00000000..56195a65
--- /dev/null
+++ b/app/controllers/players_controller.rb
@@ -0,0 +1,47 @@
+class PlayersController < ApplicationController
+ before_action :set_player, only: [:show, :edit, :update, :destroy]
+
+ respond_to :html
+
+ def index
+ @players = Player.all
+ respond_with(@players)
+ end
+
+ def show
+ respond_with(@player)
+ end
+
+ def new
+ @player = Player.new
+ respond_with(@player)
+ end
+
+ def edit
+ end
+
+ def create
+ @player = Player.new(player_params)
+ @player.save
+ respond_with(@player)
+ end
+
+ def update
+ @player.update(player_params)
+ respond_with(@player)
+ end
+
+ def destroy
+ @player.destroy
+ respond_with(@player)
+ end
+
+ private
+ def set_player
+ @player = Player.find(params[:id])
+ end
+
+ def player_params
+ params.require(:player).permit(:game_id, :user_id)
+ end
+end
diff --git a/app/helpers/games_helper.rb b/app/helpers/games_helper.rb
new file mode 100644
index 00000000..2ef8c1f4
--- /dev/null
+++ b/app/helpers/games_helper.rb
@@ -0,0 +1,2 @@
+module GamesHelper
+end
diff --git a/app/helpers/players_helper.rb b/app/helpers/players_helper.rb
new file mode 100644
index 00000000..e8f775c0
--- /dev/null
+++ b/app/helpers/players_helper.rb
@@ -0,0 +1,2 @@
+module PlayersHelper
+end
diff --git a/app/models/game.rb b/app/models/game.rb
new file mode 100644
index 00000000..2e286cdf
--- /dev/null
+++ b/app/models/game.rb
@@ -0,0 +1,42 @@
+# The game class
+class Game < ActiveRecord::Base
+ has_many :players, :dependent => :destroy
+ has_many :users, through: :players
+ accepts_nested_attributes_for :players
+ validates :title, presence: true
+
+ def start
+ # Save the game to the database
+ save
+ # Start the game TODO
+ end
+
+ def validate_startable
+ @player_count = players.size
+ errors[:notice] = 'Must be at least 2 players.' if @player_count < 2
+ errors[:players] = 'Must be less than 5 players.' if @player_count > 4
+ end
+
+ def is_startable?
+ @player_count = players.size
+ @player_count.between?(2, 4)
+ end
+
+ def add_player_from_user(user)
+ if can_accomodate(user)
+ Player.create(user: user, game: self)
+ end
+ end
+
+ def can_accomodate(user)
+ !(already_has?(user) || full?)
+ end
+
+ def already_has?(user)
+ users.include?(user)
+ end
+
+ def full?
+ players.size >= 4
+ end
+end
diff --git a/app/models/player.rb b/app/models/player.rb
new file mode 100644
index 00000000..41a1f43d
--- /dev/null
+++ b/app/models/player.rb
@@ -0,0 +1,10 @@
+# Associates users to games
+class Player < ActiveRecord::Base
+ belongs_to :game
+ belongs_to :user
+
+ has_many :player_cards
+
+ validates_presence_of :user_id
+ validates_presence_of :game_id
+end
diff --git a/app/models/player_card.rb b/app/models/player_card.rb
new file mode 100644
index 00000000..9aa2e152
--- /dev/null
+++ b/app/models/player_card.rb
@@ -0,0 +1,4 @@
+class PlayerCard < ActiveRecord::Base
+ belongs_to :player
+ belongs_to :card
+end
diff --git a/app/views/games/_form.html.haml b/app/views/games/_form.html.haml
new file mode 100644
index 00000000..fa6aa96e
--- /dev/null
+++ b/app/views/games/_form.html.haml
@@ -0,0 +1,9 @@
+= simple_form_for(@game) do |f|
+ = f.error_notification
+
+ .form-inputs
+ = f.input :title
+ = f.association :players, as: :select, collection: User.all.map {|u| u.id}, include_blank: false, include_hidden: false
+
+ .form-actions
+ = f.button :submit
diff --git a/app/views/games/edit.html.haml b/app/views/games/edit.html.haml
new file mode 100644
index 00000000..3000f15c
--- /dev/null
+++ b/app/views/games/edit.html.haml
@@ -0,0 +1,7 @@
+%h1 Editing game
+
+= render 'form'
+
+= link_to 'Show', @game
+\|
+= link_to 'Back', games_path
diff --git a/app/views/games/index.html.haml b/app/views/games/index.html.haml
new file mode 100644
index 00000000..6a76c3b7
--- /dev/null
+++ b/app/views/games/index.html.haml
@@ -0,0 +1,21 @@
+%h1 Listing games
+
+%table
+ %thead
+ %tr
+ %th Title
+ %th
+ %th
+ %th
+
+ %tbody
+ - @games.each do |game|
+ %tr
+ %td= game.title
+ %td= link_to 'Show', game
+ %td= link_to 'Edit', edit_game_path(game)
+ %td= link_to 'Destroy', game, :method => :delete, :data => { :confirm => 'Are you sure?' }
+
+%br
+
+= link_to 'New Game', new_game_path
diff --git a/app/views/games/index.json.jbuilder b/app/views/games/index.json.jbuilder
new file mode 100644
index 00000000..e9ef30ab
--- /dev/null
+++ b/app/views/games/index.json.jbuilder
@@ -0,0 +1,4 @@
+json.array!(@games) do |game|
+ json.extract! game, :id, :title
+ json.url game_url(game, format: :json)
+end
diff --git a/app/views/games/new.html.haml b/app/views/games/new.html.haml
new file mode 100644
index 00000000..c47db8ac
--- /dev/null
+++ b/app/views/games/new.html.haml
@@ -0,0 +1,5 @@
+%h1 New game
+
+= render 'form'
+
+= link_to 'Back', games_path
diff --git a/app/views/games/show.html.haml b/app/views/games/show.html.haml
new file mode 100644
index 00000000..887c95a3
--- /dev/null
+++ b/app/views/games/show.html.haml
@@ -0,0 +1,23 @@
+%p
+ %b Status:
+ = @status
+
+%p
+ %b Title:
+ = @game.title
+
+- if @game.can_accomodate(current_user)
+ = link_to 'Join', game_join_path(@game)
+
+- if @game.is_startable? && @game.already_has?(current_user)
+ = link_to 'Start', game_start_path(@game)
+
+%p
+ %b Players:
+ %ol
+ - @game.players.each do |player|
+ %li= player
+
+= link_to 'Edit', edit_game_path(@game)
+\|
+= link_to 'Back', games_path
diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder
new file mode 100644
index 00000000..8eceebb7
--- /dev/null
+++ b/app/views/games/show.json.jbuilder
@@ -0,0 +1 @@
+json.extract! @game, :id, :title, :created_at, :updated_at
diff --git a/app/views/layouts/_navigation_links.html.erb b/app/views/layouts/_navigation_links.html.erb
index 24c35e5b..02f3bb9f 100644
--- a/app/views/layouts/_navigation_links.html.erb
+++ b/app/views/layouts/_navigation_links.html.erb
@@ -1,4 +1,5 @@
-<%# add navigation links to this file %>
+
<%= link_to 'Home', root_path %>
+<%= link_to 'Quick Play', quick_play_path %>
<% if user_signed_in? %>
<%= link_to 'Edit account', edit_user_registration_path %>
<%= link_to 'Sign out', destroy_user_session_path, :method=>'delete' %>
diff --git a/app/views/players/_form.html.haml b/app/views/players/_form.html.haml
new file mode 100644
index 00000000..132b1b80
--- /dev/null
+++ b/app/views/players/_form.html.haml
@@ -0,0 +1,9 @@
+= simple_form_for(@player) do |f|
+ = f.error_notification
+
+ .form-inputs
+ = f.association :game
+ = f.association :user
+
+ .form-actions
+ = f.button :submit
diff --git a/app/views/players/edit.html.haml b/app/views/players/edit.html.haml
new file mode 100644
index 00000000..02e155c0
--- /dev/null
+++ b/app/views/players/edit.html.haml
@@ -0,0 +1,7 @@
+%h1 Editing player
+
+= render 'form'
+
+= link_to 'Show', @player
+\|
+= link_to 'Back', players_path
diff --git a/app/views/players/index.html.haml b/app/views/players/index.html.haml
new file mode 100644
index 00000000..d452b1ea
--- /dev/null
+++ b/app/views/players/index.html.haml
@@ -0,0 +1,23 @@
+%h1 Listing players
+
+%table
+ %thead
+ %tr
+ %th Game
+ %th User
+ %th
+ %th
+ %th
+
+ %tbody
+ - @players.each do |player|
+ %tr
+ %td= player.game
+ %td= player.user
+ %td= link_to 'Show', player
+ %td= link_to 'Edit', edit_player_path(player)
+ %td= link_to 'Destroy', player, :method => :delete, :data => { :confirm => 'Are you sure?' }
+
+%br
+
+= link_to 'New Player', new_player_path
diff --git a/app/views/players/index.json.jbuilder b/app/views/players/index.json.jbuilder
new file mode 100644
index 00000000..25c840c6
--- /dev/null
+++ b/app/views/players/index.json.jbuilder
@@ -0,0 +1,4 @@
+json.array!(@players) do |player|
+ json.extract! player, :id, :game_id, :user_id
+ json.url player_url(player, format: :json)
+end
diff --git a/app/views/players/new.html.haml b/app/views/players/new.html.haml
new file mode 100644
index 00000000..17c238b2
--- /dev/null
+++ b/app/views/players/new.html.haml
@@ -0,0 +1,5 @@
+%h1 New player
+
+= render 'form'
+
+= link_to 'Back', players_path
diff --git a/app/views/players/show.html.haml b/app/views/players/show.html.haml
new file mode 100644
index 00000000..80707d96
--- /dev/null
+++ b/app/views/players/show.html.haml
@@ -0,0 +1,12 @@
+%p#notice= notice
+
+%p
+ %b Game:
+ = @player.game
+%p
+ %b User:
+ = @player.user
+
+= link_to 'Edit', edit_player_path(@player)
+\|
+= link_to 'Back', players_path
diff --git a/app/views/players/show.json.jbuilder b/app/views/players/show.json.jbuilder
new file mode 100644
index 00000000..6c93eff7
--- /dev/null
+++ b/app/views/players/show.json.jbuilder
@@ -0,0 +1 @@
+json.extract! @player, :id, :game_id, :user_id, :created_at, :updated_at
diff --git a/app/views/visitors/quick-play.html.haml b/app/views/visitors/quick-play.html.haml
new file mode 100644
index 00000000..4cd27870
--- /dev/null
+++ b/app/views/visitors/quick-play.html.haml
@@ -0,0 +1 @@
+%h1 Joining a game
diff --git a/config/routes.rb b/config/routes.rb
index 3b42a77a..c7f6d6a9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,6 +1,14 @@
Rails.application.routes.draw do
+ resources :players
+
+ resources :games do
+ get 'start'
+ get 'join'
+ end
+
mount Upmin::Engine => '/admin'
root to: 'visitors#index'
+ get '/quick-play', to: 'visitors#quick-play'
devise_for :users
resources :users
end
diff --git a/db/migrate/20150104065001_create_games.rb b/db/migrate/20150104065001_create_games.rb
new file mode 100644
index 00000000..ec7beb9e
--- /dev/null
+++ b/db/migrate/20150104065001_create_games.rb
@@ -0,0 +1,9 @@
+class CreateGames < ActiveRecord::Migration
+ def change
+ create_table :games do |t|
+ t.string :title
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20150104203256_create_players.rb b/db/migrate/20150104203256_create_players.rb
new file mode 100644
index 00000000..9d017d5b
--- /dev/null
+++ b/db/migrate/20150104203256_create_players.rb
@@ -0,0 +1,10 @@
+class CreatePlayers < ActiveRecord::Migration
+ def change
+ create_table :players do |t|
+ t.references :game, index: true
+ t.references :user, index: true
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20150104203850_create_player_cards.rb b/db/migrate/20150104203850_create_player_cards.rb
new file mode 100644
index 00000000..3478e459
--- /dev/null
+++ b/db/migrate/20150104203850_create_player_cards.rb
@@ -0,0 +1,10 @@
+class CreatePlayerCards < ActiveRecord::Migration
+ def change
+ create_table :player_cards do |t|
+ t.references :player, index: true
+ t.references :card, index: true
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f0dbaa80..366b7519 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,11 +11,37 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150102000743) do
+ActiveRecord::Schema.define(version: 20150104203850) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ create_table "games", force: true do |t|
+ t.string "title"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "player_cards", force: true do |t|
+ t.integer "player_id"
+ t.integer "card_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "player_cards", ["card_id"], name: "index_player_cards_on_card_id", using: :btree
+ add_index "player_cards", ["player_id"], name: "index_player_cards_on_player_id", using: :btree
+
+ create_table "players", force: true do |t|
+ t.integer "game_id"
+ t.integer "user_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "players", ["game_id"], name: "index_players_on_game_id", using: :btree
+ add_index "players", ["user_id"], name: "index_players_on_user_id", using: :btree
+
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: ""
diff --git a/spec/factories/games.rb b/spec/factories/games.rb
new file mode 100644
index 00000000..e13770a2
--- /dev/null
+++ b/spec/factories/games.rb
@@ -0,0 +1,6 @@
+FactoryGirl.define do
+ factory :game do
+ title "MyString"
+ end
+
+end
diff --git a/spec/factories/player_cards.rb b/spec/factories/player_cards.rb
new file mode 100644
index 00000000..0260e24f
--- /dev/null
+++ b/spec/factories/player_cards.rb
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :player_card do
+ player nil
+card nil
+ end
+
+end
diff --git a/spec/factories/players.rb b/spec/factories/players.rb
new file mode 100644
index 00000000..714788b4
--- /dev/null
+++ b/spec/factories/players.rb
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :player do
+ game nil
+user nil
+ end
+
+end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 250e115b..8c1b90d6 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :user do
confirmed_at Time.now
name "Test User"
- email "test@example.com"
+ sequence(:email) { |n| "test#{n}@example.com" }
password "please123"
trait :admin do
diff --git a/spec/features/users/user_quick_play_spec.rb b/spec/features/users/user_quick_play_spec.rb
new file mode 100644
index 00000000..cc90f952
--- /dev/null
+++ b/spec/features/users/user_quick_play_spec.rb
@@ -0,0 +1,23 @@
+include Warden::Test::Helpers
+Warden.test_mode!
+
+# Feature: Quick play
+# As a user
+# I want to play a quick game
+# So I can have fun as fast as possible
+feature 'Quick play', :devise do
+
+ # Scenario: User can join a game using the quick play link
+ # Given I am signed in
+ # When I click the Quick Play link
+ # Then I join a game
+ scenario 'user can join a quick play game' do
+ pending("#EXPECT USER TO JOIN FIRST OPEN QUICK PLAY GAME")
+ user = FactoryGirl.create(:user)
+ signin(user.email, user.password)
+ click_link 'Quick Play'
+ #EXPECT VISITOR TO JOIN FIRST OPEN QUICK PLAY TABLE
+ expect(fail)
+ end
+
+end
diff --git a/spec/features/visitors/quick_play_spec.rb b/spec/features/visitors/quick_play_spec.rb
new file mode 100644
index 00000000..1389235b
--- /dev/null
+++ b/spec/features/visitors/quick_play_spec.rb
@@ -0,0 +1,19 @@
+# Feature: Quick play
+# As a visitor
+# I want to play a game
+# So I can have fun without signing up
+feature 'Quick play', :devise do
+
+ # Scenario: Visitor can join a game using the quick play link
+ # Given I am not signed in
+ # When I click the Quick Play link
+ # Then I join a game
+ scenario 'visitor can join a quick play game' do
+ pending("#EXPECT VISITOR TO JOIN FIRST OPEN QUICK PLAY GAME")
+ visit root_path
+ click_link 'Quick Play'
+ #EXPECT VISITOR TO JOIN FIRST OPEN QUICK PLAY TABLE
+ expect(fail)
+ end
+
+end
diff --git a/spec/models/game_spec.rb b/spec/models/game_spec.rb
new file mode 100644
index 00000000..a98654aa
--- /dev/null
+++ b/spec/models/game_spec.rb
@@ -0,0 +1,47 @@
+require 'rails_helper'
+
+RSpec.describe Game, type: :model do
+ before(:each) { @game = Game.new(title: 'Test Game') }
+
+ subject { @game }
+
+ it { should respond_to(:title) }
+
+ it '#title returns a string' do
+ expect(@game.title).to match 'Test Game'
+ end
+
+ describe 'validations' do
+ describe 'player_count' do
+ context 'when there are between 2 and 4 players' do
+ it 'is valid' do
+ @game.players.new
+ @game.players.new
+ expect(@game).to be_valid
+ end
+ end
+
+ context 'when there are less than 2 players' do
+ it 'fails validation with too few players' do
+ expect(@game).to_not be_valid
+ expect(@game.errors[:players])
+ .to include 'Must be at least 2 players.'
+ end
+ end
+ context 'when there are more than 4 players' do
+ it 'fails validation with too many players' do
+ 5.times do
+ @game.players.new
+ end
+ expect(@game).to_not be_valid
+ expect(@game.errors[:players])
+ .to include 'Must be less than 5 players.'
+ end
+ end
+ end
+ end
+
+ it 'Can not be started if game is invalid' do
+ expect(@game.start).to eq false
+ end
+end
diff --git a/spec/models/player_card_spec.rb b/spec/models/player_card_spec.rb
new file mode 100644
index 00000000..40e6573e
--- /dev/null
+++ b/spec/models/player_card_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe PlayerCard, :type => :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/player_spec.rb b/spec/models/player_spec.rb
new file mode 100644
index 00000000..b5778bca
--- /dev/null
+++ b/spec/models/player_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe Player, :type => :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end