monkeymusic 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +21 -0
- data/README.markdown +38 -0
- data/bin/monkeymusic +5 -0
- data/levels/testlevel.rb +28 -0
- data/levels/testlevel_maze.rb +24 -0
- data/levels/the_last_crusade.rb +21 -0
- data/levels/travelling_salesmonkeys.rb +0 -0
- data/lib/monkey_music/game.rb +27 -0
- data/lib/monkey_music/level.rb +91 -0
- data/lib/monkey_music/level_loader.rb +64 -0
- data/lib/monkey_music/player.rb +41 -0
- data/lib/monkey_music/recommendation_loader.rb +91 -0
- data/lib/monkey_music/runner.rb +169 -0
- data/lib/monkey_music/score_system.rb +37 -0
- data/lib/monkey_music/toplist_loader.rb +68 -0
- data/lib/monkey_music/ui/browser_ui.rb +36 -0
- data/lib/monkey_music/ui/console_ui.rb +31 -0
- data/lib/monkey_music/units/base.rb +71 -0
- data/lib/monkey_music/units/monkey.rb +85 -0
- data/lib/monkey_music/units/track.rb +33 -0
- data/lib/monkey_music/units/user.rb +38 -0
- data/lib/monkey_music/units/wall.rb +4 -0
- data/lib/monkey_music.rb +20 -0
- data/users/synth.rb +7 -0
- data/users/synth.yaml +1682 -0
- metadata +136 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
em-websocket (0.5.0)
|
5
|
+
eventmachine (>= 0.12.9)
|
6
|
+
http_parser.rb (~> 0.5.3)
|
7
|
+
eventmachine (1.0.3)
|
8
|
+
ffi (1.8.1)
|
9
|
+
hallon (0.18.2)
|
10
|
+
ffi (~> 1.8)
|
11
|
+
spotify (~> 12.5.1)
|
12
|
+
weak_observable (~> 1.0)
|
13
|
+
http_parser.rb (0.5.3)
|
14
|
+
json (1.7.7)
|
15
|
+
libspotify (12.1.51.3)
|
16
|
+
rack (1.5.2)
|
17
|
+
ref (1.0.4)
|
18
|
+
spotify (12.5.1)
|
19
|
+
ffi (~> 1.0, >= 1.0.11)
|
20
|
+
libspotify (~> 12.1.51)
|
21
|
+
weak_observable (1.0.1)
|
22
|
+
ref (~> 1.0.0)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
em-websocket
|
29
|
+
hallon
|
30
|
+
json
|
31
|
+
rack
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 Ryan Bates
|
2
|
+
2013 Oscar Söderlund
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
Monkey Music
|
2
|
+
============
|
3
|
+
|
4
|
+
This is the runtime for a programming contest, it's a work in progress.
|
5
|
+
|
6
|
+
To test-drive:
|
7
|
+
|
8
|
+
./bin/monkeymusic --user users/poscar.yaml --level levels/testlevel.rb --player-file p1 --player-name p1 --player-file p1 --player-name p2
|
9
|
+
|
10
|
+
Rules
|
11
|
+
-----
|
12
|
+
|
13
|
+
### Which monkey gets to move first?
|
14
|
+
|
15
|
+
Every round, all monkeys are put into a Fisher-Yates shuffled array, and
|
16
|
+
the monkeys will be allowed to move in order of increasing index.
|
17
|
+
|
18
|
+
Input
|
19
|
+
-----
|
20
|
+
|
21
|
+
One line with one positive integer, id, that identifies your monkey.
|
22
|
+
One line with two positive integers, w, h. The width and the
|
23
|
+
height of the level.
|
24
|
+
h lines with w comma-separated strings each. Each string represents a
|
25
|
+
space in the level.
|
26
|
+
|
27
|
+
A space can contain the following:
|
28
|
+
|
29
|
+
A monkey, on the form M#id, the letter M followed by a hash followed by the id of a monkey.
|
30
|
+
A basket, on the form B#id, the letter B followed by a hash followed by
|
31
|
+
A track URI, on the form spotify:track:XXXXXXXXXXXXXXX.
|
32
|
+
the id of the monkey the basket belongs to.
|
33
|
+
A palm tree, on the form P.
|
34
|
+
|
35
|
+
Output
|
36
|
+
------
|
37
|
+
|
38
|
+
One of the characters ['N','W','E','S'] followed by a line-break '\n'.
|
data/bin/monkeymusic
ADDED
data/levels/testlevel.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
carrying_capacity 3
|
2
|
+
metadata_requests_per_turn 2
|
3
|
+
max_turns 100
|
4
|
+
|
5
|
+
legend({
|
6
|
+
"1" => Monkey.player(1),
|
7
|
+
"2" => Monkey.player(2),
|
8
|
+
"X" => Track.worth(-2),
|
9
|
+
"x" => Track.worth(-1),
|
10
|
+
"l" => Track.worth(1),
|
11
|
+
"t" => Track.worth(2),
|
12
|
+
"T" => Track.worth(3),
|
13
|
+
"U" => User,
|
14
|
+
})
|
15
|
+
|
16
|
+
layout <<LAYOUT
|
17
|
+
...........
|
18
|
+
..x........
|
19
|
+
...........
|
20
|
+
.......T...
|
21
|
+
1..........
|
22
|
+
...t......U
|
23
|
+
2..........
|
24
|
+
.......l...
|
25
|
+
...........
|
26
|
+
..X........
|
27
|
+
...........
|
28
|
+
LAYOUT
|
@@ -0,0 +1,24 @@
|
|
1
|
+
width 25
|
2
|
+
height 11
|
3
|
+
max_turns 200
|
4
|
+
carrying_capacity 100
|
5
|
+
|
6
|
+
legend({
|
7
|
+
"1" => Monkey,
|
8
|
+
"!" => Track,
|
9
|
+
"#" => Wall,
|
10
|
+
})
|
11
|
+
|
12
|
+
layout <<LAYOUT
|
13
|
+
#########################
|
14
|
+
#! # # !#
|
15
|
+
### ###### # #######
|
16
|
+
# # # #
|
17
|
+
# ### ###### # #
|
18
|
+
# #! # # # #
|
19
|
+
# # # ### # # #
|
20
|
+
# # # # #1 # #
|
21
|
+
# ###### ########## #
|
22
|
+
# !# #
|
23
|
+
#########################
|
24
|
+
LAYOUT
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# In this level, the monkeys ability to navigate a maze and pick
|
2
|
+
# the best out of many tracks is tested. Do not choose poorly...
|
3
|
+
|
4
|
+
width 20
|
5
|
+
height 10
|
6
|
+
capacity 1
|
7
|
+
|
8
|
+
legend({
|
9
|
+
"T" => Tube,
|
10
|
+
"M" => Monkey,
|
11
|
+
"s" => Track,
|
12
|
+
"#" => Wall,
|
13
|
+
})
|
14
|
+
|
15
|
+
layout <<EOS
|
16
|
+
T..#.....#.....#...s
|
17
|
+
...#..#..#..#..#...s
|
18
|
+
.M.#..#..#..#..#...s
|
19
|
+
...#..#..#..#..#...s
|
20
|
+
......#.....#......s
|
21
|
+
EOS
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module MonkeyMusic
|
4
|
+
class Game
|
5
|
+
|
6
|
+
def initialize(level, players, ui)
|
7
|
+
@level = level
|
8
|
+
@players = players
|
9
|
+
@ui = ui
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
@level.max_turns.times do
|
14
|
+
if @level.complete?
|
15
|
+
break
|
16
|
+
end
|
17
|
+
@ui.update(@level)
|
18
|
+
# Query players for moves
|
19
|
+
@players.each { |p| p.query_move! }
|
20
|
+
# Move players in random order
|
21
|
+
@players.shuffle.each { |p| p.move! }
|
22
|
+
end
|
23
|
+
@ui.update(@level)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module MonkeyMusic
|
4
|
+
class Level
|
5
|
+
attr_accessor :width, :height, :max_turns
|
6
|
+
attr_reader :players
|
7
|
+
attr_reader :user
|
8
|
+
|
9
|
+
def initialize(players, user)
|
10
|
+
@players = players
|
11
|
+
@user = user
|
12
|
+
@width = 0
|
13
|
+
@height = 0
|
14
|
+
@units = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(unit, x, y)
|
18
|
+
unit.place!(self, x, y)
|
19
|
+
unit.assign_id
|
20
|
+
@units << unit
|
21
|
+
end
|
22
|
+
|
23
|
+
def at(x, y)
|
24
|
+
@units.detect { |u| u.at?(x, y) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty?(x, y)
|
28
|
+
at(x, y).nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def complete?
|
32
|
+
(@units.detect { |u| u.kind_of? Track }).nil? &&
|
33
|
+
(@players.detect { |p| p.monkey.carrying.count > 0 }).nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def remove(unit)
|
37
|
+
@units.reject! { |u| u == unit }
|
38
|
+
end
|
39
|
+
|
40
|
+
def out_of_bounds?(x, y)
|
41
|
+
x < 0 || y < 0 || x > @width-1 || y > @height-1
|
42
|
+
end
|
43
|
+
|
44
|
+
def accessible?(x, y)
|
45
|
+
not out_of_bounds?(x, y) && empty?(x, y)
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_from_file(file)
|
49
|
+
LevelLoader.new(self).instance_eval(IO.read(file))
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
rows = []
|
55
|
+
rows << " " + ("=" * @width)
|
56
|
+
@height.times do |y|
|
57
|
+
row = ["|"]
|
58
|
+
@width.times do |x|
|
59
|
+
unit = at(x, y)
|
60
|
+
row << if unit then unit.to_s else ' ' end
|
61
|
+
end
|
62
|
+
row << "|"
|
63
|
+
rows << row.join
|
64
|
+
end
|
65
|
+
rows << " " + ("=" * @width)
|
66
|
+
rows.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
def serialize
|
70
|
+
rows = []
|
71
|
+
@height.times do |y|
|
72
|
+
row = []
|
73
|
+
@width.times do |x|
|
74
|
+
unit = at(x, y)
|
75
|
+
row << if unit then unit.serialize else '_' end
|
76
|
+
end
|
77
|
+
rows << row.join(",")
|
78
|
+
end
|
79
|
+
rows.join("\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
def as_json
|
83
|
+
{
|
84
|
+
:width => @width,
|
85
|
+
:height => @height,
|
86
|
+
:units => @units,
|
87
|
+
}.to_json
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module MonkeyMusic
|
2
|
+
#
|
3
|
+
# LevelLoader defines a DSL for building levels in a ruby file
|
4
|
+
#
|
5
|
+
class LevelLoader
|
6
|
+
def initialize(level)
|
7
|
+
@level = level
|
8
|
+
@legend = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def max_turns(max_turns)
|
12
|
+
@level.max_turns = max_turns
|
13
|
+
end
|
14
|
+
|
15
|
+
def metadata_requests_per_turn(n)
|
16
|
+
@metadata_requests_per_turn = n
|
17
|
+
end
|
18
|
+
|
19
|
+
def carrying_capacity(capacity)
|
20
|
+
@level.players.each { |p| p.monkey.capacity = capacity }
|
21
|
+
end
|
22
|
+
|
23
|
+
def legend(legend)
|
24
|
+
@legend = legend
|
25
|
+
end
|
26
|
+
|
27
|
+
def layout(layout)
|
28
|
+
# Transform layout into x y indexed array
|
29
|
+
units = (layout.lines.map { |l| l.chomp.split(//) }).transpose
|
30
|
+
@level.width = units[0].length
|
31
|
+
@level.height = units.length
|
32
|
+
# Add units from layout to level
|
33
|
+
@level.height.times do |y|
|
34
|
+
@level.width.times do |x|
|
35
|
+
curr_character = units[x][y]
|
36
|
+
unit = parse_character(curr_character)
|
37
|
+
@level.add(unit, x, y) if unit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_character(character)
|
45
|
+
klass = @legend[character]
|
46
|
+
if klass
|
47
|
+
unit = if (klass <= Monkey)
|
48
|
+
klass.from_players(@level.players)
|
49
|
+
elsif klass <= Track
|
50
|
+
klass.from_user(@level.user)
|
51
|
+
elsif klass == User
|
52
|
+
@level.user
|
53
|
+
else
|
54
|
+
klass.new
|
55
|
+
end
|
56
|
+
if unit
|
57
|
+
unit.character = character
|
58
|
+
unit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MonkeyMusic
|
2
|
+
class Player
|
3
|
+
attr_accessor :monkey
|
4
|
+
|
5
|
+
def initialize(file)
|
6
|
+
@file = file
|
7
|
+
@monkey = Monkey.new()
|
8
|
+
end
|
9
|
+
|
10
|
+
def query_move!
|
11
|
+
IO.popen(@file, "r+") do |io|
|
12
|
+
io.puts @monkey.serialize
|
13
|
+
io.puts @monkey.remaining_capacity
|
14
|
+
io.puts @monkey.level.width
|
15
|
+
io.puts @monkey.level.height
|
16
|
+
io.puts @monkey.level.serialize
|
17
|
+
move = io.gets
|
18
|
+
@next_move = parse_move(move) if move
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_move(s)
|
23
|
+
case s.chomp
|
24
|
+
when "N" then :north
|
25
|
+
when "W" then :west
|
26
|
+
when "E" then :east
|
27
|
+
when "S" then :south
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def move!
|
32
|
+
@monkey.move! @next_move if @next_move
|
33
|
+
@next_move = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"#{@monkey.name}: #{@file}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'hallon'
|
2
|
+
|
3
|
+
module MonkeyMusic
|
4
|
+
class RecommendationLoader
|
5
|
+
|
6
|
+
def initialize(loaded_toplists, load_factor = 5)
|
7
|
+
@loaded_toplists = loaded_toplists
|
8
|
+
@load_factor = load_factor
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_for_user!(user)
|
12
|
+
@user = user
|
13
|
+
puts "Loading recommendations from album toplist..."
|
14
|
+
load_recommendations_from_albums!
|
15
|
+
puts "Loading recommendations from artist toplist..."
|
16
|
+
load_recommendations_from_artists!
|
17
|
+
puts "Loading recommendations from track toplist albums..."
|
18
|
+
load_recommendations_from_top_track_albums!
|
19
|
+
puts "Loading recommendations from track toplist..."
|
20
|
+
load_recommendations_from_already_heard!
|
21
|
+
puts "Loading recommendations from disliked artists..."
|
22
|
+
load_recommendations_from_disliked!
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def load_recommendations_from_albums!
|
28
|
+
@loaded_toplists[:top_albums].each do |album|
|
29
|
+
puts "Browsing #{album.name}..."
|
30
|
+
browse = album.browse
|
31
|
+
browse.load unless browse.loaded?
|
32
|
+
browse.tracks.first(@load_factor).each do |rec|
|
33
|
+
@user.recommendations << parse_track(rec)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_recommendations_from_artists!
|
39
|
+
@loaded_toplists[:top_artists].each do |artist|
|
40
|
+
puts "Browsing #{artist.name}..."
|
41
|
+
browse = artist.browse(:no_albums)
|
42
|
+
browse.load unless browse.loaded?
|
43
|
+
browse.top_hits.first(@load_factor).each do |rec|
|
44
|
+
@user.recommendations << parse_track(rec)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_recommendations_from_top_track_albums!
|
50
|
+
@loaded_toplists[:top_track_albums].each do |album|
|
51
|
+
puts "Browsing #{album.name}..."
|
52
|
+
browse = album.browse
|
53
|
+
browse.load unless browse.loaded?
|
54
|
+
browse.tracks.first(@load_factor).each do |rec|
|
55
|
+
@user.recommendations << parse_track(rec)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_recommendations_from_already_heard!
|
61
|
+
@loaded_toplists[:top_tracks].each do |track|
|
62
|
+
@user.recommendations << parse_track(track)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def load_recommendations_from_disliked!
|
67
|
+
@loaded_toplists[:disliked].each do |artist|
|
68
|
+
puts "Browsing #{artist.name}..."
|
69
|
+
browse = artist.browse(:no_albums)
|
70
|
+
browse.load unless browse.loaded?
|
71
|
+
browse.top_hits.first(@load_factor).each do |rec|
|
72
|
+
@user.recommendations << parse_track(rec)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_track(track)
|
78
|
+
album = track.album.load
|
79
|
+
artist = track.artist.load
|
80
|
+
user_track = Track.new
|
81
|
+
user_track.uri = track.to_link.to_str
|
82
|
+
user_track.name = track.name
|
83
|
+
user_track.artist = artist.name
|
84
|
+
user_track.album = album.name
|
85
|
+
user_track.popularity = track.popularity
|
86
|
+
user_track.year = album.release_year
|
87
|
+
user_track
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module MonkeyMusic
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
def initialize(arguments)
|
7
|
+
@arguments = arguments
|
8
|
+
@opt_parser = OptionParser.new
|
9
|
+
@players = []
|
10
|
+
@delay = 1
|
11
|
+
init_parser(@opt_parser)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
@opt_parser.parse!
|
16
|
+
if generate_user?
|
17
|
+
# Create user
|
18
|
+
user = User.new
|
19
|
+
# Connect to libspotify
|
20
|
+
Hallon.load_timeout = 0
|
21
|
+
session = Hallon::Session.initialize(IO.read(@spotify_appkey_file))
|
22
|
+
session.login!(@spotify_account, @spotify_password)
|
23
|
+
# Load toplists
|
24
|
+
puts "Loading toplists from #{@toplist_file}..."
|
25
|
+
toplist_loader = ToplistLoader.new(@toplist_file)
|
26
|
+
toplist_loader.load_for_user!(user)
|
27
|
+
# Generate recommendations
|
28
|
+
puts "Loading recommendations..."
|
29
|
+
loaded_toplists = toplist_loader.loaded_toplists
|
30
|
+
recommendation_loader = RecommendationLoader.new(loaded_toplists)
|
31
|
+
recommendation_loader.load_for_user!(user)
|
32
|
+
# Disconnect from libspotify
|
33
|
+
session.logout!
|
34
|
+
# Evaluate recommendations
|
35
|
+
puts "Evaluating recommendations..."
|
36
|
+
score_system = ScoreSystem.new
|
37
|
+
score_system.evaluate_user_recommendations!(user)
|
38
|
+
# Dump and print the user
|
39
|
+
File.open(@out_file, 'w') do |f|
|
40
|
+
f.write(user.dump)
|
41
|
+
end
|
42
|
+
puts "====="
|
43
|
+
puts "DONE!"
|
44
|
+
puts "====="
|
45
|
+
puts "Loaded tracks:"
|
46
|
+
user.recommendations.group_by(&:multiplier).sort.each do |k,v|
|
47
|
+
puts "#Multiplier #{k}:\t#{v.length}"
|
48
|
+
end
|
49
|
+
exit
|
50
|
+
elsif not game_is_playable?
|
51
|
+
puts @opt_parser
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
# Load user
|
55
|
+
user = User.new
|
56
|
+
user.load_from_file(@user_file)
|
57
|
+
# Load level
|
58
|
+
level = Level.new(@players, user)
|
59
|
+
level.load_from_file(@level_file)
|
60
|
+
## Initialize UI
|
61
|
+
if browser_ui?
|
62
|
+
print "Using browser UI. Press the enter key to start game. "
|
63
|
+
gets
|
64
|
+
puts "Starting game..."
|
65
|
+
ui = BrowserUI.new(@delay)
|
66
|
+
else
|
67
|
+
ui = ConsoleUI.new(@delay)
|
68
|
+
end
|
69
|
+
## Start game
|
70
|
+
@game = Game.new(level, @players, ui)
|
71
|
+
@game.start
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def generate_user?
|
77
|
+
(defined? @toplist_file) &&
|
78
|
+
(defined? @out_file) &&
|
79
|
+
(defined? @spotify_appkey_file) &&
|
80
|
+
(defined? @spotify_account) &&
|
81
|
+
(defined? @spotify_password)
|
82
|
+
end
|
83
|
+
|
84
|
+
def game_is_playable?
|
85
|
+
(defined? @user_file) &&
|
86
|
+
(defined? @level_file) &&
|
87
|
+
(not @players.empty?)
|
88
|
+
end
|
89
|
+
|
90
|
+
def browser_ui?
|
91
|
+
@browser_ui == true
|
92
|
+
end
|
93
|
+
|
94
|
+
def init_parser(opts)
|
95
|
+
opts.banner = 'Usage: monkeymusic [options]'
|
96
|
+
|
97
|
+
opts.on('-l',
|
98
|
+
'--level LEVEL',
|
99
|
+
'The level to play.') do |file|
|
100
|
+
@level_file = File.join(Dir.getwd, file)
|
101
|
+
end
|
102
|
+
|
103
|
+
opts.on('-u',
|
104
|
+
'--user USER',
|
105
|
+
'The user the players will recommend music for.') do |user|
|
106
|
+
@user_file = File.join(Dir.getwd, user)
|
107
|
+
end
|
108
|
+
|
109
|
+
opts.on('-p',
|
110
|
+
'--player FILE',
|
111
|
+
'The path to a player program.') do |file|
|
112
|
+
player_file = File.join(Dir.getwd, file)
|
113
|
+
@players << Player.new(player_file)
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on('-n',
|
117
|
+
'--player-name NAME',
|
118
|
+
'Set the name of the last entered player.') do |name|
|
119
|
+
@players[-1].monkey.name = name unless @players.empty?
|
120
|
+
end
|
121
|
+
|
122
|
+
opts.on('-d', '--delay DELAY', OptionParser::DecimalNumeric,
|
123
|
+
'The delay (in seconds) between each round.') do |delay|
|
124
|
+
@delay = delay
|
125
|
+
end
|
126
|
+
|
127
|
+
opts.on('-g',
|
128
|
+
'--generate TOPLIST_FILE',
|
129
|
+
'Generate a user from a toplist file.') do |user|
|
130
|
+
@toplist_file = File.join(Dir.getwd, user)
|
131
|
+
end
|
132
|
+
|
133
|
+
opts.on('-o',
|
134
|
+
'--out OUT_FILE',
|
135
|
+
'The file to dump a generated user to.') do |file|
|
136
|
+
@out_file = File.join(Dir.getwd, file)
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on('-k',
|
140
|
+
'--app-key KEY',
|
141
|
+
'Path to libspotify application key.') do |key|
|
142
|
+
@spotify_appkey_file = File.join(Dir.getwd, key)
|
143
|
+
end
|
144
|
+
|
145
|
+
opts.on('-a',
|
146
|
+
'--account ACCOUNT',
|
147
|
+
'Username for a Spotify premium account.') do |account|
|
148
|
+
@spotify_account = account
|
149
|
+
end
|
150
|
+
|
151
|
+
opts.on('-w', '--password PASSWORD',
|
152
|
+
'Password for a Spotify premium account.') do |password|
|
153
|
+
@spotify_password = password
|
154
|
+
end
|
155
|
+
|
156
|
+
opts.on('-b', '--browser-ui',
|
157
|
+
'View the game through the browser instead of the console.') do |password|
|
158
|
+
@browser_ui = true
|
159
|
+
end
|
160
|
+
|
161
|
+
opts.on_tail('-h',
|
162
|
+
'--help',
|
163
|
+
'Show this message.') do
|
164
|
+
puts opts
|
165
|
+
exit
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|