threesmodel 0.0.3 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/README.md +48 -7
  4. data/features/basic_folding.feature +32 -10
  5. data/features/basic_summing.feature +13 -13
  6. data/features/scoring.feature +14 -14
  7. data/features/steps/basic_steps.rb +21 -5
  8. data/features/steps/game_over_steps.rb +1 -2
  9. data/features/steps/game_play_steps.rb +7 -5
  10. data/lib/solvers/highest_paying_next_move_player.rb +19 -0
  11. data/lib/solvers/i_fear_down_folds_player.rb +20 -0
  12. data/lib/solvers/sample_automated_player.rb +16 -0
  13. data/lib/solvers/up_right_left_down_order_player.rb +20 -0
  14. data/lib/threesmodel.rb +65 -8
  15. data/lib/{candidate_extractor.rb → threesmodel/candidate_extractor.rb} +1 -1
  16. data/lib/{candidate_translator.rb → threesmodel/candidate_translator.rb} +0 -0
  17. data/lib/{game_board_folder.rb → threesmodel/game_board_folder.rb} +0 -1
  18. data/lib/{game_creator.rb → threesmodel/game_creator.rb} +1 -3
  19. data/lib/{game_over_checker.rb → threesmodel/game_over_checker.rb} +0 -0
  20. data/lib/{line_folder.rb → threesmodel/line_folder.rb} +5 -36
  21. data/lib/{next_number_determinator.rb → threesmodel/next_number_determinator.rb} +0 -0
  22. data/lib/{next_number_positioner.rb → threesmodel/next_number_positioner.rb} +0 -0
  23. data/lib/{score_calculator.rb → threesmodel/score_calculator.rb} +4 -0
  24. data/lib/threesmodel/version.rb +1 -1
  25. data/spec/candidate_extraction_spec.rb +1 -2
  26. data/spec/candidate_translator_spec.rb +1 -1
  27. data/spec/game_board_folder_spec.rb +10 -2
  28. data/spec/game_creator_spec.rb +1 -1
  29. data/spec/line_folder_spec.rb +56 -1
  30. data/spec/next_number_determination_spec.rb +1 -1
  31. data/spec/next_number_positioner_spec.rb +1 -1
  32. data/spec/run_sample_client_spec.rb +27 -0
  33. data/threesmodel.gemspec +1 -1
  34. metadata +18 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 957115b434fa33462e405bee92fa5d888674a0ca
4
- data.tar.gz: 5b7a6860503769c440c8218678f4324bb793a033
3
+ metadata.gz: 687648f2451c403616405c662e634c983a194032
4
+ data.tar.gz: 4cce10bc6b1fb25c34f81a90c8fb0fcc89851ad9
5
5
  SHA512:
6
- metadata.gz: fe6510bb2b3bb1336fdb24e9d1e7e36e1cc71e522ffc6aec469ecf9d276c12f41a825e428346a3c92d2ab68ae2ba940b391b8330eef7dcf176707360bf09d9bd
7
- data.tar.gz: 231be835a76ee3e4ba4e8c091f556ade7611abeccab1db1216970bcf1920d797e084d5d24643b756bdd28ea859f20f5080082752a8893e08f9d5836a4d541f3a
6
+ metadata.gz: 2a128c77f04e5e651b197121244690d2df366954baf906297dcfa953051bcb61727c3a2f81a32d028f985051db0036fbd471856c973f7104b123ff9f04f935d6
7
+ data.tar.gz: c256bfed6fcfa62d84bf6eef538ae0471baa971f1be2aab03cca76240f003f2d70cd67292950a5459f5f4d0b19d93bda864537d18fd96d93346d7f1429c99a62
data/.gitignore CHANGED
@@ -1,3 +1,7 @@
1
+ .idea
2
+ *.txt
3
+ *.tgz
4
+ *.iml
1
5
  *.gem
2
6
  *.rbc
3
7
  .bundle
data/README.md CHANGED
@@ -24,9 +24,11 @@ Or install it yourself as:
24
24
 
25
25
  Creating and playing a basic game works like this:
26
26
 
27
- require 'threesmodel'
28
- game_controller = Threesmodel::GameController.new
29
- game_state = game_controller.start_new_game
27
+ ```ruby
28
+ require 'threesmodel'
29
+ game_controller = Threesmodel::GameController.new
30
+ game_state = game_controller.start_new_game
31
+ ```
30
32
 
31
33
  The game state object is a hash with the keys :id (the identifier of the game),
32
34
  :game the layout of the current game board (as an instance of a Matrix class),
@@ -36,10 +38,49 @@ The game state object is a hash with the keys :id (the identifier of the game),
36
38
 
37
39
  Play by issuing fold calls to the game controller identifying the game with the id like this:
38
40
 
