love_letter_application 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +91 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +39 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/love_letter_application.rb +7 -0
  13. data/lib/love_letter_application/action_creator.rb +16 -0
  14. data/lib/love_letter_application/actions/clown.rb +45 -0
  15. data/lib/love_letter_application/actions/general.rb +29 -0
  16. data/lib/love_letter_application/actions/knight.rb +31 -0
  17. data/lib/love_letter_application/actions/marquess.rb +28 -0
  18. data/lib/love_letter_application/actions/play_card.rb +33 -0
  19. data/lib/love_letter_application/actions/priestess.rb +36 -0
  20. data/lib/love_letter_application/actions/princess.rb +32 -0
  21. data/lib/love_letter_application/actions/soldier.rb +47 -0
  22. data/lib/love_letter_application/actions/wizard.rb +31 -0
  23. data/lib/love_letter_application/execute_action.rb +21 -0
  24. data/lib/love_letter_application/love_letter_imports.rb +641 -0
  25. data/lib/love_letter_application/models/card.rb +23 -0
  26. data/lib/love_letter_application/models/effects/discard_and_draw.rb +51 -0
  27. data/lib/love_letter_application/models/effects/eliminate_player.rb +43 -0
  28. data/lib/love_letter_application/models/effects/make_player_not_targetable.rb +44 -0
  29. data/lib/love_letter_application/models/effects/next_player_draw_card.rb +45 -0
  30. data/lib/love_letter_application/models/effects/play_card.rb +48 -0
  31. data/lib/love_letter_application/models/effects/round_complete.rb +29 -0
  32. data/lib/love_letter_application/models/effects/switch_hands.rb +50 -0
  33. data/lib/love_letter_application/models/game_board.rb +28 -0
  34. data/lib/love_letter_application/models/player.rb +36 -0
  35. data/lib/love_letter_application/results/eliminate_player.rb +43 -0
  36. data/lib/love_letter_application/results/nodes/card_played_node.rb +15 -0
  37. data/lib/love_letter_application/results/nodes/card_viewed_node.rb +21 -0
  38. data/lib/love_letter_application/results/nodes/discard_card_node.rb +20 -0
  39. data/lib/love_letter_application/results/nodes/drawn_card_node.rb +20 -0
  40. data/lib/love_letter_application/results/nodes/eliminated_player_node.rb +19 -0
  41. data/lib/love_letter_application/results/nodes/hands_switched_node.rb +22 -0
  42. data/lib/love_letter_application/results/nodes/knight_drawn_node.rb +15 -0
  43. data/lib/love_letter_application/results/nodes/knight_victory_node.rb +20 -0
  44. data/lib/love_letter_application/results/nodes/log_node.rb +20 -0
  45. data/lib/love_letter_application/results/nodes/next_player_node.rb +19 -0
  46. data/lib/love_letter_application/results/nodes/play_card_with_no_args_option_node.rb +19 -0
  47. data/lib/love_letter_application/results/nodes/play_card_with_player_id_and_card_id_option_node.rb +21 -0
  48. data/lib/love_letter_application/results/nodes/play_card_with_player_id_option_node.rb +20 -0
  49. data/lib/love_letter_application/results/nodes/player_not_targetable_node.rb +14 -0
  50. data/lib/love_letter_application/results/nodes/player_victory_node.rb +20 -0
  51. data/lib/love_letter_application/results/nodes/players_and_scores_node.rb +44 -0
  52. data/lib/love_letter_application/results/nodes/princess_discarded_node.rb +19 -0
  53. data/lib/love_letter_application/results/nodes/result_game_board_node.rb +19 -0
  54. data/lib/love_letter_application/results/process_correct_guess.rb +22 -0
  55. data/lib/love_letter_application/results/process_draw_after_discard.rb +26 -0
  56. data/lib/love_letter_application/results/process_incorrect_guess.rb +20 -0
  57. data/lib/love_letter_application/results/process_knight_showdown.rb +50 -0
  58. data/lib/love_letter_application/results/process_next_player_turn.rb +57 -0
  59. data/lib/love_letter_application/results/process_next_turn_options.rb +53 -0
  60. data/lib/love_letter_application/results/process_princess_discarded.rb +23 -0
  61. data/lib/love_letter_application/results/process_resolve_wizard.rb +36 -0
  62. data/lib/love_letter_application/results/process_round_complete_by_depleted_deck.rb +50 -0
  63. data/lib/love_letter_application/results/process_round_complete_by_elimination.rb +26 -0
  64. data/lib/love_letter_application/results/process_switch_hands.rb +51 -0
  65. data/lib/love_letter_application/results/yield_to_block.rb +12 -0
  66. data/lib/love_letter_application/types/card.rb +20 -0
  67. data/lib/love_letter_application/types/game_board.rb +59 -0
  68. data/lib/love_letter_application/types/player.rb +25 -0
  69. data/lib/love_letter_application/validator/base.rb +19 -0
  70. data/lib/love_letter_application/validator/builder.rb +50 -0
  71. data/lib/love_letter_application/validator/get_legal_card_ids.rb +23 -0
  72. data/lib/love_letter_application/validator/get_legal_card_ids/marquess.rb +18 -0
  73. data/lib/love_letter_application/validator/play_card.rb +21 -0
  74. data/lib/love_letter_application/validator/play_card/builder.rb +23 -0
  75. data/lib/love_letter_application/validator/play_card/no_options.rb +19 -0
  76. data/lib/love_letter_application/validator/play_card/select_target_player.rb +30 -0
  77. data/lib/love_letter_application/validator/play_card/select_target_player/builder.rb +44 -0
  78. data/lib/love_letter_application/validator/play_card/soldier.rb +39 -0
  79. data/lib/love_letter_application/validator/play_card/soldier/builder.rb +49 -0
  80. data/lib/love_letter_application/validator/validate_card_id.rb +23 -0
  81. data/lib/love_letter_application/version.rb +3 -0
  82. data/love_letter_application.gemspec +43 -0
  83. metadata +278 -0
