This repository has been archived by the owner on Sep 29, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
quipbot.rb
executable file
·170 lines (150 loc) · 4.46 KB
/
quipbot.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/bin/env ruby
require 'optparse'
require_relative 'lib/markov.rb'
require_relative 'lib/quiplash.rb'
require_relative 'lib/quiplash2.rb'
require_relative 'lib/teeko.rb'
require_relative 'lib/drawful2.rb'
GAMES = [:quiplash, :quiplash2, :teeko, :drawful2]
# Defaults
options = {
game: GAMES[0],
model: './model.mp.gz',
pic_dir: File.join(ENV['HOME'], 'Pictures'),
e9_icon: false,
instances: 1,
# room_code: must be set by an argument
}
# Parse command line arguments
optparse = OptionParser.new do |parser|
parser.banner = "Usage: quibot.rb --code CODE [options]"
# Mandatory room code, can't join a game without it
parser.on('-cCODE', '--code=CODE',
'The Jackbox room code used to join the game') do |code|
if code.size != 4
raise OptionParser::InvalidOption.new('Room code must be 4 letters')
end
options[:room_code] = code.upcase
end
parser.on('-gGAME',
'--game=GAME',
GAMES,
'Which game the bot should attempt to play.',
"Default: #{options[:game]}",
"Valid choices: #{GAMES.join(' ')}") do |game|
options[:game] = game.to_sym
end
parser.on('-fMODEL',
'--file=MODEL',
'The model file to use for text generation') do |model|
options[:model] = model
end
parser.on('-nINSTANCES',
'--number=INSTANCES',
Integer,
'How many instances of the bot to launch.',
'Must be between 1 and 8, inclusive.') do |instances|
if instances < 1 || instances > 8
raise OptionParser::InvalidOption.new(
'Number of instances must be between 1 and 8.')
end
options[:instances] = instances
end
parser.on('-pPICTURE_DIR',
'--picture-dir=PICTURE_DIR',
String,
'Picture directory to use for Tee K.O. shirts and Drawful icons',
'Default is ~/Pictures/.') do |pic_dir|
unless File.directory? pic_dir
raise OptionParser::InvalidOption.new(
'Specified picture directory does not appear to be a directory.')
end
options[:pic_dir] = pic_dir
end
parser.on('-e',
'--e926-icon',
'Try to load an image from E926 for the Drawful icon') do |use_e9|
options[:e9_icon] = use_e9
end
parser.on('-h', '--help', 'Prints this help') do
puts parser
exit
end
end
begin
optparse.parse!
if options[:room_code].nil?
raise OptionParser::MissingArgument.new('room_code')
end
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
# Print the error and usage info, then exit with nonzero status
puts $!.to_s
puts
puts optparse
abort
end
# Load some bot objects
bot_threads = Array.new(options[:instances])
bot_threads.each_index do |i|
# Check for an existing game ID
if File.exists?("#{i}.game_uuid")
puts 'Found previous game info, loading saved details'
game_id = File.read("#{i}.game_uuid")
end
if options[:game] == :quiplash
puts 'Starting game of Quiplash'
bot = Quiplash.new(options[:room_code], "Quipbot#{i}", game_id)
elsif options[:game] == :quiplash2
puts 'Starting game of Quiplash 2'
bot = Quiplash2.new(options[:room_code], "Quipbot#{i}", game_id)
elsif options[:game] == :teeko
puts 'Starting game of Tee K.O.'
bot = TeeKO.new(
options[:room_code],
"Quipbot#{i}",
game_id,
options[:pic_dir]
)
elsif options[:game] == :drawful2
puts 'Starting game of Drawful 2'
bot = Drawful2.new(
options[:room_code],
"Quipbot#{i}",
game_id,
options[:pic_dir],
options[:e9_icon],
)
else
puts 'Error: requested game has no implementation yet.'
abort
end
game_id = bot.login
uuid_file = File.new("#{i}.game_uuid", 'w')
uuid_file.write(game_id)
uuid_file.close
# Load the markov model
puts 'Loading Markov Chain'
chain = MarkovChain.new options[:model]
puts 'Markov chain loaded'
if options[:game] == :teeko
bot_threads[i] = bot.start_playing do |prompt|
chain.gen_random_text(word_limit: 5)
end
elsif options[:game] == :drawful2
bot_threads[i] = bot.start_playing do |prompt|
chain.gen_random_text(word_limit: 3)
end
else
bot_threads[i] = bot.start_playing do |prompt|
begin
response = chain.gen_seeded_text(prompt, word_limit: 7, include_seed: false)
rescue ModelMatchError
response = chain.gen_random_text(word_limit: 7)
end
response
end
end
end
bot_threads.each do |thread|
thread.join
end