39
- game_state = game_controller.fold_left(game_state[:id])
40
- game_state = game_controller.fold_right(game_state[:id])
41
- game_state = game_controller.fold_up(game_state[:id])
42
- game_state = game_controller.fold_down(game_state[:id])
41
+ ```ruby
42
+ game_state = game_controller.fold_left(game_state[:id])
43
+ game_state = game_controller.fold_right(game_state[:id])
44
+ game_state = game_controller.fold_up(game_state[:id])
45
+ game_state = game_controller.fold_down(game_state[:id])
46
+ ```
47
+
48
+ ## Creating an automated solver
49
+
50
+ If you want to try to make an automated puzzel solver. You can do the following.
51
+
52
+ ```ruby
53
+ require 'threesmodel'
54
+ class MySmartPlayer < Threesmodel::BaseGameAutomation
55
+
56
+
57
+ def play()
58
+ # for your convenience you will have a few API classes set up for you.
59
+ # these two gives you the opportunity to try things out, before you decide
60
+ # which move you want to make
61
+ @game_board_folder
62
+ @score_calculator
63
+
64
+ # The game controller allows you to execute a move (or fold as I like to call it)
65
+ @game = @game_controller.fold_down(@game[:id])
66
+ end
67
+ ```
68
+ Note that you should keep the state returned after the fold in order to be able
69
+ to progress with the game.
70
+
71
+ Then you should call the automated solver in this manner (I usually use a rspec test cases as a runner).
72
+
73
+ ```ruby
74
+ player = MySmartPlayer.new
75
+ player.play_many(number_of_games_to_play)
76
+ ```
77
+ Where the "number_of_games_to_play" parameter is an integer stating the numnber of games the algorithm shall play.
78
+ The end result is a few stats about the runs. High score, a histogram of the value of the highest cell in the game board.
79
+ And a file (called by the solver class name dot txt) containing all the scores if you want to make your own statistical analysis.
80
+
81
+ Happy hacking!
82
+
83
+ Future ideas is to create some basic suppurt for setting up a solver algorithm competition.
43
84
 
44
85
 
45
86
  ## Contributing
@@ -1,66 +1,88 @@
1
1
  Feature: The start situation is playable and 1's fold into 2's to create 3's.
2
2
  Scenario: I have just started a game. The board is full of small numbers and empty cells.
3
3
 
4
- Given a gameboard
4
+ Given a game board
5
5
  |0|1|2|0|
6
6
  |0|1|2|0|
7
7
  |0|1|2|0|
8
8
  |0|1|2|0|
9
9
  When the game is folded right to left
10
- Then the gameboard looks like
10
+ Then the game board looks like
11
11
  |1|2|0|0|
12
12
  |1|2|0|0|
13
13
  |1|2|0|0|
14
14
  |1|2|0|0|
15
15
 
16
16
  Scenario: I am folding ones and twos in a fairly empty board
17
- Given a gameboard
17
+ Given a game board
18
18
  |1|2|0|0|
19
19
  |1|2|0|0|
20
20
  |1|2|0|0|
21
21
  |1|2|0|0|
22
22
  When the game is folded right to left
23
- Then the gameboard looks like
23
+ Then the game board looks like
24
24
  |3|0|0|0|
25
25
  |3|0|0|0|
26
26
  |3|0|0|0|
27
27
  |3|0|0|0|
28
28
 
29
29
  Scenario: I am folding right over zeros
30
- Given a gameboard
30
+ Given a game board
31
31
  |1|2|0|0|
32
32
  |1|2|0|0|
33
33
  |1|2|0|0|
34
34
  |1|2|0|0|
35
35
  When the game is folded left to right
36
- Then the gameboard looks like
36
+ Then the game board looks like
37
37
  |0|1|2|0|
38
38
  |0|1|2|0|
39
39
  |0|1|2|0|
40
40
  |0|1|2|0|
41
41
 
42
42
  Scenario: I am folding up over zeros
43
- Given a gameboard
43
+ Given a game board
44
44
  |0|0|0|0|
45
45
  |2|2|2|2|
46
46
  |1|1|1|1|
47
47
  |0|0|0|0|
48
48
  When the game is folded upwards
49
- Then the gameboard looks like
49
+ Then the game board looks like
50
50
  |2|2|2|2|
51
51
  |1|1|1|1|
52
52
  |0|0|0|0|
53
53
  |0|0|0|0|
54
54
 
55
55
  Scenario: I am folding down over zeros
56
- Given a gameboard
56
+ Given a game board
57
57
  |0|0|0|0|
58
58
  |2|2|2|2|
59
59
  |1|1|1|1|
60
60
  |0|0|0|0|
61
61
  When the game is folded downwards
62
- Then the gameboard looks like
62
+ Then the game board looks like
63
63
  |0|0|0|0|
64
64
  |0|0|0|0|
65
65
  |2|2|2|2|
66
66
  |1|1|1|1|
67
+
68
+ Scenario: Folding a specific game board
69
+ Given a game board
70
+ |2|24| 1|24|
71
+ |0| 3| 6|12|
72
+ |0| 6| 2| 2|
73
+ |0| 0| 0| 3|
74
+ Then the game board can fold left
75
+ And the game board can fold down
76
+ And the game board can not fold up
77
+ And the game board can not fold right
78
+
79
+ Scenario: Folding a specific game board
80
+ Given a game board
81
+ |6|12| 1| 6|
82
+ |2| 6| 1| 1|
83
+ |0| 0| 3|12|
84
+ |0| 0| 0| 2|
85
+ Then the game board can fold left
86
+ And the game board can fold down
87
+ And the game board can not fold up
88
+ And the game board can not fold right
@@ -1,81 +1,81 @@
1
1
  Feature: The start situation is playable and equal numbers fold to create new, double numbers.