@@ -0,0 +1,25 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-initializer'
4
+ require 'love_letter_application/types/card'
5
+
6
+ module LoveLetterApplication
7
+ module Types
8
+ i = Class::new do
9
+ @@has_player_methods = ::Types.Interface(:id, :seat, :played_cards, :hand, :active?)
10
+
11
+ def call(player)
12
+ @@has_player_methods.(player)
13
+ ::Types::Coercible::Integer.call(player.id)
14
+ ::Types::Coercible::Integer.call(player.seat)
15
+ ::Types::Array::of(LoveLetterApplication::Types::Card).call(player.played_cards)
16
+ ::Types::Array::of(LoveLetterApplication::Types::Card).call(player.hand)
17
+ ::Types::Strict::Bool.call(player.active?)
18
+ player
19
+ end
20
+ end.new
21
+
22
+ LoveLetterApplication::Types::Player = ::Types::Constructor(Class){|value| i.call(value)}
23
+ end
24
+ end
25
+
@@ -0,0 +1,19 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-initializer'
4
+
5
+ module LoveLetterApplication
6
+ class Validator
7
+ class Base
8
+ extend Dry::Initializer
9
+ option :validate_input, type: Types.Interface(:call)
10
+ option :wrap_result, type: Types.Interface(:call)
11
+
12
+ def call(action_hash)
13
+ result = validate_input.(action_hash)
14
+ return result if result.failure?
15
+ wrap_result.(result)
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-initializer'
4
+ require 'love_letter_application/validator/play_card'
5
+
6
+ module LoveLetterApplication
7
+ module Validator
8
+ class Builder
9
+ include Dry::Initializer.define -> do
10
+ option :all_card_validator_builders, type: ::Types::ArrayOfCallable
11
+ option :get_legal_card_ids, type: ::Types::Callable
12
+ end
13
+
14
+ def call(game_board:, last_action_id:)
15
+ current_player = game_board.players.find do |player|
16
+ player.id.to_i.eql?(game_board.current_player_id.to_i)
17
+ end
18
+
19
+ validate_player_action_and_user = GameValidator::Validator::Base::new(
20
+ legal_options: ['play_card'],
21
+ current_player_id: game_board.current_player_id,
22
+ last_action_id: last_action_id)
23
+
24
+ legal_card_ids = get_legal_card_ids.(card_list: current_player.hand)
25
+
26
+ validate_card_id = ValidateCardId::new(legal_card_ids: legal_card_ids)
27
+
28
+ card_validators = all_card_validator_builders
29
+ .map
30
+ .with_index{|v, k| [k, v]}
31
+ .to_h
32
+ .select{|k, v| legal_card_ids.include?(k)}
33
+ .map{|k, v| [k, v.call(game_board)]}
34
+ .to_h
35
+
36
+ play_card = PlayCard::new(
37
+ validate_card_id: validate_card_id,
38
+ full_validator_for: card_validators)
39
+
40
+ full_validator_for =
41
+ {['play_card', true] => play_card, ['play_card', false] => play_card}
42
+
43
+ validate_input = GameValidator::Validator::new(
44
+ validate_player_action_and_user: validate_player_action_and_user,
45
+ full_validator_for: full_validator_for)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-initializer'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class GetLegalCardIds
8
+ include Dry::Initializer.define -> do
9
+ option :validate_card_combo_for, type: ::Types::ArrayOfCallable
10
+ end
11
+
12
+ def call(card_list:)
13
+ legal_card_ids = ::Types::ArrayOfStrictInteger.call(card_list.map{|c| c.id.to_i})
14
+ card_list.uniq.each do |card|
15
+ legal_card_ids = legal_card_ids
16
+ .&(validate_card_combo_for[card.id.to_i].call(card_list: card_list))
17
+ end
18
+ legal_card_ids.sort
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoveLetterApplication
4
+ module Validator
5
+ class GetLegalCardIds
6
+ class Marquess
7
+ def call(card_list:)
8
+ if card_list.map{|card| card.rank.to_i}.sum >= 12
9
+ card_list.map{|card| card.id.to_i}.select{|card_id| card_id.eql?(7)}
10
+ else
11
+ card_list.map{|card| card.id.to_i}
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,21 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-initializer'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class PlayCard
8
+ extend Dry::Initializer
9
+ option :validate_card_id, type: ::Types::Callable
10
+ option :full_validator_for, type: ::Types::Hash
11
+
12
+ def call(action_hash)
13
+ result = validate_card_id.(action_hash)
14
+ return result if result.failure?
15
+ validate = full_validator_for[result[:card_id]]
16
+ validate.(action_hash)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,23 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-initializer'
4
+ require 'game_validator/validator/validate_to_action'
5
+
6
+ module LoveLetterApplication
7
+ module Validator
8
+ class PlayCard
9
+ class Builder
10
+ extend Dry::Initializer
11
+ option :build_raw_validator, type: ::Types::Callable
12
+ option :wrap_result, type: ::Types::Callable
13
+
14
+ def call(model)
15
+ GameValidator::Validator::ValidateToAction::new(
16
+ validate: build_raw_validator.(model),
17
+ wrap: wrap_result)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,19 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class PlayCard
8
+ class NoOptions < Dry::Validation::Contract
9
+ params{}
10
+
11
+ def accept(visitor, **args)
12
+ visitor = ::Types.Interface(:handle_no_options_validator).call(visitor)
13
+ visitor.handle_no_options_validator(self, args)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,30 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class PlayCard
8
+ class SelectTargetPlayer < Dry::Validation::Contract
9
+ option :legal_target_player_ids, type: ::Types::Array.of(::Types::Coercible::Integer)
10
+
11
+ params do
12
+ required(:target_player_id).filled(:integer)
13
+ end
14
+
15
+ rule(:target_player_id) do
16
+ if !legal_target_player_ids.include?(values[:target_player_id])
17
+ key.failure({text: "target_player_id '#{values[:target_player_id]}' is not permitted",
18
+ status: 422})
19
+ end
20
+ end
21
+
22
+ def accept(visitor, **args)
23
+ visitor = ::Types.Interface(:handle_select_player_id_validator).call(visitor)
24
+ visitor.handle_select_player_id_validator(self, args)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,44 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-initializer'
4
+ require 'dry-validation'
5
+ require 'love_letter_application/validator/play_card/select_target_player'
6
+
7
+ module LoveLetterApplication
8
+ module Validator
9
+ class PlayCard
10
+ class SelectTargetPlayer < Dry::Validation::Contract
11
+ class Builder
12
+ extend Dry::Initializer
13
+ option :target_self?, as: :target_self, type: ::Types::Strict::Bool
14
+ option :no_options_validator, type: ::Types::Callable
15
+
16
+ def call(model)
17
+ legal_target_player_ids = get_legal_target_player_ids(model)
18
+ if legal_target_player_ids.empty?
19
+ no_options_validator
20
+ else
21
+ LoveLetterApplication::Validator::PlayCard::SelectTargetPlayer::new(
22
+ legal_target_player_ids: legal_target_player_ids)
23
+ end
24
+ end
25
+
26
+ private
27
+ def get_legal_target_player_ids(model)
28
+ legal_target_players = model.players
29
+ .select(&:active?) # must not be an eliminated player
30
+ .select(&:targetable?) # can't have immunity to targeting (e.g. with priestess)
31
+ if !target_self?
32
+ legal_target_players = legal_target_players
33
+ .reject{|p| p.id.to_i.eql?(model.current_player_id.to_i)} # can't target self
34
+ end
35
+ legal_target_players.map{|p| p.id.to_i}
36
+ end
37
+
38
+ def target_self?;@target_self;end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,39 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class PlayCard
8
+ class Soldier < Dry::Validation::Contract
9
+ option :legal_target_player_ids, type: ::Types::Array.of(::Types::Coercible::Integer)
10
+ option :legal_target_card_ids, type: ::Types::Array.of(::Types::Coercible::Integer)
11
+
12
+ params do
13
+ required(:target_player_id).filled(:integer)
14
+ required(:target_card_id).filled(:integer)
15
+ end
16
+
17
+ rule(:target_player_id) do
18
+ if !legal_card_ids.include?(values[:target_player_id])
19
+ key.failure({text: "target_player_id '#{values[:target_player_id]}' is not permitted",
20
+ status: 422})
21
+ end
22
+ end
23
+
24
+ rule(:target_card_id) do
25
+ if !legal_card_ids.include?(values[:target_card_id])
26
+ key.failure({text: "target_card_id '#{values[:target_card_id]}' is not permitted",
27
+ status: 422})
28
+ end
29
+ end
30
+
31
+ def accept(visitor, **args)
32
+ visitor = ::Types.Interface(:handle_soldier_validator).call(visitor)
33
+ visitor.handle_soldier_validator(self, args)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,49 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-validation'
4
+ require 'dry-initializer'
5
+ require 'love_letter_application/validator/play_card/soldier'
6
+
7
+ module LoveLetterApplication
8
+ module Validator
9
+ class PlayCard
10
+ class Soldier < Dry::Validation::Contract
11
+ class Builder
12
+ include Dry::Initializer.define -> do
13
+ option :no_options_validator, type: ::Types::Callable
14
+ end
15
+
16
+ def call(model)
17
+ card_id = LoveLetterApplication::Actions::Soldier::id,
18
+ legal_target_player_ids = get_legal_target_player_ids(model)
19
+ if legal_target_player_ids.empty?
20
+ no_options_validator
21
+ else
22
+ LoveLetterApplication::Validator::PlayCard::Soldier::new(
23
+ legal_target_player_ids: legal_target_player_ids,
24
+ legal_target_card_ids: get_legal_target_card_ids(model))
25
+ end
26
+ end
27
+
28
+ private
29
+ def get_legal_target_player_ids(model)
30
+ model.players
31
+ .select(&:active?) # must not be an eliminated player
32
+ .select(&:targetable?) # can't have immunity to targeting (e.g. with priestess)
33
+ .reject{|p| p.id.to_i.eql?(model.current_player_id.to_i)} # can't target self
34
+ .map{|p| p.id.to_i}
35
+ end
36
+
37
+ def get_legal_target_card_ids(model)
38
+ legal_target_cards = [model.set_aside_card] + model.draw_pile
39
+ model.players.each{|p| legal_target_cards += p.played_cards + p.hand}
40
+ legal_target_cards.select(&:targetable?)
41
+ .map{|c| c.id.to_i}
42
+ .uniq
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,23 @@
1
+ #frozen string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module LoveLetterApplication
6
+ module Validator
7
+ class ValidateCardId < Dry::Validation::Contract
8
+ option :legal_card_ids, type: ::Types::Array.of(::Types::Coercible::Integer)
9
+
10
+ params do
11
+ required(:player_action).filled(:string, eql?: 'play_card')
12
+ required(:card_id).filled(:integer)
13
+ end
14
+
15
+ rule(:card_id) do
16
+ if !legal_card_ids.include?(values[:card_id])
17
+ key.failure({text: "card_id '#{values[:card_id]}' is not permitted", status: 400})
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,3 @@
1
+ module LoveLetterApplication
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,43 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "love_letter_application/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'love_letter_application'
7
+ spec.version = LoveLetterApplication::VERSION
8
+ spec.authors = ['Colin Horner']
9
+ spec.email = ['25807014+cmcolinh@users.noreply.github.com']
10
+
11
+ spec.summary = 'Love Letter application'
12
+ spec.description = 'Runs the application'
13
+ #spec.homepage = "TODO: Put your gem's website or public repo URL here."
14
+ spec.license = 'MIT'
15
+
16
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
17
+
18
+ #spec.metadata["homepage_uri"] = spec.homepage
19
+ #spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
20
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_development_dependency 'bundler', '~> 2.0'
32
+ spec.add_development_dependency 'change_orders'
33
+ spec.add_development_dependency 'dry-auto_inject'
34
+ spec.add_development_dependency 'dry-initializer'
35
+ spec.add_development_dependency 'dry-monads'
36
+ spec.add_development_dependency 'dry-struct'
37
+ spec.add_development_dependency 'dry-types'
38
+ spec.add_development_dependency 'dry-validation'
39
+ spec.add_development_dependency 'game_validator', '~> 0.6.0'
40
+ spec.add_development_dependency 'rake', '~> 10.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.0'
42
+ end
43
+