2
2
  Scenario: Threes will fold into sixes.
3
- Given a gameboard
3
+ Given a game board
4
4
  |0| 0|0|0|
5
5
  |0| 0|0|0|
6
6
  |3| 6|0|0|
7
7
  |3|12|2|0|
8
8
  When the game is folded downwards
9
- Then the gameboard looks like
9
+ Then the game board looks like
10
10
  |0| 0|0|0|
11
11
  |0| 0|0|0|
12
12
  |0| 6|0|0|
13
13
  |6|12|2|0|
14
14
 
15
15
  Scenario: Equal numbers in several lines
16
- Given a gameboard
16
+ Given a game board
17
17
  |1|2| 0| 0|
18
18
  |1|2| 0| 0|
19
19
  |3|6|12|24|
20
20
  |3|6|12|24|
21
21
  When the game is folded downwards
22
- Then the gameboard looks like
22
+ Then the game board looks like
23
23
  |0| 0| 0| 0|
24
24
  |1| 2| 0| 0|
25
25
  |1| 2| 0| 0|
26
26
  |6|12|24|48|
27
27
 
28
28
  Scenario: Equal numbers in the middle of the line
29
- Given a gameboard
29
+ Given a game board
30
30
  |6|2| 3| 0|
31
31
  |6|3|12|24|
32
32
  |6|3|12|24|
33
33
  |3|6| 3| 3|
34
34
  When the game is folded downwards
35
- Then the gameboard looks like
35
+ Then the game board looks like
36
36
  | 0|0| 0| 0|
37
37
  | 6|2| 3| 0|
38
38
  |12|6|24|48|
39
39
  | 3|6| 3| 3|
40
40
 
41
41
  Scenario: Fold an unanimous matrix completely
42
- Given a gameboard
42
+ Given a game board
43
43
  |12|12|12|12|
44
44
  |12|12|12|12|
45
45
  |12|12|12|12|
46
46
  |12|12|12|12|
47
47
  When the game is folded downwards
48
- Then the gameboard looks like
48
+ Then the game board looks like
49
49
  | 0| 0| 0| 0|
50
50
  |12|12|12|12|
51
51
  |12|12|12|12|
52
52
  |24|24|24|24|
53
53
  When the game is folded downwards
54
- Then the gameboard looks like
54
+ Then the game board looks like
55
55
  | 0| 0| 0| 0|
56
56
  | 0| 0| 0| 0|
57
57
  |24|24|24|24|
58
58
  |24|24|24|24|
59
59
  When the game is folded downwards
60
- Then the gameboard looks like
60
+ Then the game board looks like
61
61
  | 0| 0| 0| 0|
62
62
  | 0| 0| 0| 0|
63
63
  | 0| 0| 0| 0|
64
64
  |48|48|48|48|
65
65
  When the game is folded right
66
- Then the gameboard looks like
66
+ Then the game board looks like
67
67
  |0| 0| 0| 0|
68
68
  |0| 0| 0| 0|
69
69
  |0| 0| 0| 0|
70
70
  |0|48|48|96|
71
71
  When the game is folded right
72
- Then the gameboard looks like
72
+ Then the game board looks like
73
73
  |0|0| 0| 0|
74
74
  |0|0| 0| 0|
75
75
  |0|0| 0| 0|
76
76
  |0|0|96|96|
77
77
  When the game is folded right
78
- Then the gameboard looks like
78
+ Then the game board looks like
79
79
  |0|0|0| 0|
80
80
  |0|0|0| 0|
81
81
  |0|0|0| 0|
@@ -1,6 +1,6 @@
1
1
  Feature: For every game state there is a score.
2
2
  Scenario: Ones and twos give zero points.
3
- Given a gameboard
3
+ Given a game board
4
4
  |0|0|0|1|
5
5
  |0|1|2|0|
6
6
  |2|1|0|2|
@@ -8,7 +8,7 @@ Scenario: Ones and twos give zero points.
8
8
  Then score is:"0"
9
9
 
10
10
  Scenario: A three gives 3 points
11
- Given a gameboard
11
+ Given a game board
12
12
  |0|0|0|1|
13
13
  |0|1|2|0|
14
14
  |2|1|0|2|
@@ -16,7 +16,7 @@ Scenario: A three gives 3 points
16
16
  Then score is:"3"
17
17
 
18
18
  Scenario: A six gives 9 points
19
- Given a gameboard
19
+ Given a game board
20
20
  |0|0|0|1|
21
21
  |0|1|2|0|
22
22
  |2|1|0|2|
@@ -24,7 +24,7 @@ Scenario: A six gives 9 points
24
24
  Then score is:"9"
25
25
 
26
26
  Scenario: A 12 gives 27 points
27
- Given a gameboard
27
+ Given a game board
28
28
  |0|0|0| 1|
29
29
  |0|1|2| 0|
30
30
  |2|1|0| 2|
@@ -32,7 +32,7 @@ Scenario: A 12 gives 27 points
32
32
  Then score is:"27"
33
33
 
34
34
  Scenario: A 24 gives 81 points
35
- Given a gameboard
35
+ Given a game board
36
36
  |0|0|0| 1|
37
37
  |0|1|2| 0|
38
38
  |2|1|0| 2|
@@ -40,7 +40,7 @@ Scenario: A 24 gives 81 points
40
40
  Then score is:"81"
41
41
 
42
42
  Scenario: A 48 gives 243 points
43
- Given a gameboard
43
+ Given a game board
44
44
  |0|0|0| 1|
45
45
  |0|1|2| 0|
46
46
  |2|1|0| 2|
@@ -48,7 +48,7 @@ Scenario: A 48 gives 243 points
48
48
  Then score is:"243"
49
49
 
50
50
  Scenario: A 96 gives 729 points
51
- Given a gameboard
51
+ Given a game board
52
52
  |0|0|0| 1|
53
53
  |0|1|2| 0|
54
54
  |2|1|0| 2|
@@ -56,7 +56,7 @@ Scenario: A 96 gives 729 points
56
56
  Then score is:"729"
57
57
 
58
58
  Scenario: A 192 gives 2187 points
59
- Given a gameboard
59
+ Given a game board
60
60
  |0|0|0| 1|
61
61
  |0|1|2| 0|
62
62
  |2|1|0| 2|
@@ -64,7 +64,7 @@ Scenario: A 192 gives 2187 points
64
64
  Then score is:"2187"
65
65
 
66
66
  Scenario: A 384 gives 6561 points
67
- Given a gameboard
67
+ Given a game board
68
68
  |0|0|0| 1|
69
69
  |0|1|2| 0|
70
70
  |2|1|0| 2|
@@ -72,7 +72,7 @@ Scenario: A 384 gives 6561 points
72
72
  Then score is:"6561"
73
73
 
74
74
  Scenario: A 768 gives 19683 points
75
- Given a gameboard
75
+ Given a game board
76
76
  |0|0|0| 1|
77
77
  |0|1|2| 0|
78
78
  |2|1|0| 2|
@@ -80,7 +80,7 @@ Scenario: A 768 gives 19683 points
80
80
  Then score is:"19683"
81
81
 
82
82
  Scenario: A 1536 gives 59049 points
83
- Given a gameboard
83
+ Given a game board
84
84
  |0|0|0| 1|
85
85
  |0|1|2| 0|
86
86
  |2|1|0| 2|
@@ -88,7 +88,7 @@ Scenario: A 1536 gives 59049 points
88
88
  Then score is:"59049"
89
89
 
90
90
  Scenario: A 3072 gives 177147 points
91
- Given a gameboard
91
+ Given a game board
92
92
  |0|0|0| 1|
93
93
  |0|1|2| 0|
94
94
  |2|1|0| 2|
@@ -96,7 +96,7 @@ Scenario: A 3072 gives 177147 points
96
96
  Then score is:"177147"
97
97
 
98
98
  Scenario: A 6144 gives 531441 points
99
- Given a gameboard
99
+ Given a game board
100
100
  |0|0|0| 1|
101
101
  |0|1|2| 0|
102
102
  |2|1|0| 2|
@@ -104,7 +104,7 @@ Scenario: A 6144 gives 531441 points
104
104
  Then score is:"531441"
105
105
 
106
106
  Scenario: All points are summed up
107
- Given a gameboard
107
+ Given a game board
108
108
  | 1| 2| 3| 6|
109
109
  | 12| 24| 48| 96|
110
110
  | 192| 384|768|1536|
@@ -1,8 +1,7 @@
1
- require 'Matrix'
2
- require_relative '../../lib/game_board_folder'
3
- require_relative '../../lib/score_calculator'
1
+ require 'threesmodel/game_board_folder'
2
+ require 'threesmodel/score_calculator'
4
3
 
5
- Given(/^a gameboard$/) do |table|
4
+ Given(/^a game board$/) do |table|
6
5
  @game_board = GameBoardFolder.new
7
6
  matrix = table.raw
8
7
  matrix = matrix.map{|l| l.map{|cell| cell.strip.to_i}}
@@ -29,7 +28,7 @@ When(/^the game is folded right$/) do
29
28
  @state = @game_board.fold_right @state
30
29
  end
31
30
 
32
- Then(/^the gameboard looks like$/) do |table|
31
+ Then(/^the game board looks like$/) do |table|
33
32
  matrix = table.raw
34
33
  matrix = matrix.map{|l| l.map{|cell| cell.strip.to_i}}
35
34
  expect(@state).to eq(Matrix.rows(matrix))
@@ -39,3 +38,20 @@ Then(/^score is:"(.*?)"$/) do |score|
39
38
  actual_score = ScoreCalculator.score_for(@state)
40
39
  expect(actual_score).to eq(score.to_i)
41
40
  end
41
+
42
+
43
+ Then(/^the game board can fold left$/) do
44
+ expect(@game_board.can_fold_left?(@state)).to eq(true)
45
+ end
46
+
47
+ Then(/^the game board can fold down$/) do
48
+ expect(@game_board.can_fold_down?(@state)).to eq(true)
49
+ end
50
+
51
+ Then(/^the game board can not fold up$/) do
52
+ expect(@game_board.can_fold_up?(@state)).to eq(false)
53
+ end
54
+
55
+ Then(/^the game board can not fold right$/) do
56
+ expect(@game_board.can_fold_right?(@state)).to eq(false)
57
+ end
@@ -1,5 +1,4 @@
1
- require 'Matrix'
2
- require_relative '../../lib/game_over_checker'
1
+ require 'threesmodel/game_over_checker'
3
2
 
4
3
  Before do
5
4
  @game_over_checker = GameOverChecker.new
@@ -1,5 +1,5 @@
1
- require_relative '../../lib/threesmodel'
2
-
1
+ require 'threesmodel'
2
+ require 'threesmodel/game_board_folder'
3
3
  Before do
4
4
  end
5
5
 
@@ -16,6 +16,7 @@ Then(/^the game is not over$/) do
16
16
  expect(@game_state[:game_over]).to eq(false)
17
17
  end
18
18
 
19
+
19
20
  Then(/^the game board has (\d+) cells filled$/) do |filled_cells|
20
21
  c = []
21
22
  values = @game_state[:game].row_vectors.each{|row|
@@ -28,12 +29,13 @@ end
28
29
 
29
30
  Then(/^the board contains no other but the following numbers:$/) do |table|
30
31
  data = table.raw[0]
32
+ data = data.map{|x| x.to_i}
31
33
  c = []
32
- values = @game_state[:game].row_vectors.each{|row|
34
+ @game_state[:game].row_vectors.each{|row|
33
35
  c << row.to_a
34
36
  }
35
37
  c.flatten!.uniq!
36
- data.each{|value|
37
- expect(c.include?(value.to_i)).to eq(true)
38
+ c.each{|value|
39
+ expect(data.include?(value.to_i)).to eq(true)
38
40
  }
39
41
  end
@@ -0,0 +1,19 @@
1
+ require 'threesmodel'
2
+
3
+ class HighestPayingNextMovePlayer < Threesmodel::BaseGameAutomation
4
+ def play
5
+ while (not @game[:game_over]) do
6
+ possible_moves = [:fold_right, :fold_left, :fold_up, :fold_down]
7
+ possible_moves.select! do |move|
8
+ @game_board_folder.send("can_#{move.to_s}?".to_sym, @game[:game])
9
+ end
10
+
11
+ scored_moves = possible_moves.map do |move|
12
+ [move, @score_calculator.score_for(@game_board_folder.send(move, @game[:game]))]
13
+ end
14
+ new_move = scored_moves.max{ |a, b| a[1] <=> b[1] }[0]
15
+ @game = @game_controller.send(new_move, @game[:id])
16
+ end
17
+ @game[:score]
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require 'threesmodel'
2
+
3
+ class IFearDownFoldsPlayer < Threesmodel::BaseGameAutomation
4
+
5
+ def play
6
+ while (not @game[:game_over]) do
7
+
8
+ if (@game_board_folder.can_fold_up?(@game[:game]) or @game_board_folder.can_fold_left?(@game[:game]) or @game_board_folder.can_fold_right?(@game[:game])) then
9
+ @game_controller.fold_up(@game[:id])
10
+ @game_controller.fold_right(@game[:id])
11
+ @game = @game_controller.fold_left(@game[:id])
12
+ else
13
+ @game = @game_controller.fold_down(@game[:id])
14
+ end
15
+
16
+ end
17
+ @game[:score]
18
+ end
19
+
20
+ end
@@ -0,0 +1,16 @@
1
+ require 'threesmodel'
2
+
3
+
4
+ class SampleAutomatedPlayer < Threesmodel::BaseGameAutomation
5
+
6
+ def play
7
+ while (not @game[:game_over]) do
8
+ @game_controller.fold_right(@game[:id])
9
+ @game_controller.fold_up(@game[:id])
10
+ @game_controller.fold_left(@game[:id])
11
+ @game = @game_controller.fold_down(@game[:id])
12
+ end
13
+ @game[:score]
14
+ end
15
+
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'threesmodel'
2
+
3
+ class UpRightLeftDownOrderPlayer < Threesmodel::BaseGameAutomation
4
+
5
+ def play
6
+ while (not @game[:game_over]) do
7
+ if @game_board_folder.can_fold_up?(@game[:game])
8
+ @game = @game_controller.fold_up(@game[:id])
9
+ elsif @game_board_folder.can_fold_right?(@game[:game])
10
+ @game = @game_controller.fold_right(@game[:id])
11
+ elsif @game_board_folder.can_fold_left?(@game[:game])
12
+ @game = @game_controller.fold_left(@game[:id])
13
+ else
14
+ @game = @game_controller.fold_down(@game[:id])
15
+ end
16
+ end
17
+ @game[:score]
18
+ end
19
+
20
+ end
data/lib/threesmodel.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require "threesmodel/version"
2
- require 'candidate_translator'
3
- require 'candidate_extractor'
4
- require 'game_board_folder'
5
- require 'next_number_positioner'
6
- require 'next_number_determinator'
7
- require 'game_over_checker'
8
- require 'game_creator'
2
+ require 'threesmodel/candidate_translator'
3
+ require 'threesmodel/candidate_extractor'
4
+ require 'threesmodel/game_board_folder'
5
+ require 'threesmodel/next_number_positioner'
6
+ require 'threesmodel/next_number_determinator'
7
+ require 'threesmodel/game_over_checker'
8
+ require 'threesmodel/game_creator'
9
9
  require 'securerandom'
10
+ require 'threesmodel/score_calculator'
10
11
  require 'matrix'
11
- require 'score_calculator'
12
12
 
13
13
  module Threesmodel
14
14
  class InternalAPI
@@ -16,6 +16,63 @@ module Threesmodel
16
16
 
17
17
  end
18
18
  end
19
+
20
+ class BaseGameAutomation
21
+ def initialize
22
+ @game_controller = Threesmodel::GameController.new
23
+ @game_board_folder = GameBoardFolder.new
24
+ @score_calculator = ScoreCalculator.new
25
+ @scores = []
26
+ @highest_cell_value_histogram = { c3: 0, c6: 0, c12: 0, c24: 0, c48: 0, c96: 0, c192: 0, c384: 0, c768: 0, c1536: 0, c3072: 0, c6144:0}
27
+ @best_game = nil
28
+ end
29
+
30
+ def play;
31
+ raise 'Method missing - please implement "play" method.';
32
+ end
33
+
34
+ def score_filename
35
+ self.class.name + ".txt"
36
+ end
37
+
38
+ def play_many(times=100)
39
+ max_score = 0
40
+ iteration = 1
41
+ times.times do
42
+ @game = @game_controller.start_new_game
43
+ score = play
44
+ if score > max_score then
45
+ max_score = score
46
+ @best_game = @game[:game]
47
+ end
48
+ @scores << score
49
+ print "." if iteration % 1000 == 0
50
+ update_highest_value_histogram(@game[:game])
51
+ end
52
+ puts "Done!"
53
+ puts max_score
54
+ puts @highest_cell_value_histogram
55
+
56
+ File.open(score_filename, "w+") do |f|
57
+ f.puts(@scores)
58
+ end
59
+
60
+ puts "Best game is:"
61
+ puts @best_game
62
+ end
63
+
64
+ def update_highest_value_histogram(game_board)
65
+ highest_cell_value = 0
66
+ game_board.each { |val|
67
+ highest_cell_value = val if val > highest_cell_value
68
+ }
69
+ key = ("c" + highest_cell_value.to_s).to_sym
70
+ @highest_cell_value_histogram[key] += 1
71
+ end
72
+
73
+ end
74
+
75
+
19
76
  class GameController
20
77
 
21
78
  def initialize
@@ -1,4 +1,4 @@
1
- require 'line_folder'
1
+ require_relative 'line_folder'
2
2
  class CandidateExtractor
3
3
 
4
4
  def initialize(line_folder = LineFolder.new)
@@ -1,5 +1,4 @@
1
1
  require_relative 'line_folder'
2
- require "Matrix"
3
2
  # A game board keeps and manipulates the state of the game.
4
3
  class GameBoardFolder
5
4
 
@@ -1,5 +1,3 @@
1
- require 'Matrix'
2
-
3
1
  class GameCreator
4
2
  def self.create_new_game
5
3
  positions = random_positions(9)
@@ -27,4 +25,4 @@ class GameCreator
27
25
  end
28
26
  positions
29
27
  end
30
- end
28
+ end
@@ -18,12 +18,15 @@ class LineFolder
18
18
  end
19
19
 
20
20
  def wall_index_of
21
+ return 3 if self == ([1,1,1,1] or [2,2,2,2])
22
+ return 3 if self[1..3] == [0,0,0]
21
23
  return 0 if self[0] == 0
22
24
  return 0 if self[0] == 1 and self[1] == 2
23
25
  return 0 if self[0] == 2 and self[1] == 1
24
26
  if self[0] > 2
25
27
  return 0 if self[0] == self[1]
26
28
  end
29
+ return 3 if self[2..3] == [0,0]
27
30
  return 1 if self[1] == 0
28
31
  return 1 if (self[0] != self[1]) and self[1] == 1 and self[2] == 2
29
32
  return 1 if (self[0] != self[1]) and self[1] == 2 and self[2] == 1
@@ -38,6 +41,7 @@ class LineFolder
38
41
  if self[2] > 2
39
42
  return 2 if self[2] == self[3]
40
43
  end
44
+ 3
41
45
  end
42
46
 
43
47
  end
@@ -45,7 +49,6 @@ class LineFolder
45
49
 
46
50
  def fold(line)
47
51
  if can_fold?(line) then
48
- if(line == [0,0,0,0]) then return line end
49
52
  return line.squash
50
53
  else
51
54
  return line
@@ -53,41 +56,7 @@ class LineFolder
53
56
  end
54
57
 
55
58
  def can_fold?(line)
56
- foldable = has_adjacent_one_and_two?(line)
57
- foldable = (foldable or has_adjacent_equals?(line))
58
- foldable = (foldable or has_non_trailing_zeros?(line))
59
- return foldable
60
- end
61
-
62
- def has_non_trailing_zeros?(line)
63
- first_non_zero_from_end = index_of_first_non_trailing_zero(line)
64
- if (first_non_zero_from_end == nil) then return true end
65
- if (line.index(0) == nil) then return false end
66
- return (line.index(0) < first_non_zero_from_end)
67
- end
68
-
69
- def index_of_first_non_trailing_zero(line)
70
- first_non_zero_from_end = line.rindex {|element| element != 0}
71
- end
72
-
73
- def has_adjacent_one_and_two?(line)
74
- pairs = line.each_cons(2).to_a
75
- index = pairs.each_index {|i|
76
- if (pairs[i].sort == [1, 2])
77
- return true
78
- end
79
- }
80
- false
81
- end
82
-
83
- def has_adjacent_equals?(line)
84
- pairs = line.each_cons(2).to_a
85
- index = pairs.each {|pair|
86
- if(pair[0] == pair[1] and (pair[0] > 2))
87
- return true
88
- end
89
- }
90
- false
59
+ return line.wall_index_of < 3
91
60
  end
92
61
 
93
62
  end
@@ -24,4 +24,8 @@ class ScoreCalculator
24
24
  score
25
25
  end
26
26
 
27
+ def score_for(game_board)
28
+ ScoreCalculator.score_for(game_board)
29
+ end
30
+
27
31
  end
@@ -1,3 +1,3 @@
1
1
  module Threesmodel
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -1,5 +1,4 @@
1
- require_relative "../lib/candidate_extractor"
2
- require "Matrix"
1
+ require "threesmodel/candidate_extractor"
3
2
 
4
3
  describe CandidateExtractor do
5
4
 
@@ -1,4 +1,4 @@
1
- require_relative '../lib/candidate_translator'
1
+ require 'threesmodel/candidate_translator'
2
2
  describe CandidateTranslator do
3
3
 
4
4
  it "translates left fold candidates with same candidates" do
@@ -1,5 +1,4 @@
1
- require_relative "../lib/game_board_folder"
2
- require "Matrix"
1
+ require "threesmodel/game_board_folder"
3
2
 
4
3
  describe GameBoardFolder do
5
4
 
@@ -47,4 +46,13 @@ describe GameBoardFolder do
47
46
  expect(state.row(3).to_a).to eq([2,2,2,2])
48
47
  end
49
48
 
49
+ it "can not fold up when no columns can be folded" do
50
+ state = @game_board_folder.can_fold_up?(
51
+ Matrix.rows([[3,0,3,3],
52
+ [2,0,2,1],
53
+ [3,0,3,3],
54
+ [2,0,2,1]]))
55
+ expect(state).to eq(false)
56
+ end
57
+
50
58
  end
@@ -1,5 +1,5 @@
1
1
  require 'rspec'
2
- require_relative '../lib/game_creator'
2
+ require 'threesmodel/game_creator'
3
3
  require 'custom_matchers'
4
4
 
5
5
  describe 'Create new Game' do
@@ -1,4 +1,4 @@
1
- require_relative "../lib/line_folder"
1
+ require "threesmodel/line_folder"
2
2
 
3
3
  describe LineFolder do
4
4
 
@@ -33,10 +33,18 @@ describe LineFolder do
33
33
  expect(@line_folder.can_fold?([0,0,1,2])).to eq(true)
34
34
  end
35
35
 
36
+ it "can not fold when line is all zeros" do
37
+ expect(@line_folder.can_fold?([0,0,0,0])).to eq(false)
38
+ end
39
+
36
40
  it "can not fold when line is all ones" do
37
41
  expect(@line_folder.can_fold?([1,1,1,1])).to eq(false)
38
42
  end
39
43
 
44
+ it "can not fold when line is all twos" do
45
+ expect(@line_folder.can_fold?([2,2,2,2])).to eq(false)
46
+ end
47
+
40
48
  it "can fold when line has a one and a two adjacent" do
41
49
  expect(@line_folder.can_fold?([1,2,1,1])).to eq(true)
42
50
  end
@@ -49,6 +57,20 @@ describe LineFolder do
49
57
  expect(@line_folder.can_fold?([3,3,6,12])).to eq(true)
50
58
  end
51
59
 
60
+ it "can not fold" do
61
+ expect(@line_folder.can_fold?([2,0,0,0])).to eq(false)
62
+ expect(@line_folder.can_fold?([24,3,6,0])).to eq(false)
63
+ expect(@line_folder.can_fold?([1,6,2,0])).to eq(false)
64
+ expect(@line_folder.can_fold?([24,12,2,3])).to eq(false)
65
+ end
66
+
67
+ it "can not even fold" do
68
+ expect(@line_folder.can_fold?([6,2,0,0])).to eq(false)
69
+ expect(@line_folder.can_fold?([12,6,0,0])).to eq(false)
70
+ expect(@line_folder.can_fold?([1,1,3,0])).to eq(false)
71
+ expect(@line_folder.can_fold?([6,1,12,2])).to eq(false)
72
+ end
73
+
52
74
  it "folds undetectably when all zero line" do
53
75
  expect(@line_folder.fold([0,0,0,0])).to eq([0,0,0,0])
54
76
  end
@@ -84,4 +106,37 @@ describe LineFolder do
84
106
  expect(@line_folder.fold([1,2,0,3])).to eq([3,0,3,0])
85
107
  end
86
108
 
109
+ it "considers to have the wall index at cell 3 for an all zero line" do
110
+ expect([0,0,0,0].wall_index_of).to eq(3)
111
+ end
112
+ it "considers to have the wall index at cell 3 for an all ones line" do
113
+ expect([1,1,1,1].wall_index_of).to eq(3)
114
+ end
115
+ it "considers to have the wall index at cell 3 for an all twos line" do
116
+ expect([2,2,2,2].wall_index_of).to eq(3)
117
+ end
118
+
119
+ it "considers an line with trailing zeros to have wall index 3" do
120
+ expect([2,0,0,0].wall_index_of).to eq(3)
121
+ end
122
+
123
+ it "considers an line with less trailing zeros to have wall index 3" do
124
+ expect([2,2,0,0].wall_index_of).to eq(3)
125
+ end
126
+
127
+ it "considers an line with trailing ones to have wall index 3" do
128
+ expect([3,1,1,1].wall_index_of).to eq(3)
129
+ end
130
+
131
+ it "considers an line with less trailing ones to have wall index 3" do
132
+ expect([3,6,1,1].wall_index_of).to eq(3)
133
+ end
134
+
135
+ it "considers an line with trailing twos to have wall index 3" do
136
+ expect([3,2,2,2].wall_index_of).to eq(3)
137
+ end
138
+
139
+ it "considers an line with less trailing twos to have wall index 3" do
140
+ expect([3,6,2,2].wall_index_of).to eq(3)
141
+ end
87
142
  end
@@ -1,4 +1,4 @@
1
- require_relative "../lib/next_number_determinator"
1
+ require "threesmodel/next_number_determinator"
2
2
  require_relative "custom_matchers"
3
3
 
4
4
  describe NextNumberDeterminator do
@@ -1,4 +1,4 @@
1
- require_relative "../lib/next_number_positioner"
1
+ require "threesmodel/next_number_positioner"
2
2
  require_relative "custom_matchers"
3
3
 
4
4
  describe NextNumberPositioner do
@@ -0,0 +1,27 @@
1
+ require "solvers/sample_automated_player"
2
+ require "solvers/i_fear_down_folds_player"
3
+ require "solvers/up_right_left_down_order_player"
4
+ require "solvers/highest_paying_next_move_player"
5
+
6
+ describe SampleAutomatedPlayer do
7
+ it "runs the sample automated player" do
8
+ player = SampleAutomatedPlayer.new
9
+ player.play_many(5)
10
+ end
11
+
12
+ it "runs the player that tries to avoid down folds" do
13
+ player = IFearDownFoldsPlayer.new
14
+ player.play_many(5)
15
+ end
16
+
17
+ it "runs the player that tries to fold up right" do
18
+ player = UpRightLeftDownOrderPlayer.new
19
+ player.play_many(5)
20
+ end
21
+
22
+ it "runs the player that goes with the highest paying next move" do
23
+ player = HighestPayingNextMovePlayer.new
24
+ player.play_many(5)
25
+ end
26
+
27
+ end
data/threesmodel.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["mans.sandstrom@gmail.com"]
11
11
  spec.description = %q{A stab at implementing the game logic for the game threes, eventually making it scriptable for a bot.}
12
12
  spec.summary = %q{An API for something that resembles the game threes}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/msa/threesmodel"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: threesmodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Måns Sandström
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-16 00:00:00.000000000 Z
11
+ date: 2017-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -60,16 +60,20 @@ files:
60
60
  - features/steps/basic_steps.rb
61
61
  - features/steps/game_over_steps.rb
62
62
  - features/steps/game_play_steps.rb
63
- - lib/candidate_extractor.rb
64
- - lib/candidate_translator.rb
65
- - lib/game_board_folder.rb
66
- - lib/game_creator.rb
67
- - lib/game_over_checker.rb
68
- - lib/line_folder.rb
69
- - lib/next_number_determinator.rb
70
- - lib/next_number_positioner.rb
71
- - lib/score_calculator.rb
63
+ - lib/solvers/highest_paying_next_move_player.rb
64
+ - lib/solvers/i_fear_down_folds_player.rb
65
+ - lib/solvers/sample_automated_player.rb
66
+ - lib/solvers/up_right_left_down_order_player.rb
72
67
  - lib/threesmodel.rb
68
+ - lib/threesmodel/candidate_extractor.rb
69
+ - lib/threesmodel/candidate_translator.rb
70
+ - lib/threesmodel/game_board_folder.rb
71
+ - lib/threesmodel/game_creator.rb
72
+ - lib/threesmodel/game_over_checker.rb
73
+ - lib/threesmodel/line_folder.rb
74
+ - lib/threesmodel/next_number_determinator.rb
75
+ - lib/threesmodel/next_number_positioner.rb
76
+ - lib/threesmodel/score_calculator.rb
73
77
  - lib/threesmodel/version.rb
74
78
  - spec/candidate_extraction_spec.rb
75
79
  - spec/candidate_translator_spec.rb
@@ -79,9 +83,10 @@ files:
79
83
  - spec/line_folder_spec.rb
80
84
  - spec/next_number_determination_spec.rb
81
85
  - spec/next_number_positioner_spec.rb
86
+ - spec/run_sample_client_spec.rb
82
87
  - spec/spec_helper.rb
83
88
  - threesmodel.gemspec
84
- homepage: ''
89
+ homepage: https://github.com/msa/threesmodel
85
90
  licenses:
86
91
  - MIT
87
92
  metadata: {}
@@ -122,4 +127,5 @@ test_files:
122
127
  - spec/line_folder_spec.rb
123
128
  - spec/next_number_determination_spec.rb
124
129
  - spec/next_number_positioner_spec.rb
130
+ - spec/run_sample_client_spec.rb
125
131
  - spec/spec_helper.rb