-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.py
753 lines (640 loc) · 29.1 KB
/
game.py
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
863
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
#!/usr/bin/env python
# coding: utf-8
# # Text adventure game
#
# This Python notebook builds a simple text advenutre game inspired by the [Adventuron Classroom](https://adventuron.io/classroom/) design by Chris Ainsley of Adventuron Software Limited.
#
# The main components are:
# 1. __The parser__, which interprets the player's commands.
# 2. __The game__, which represents the world (a collection of __locations__ and __items__), and describes what the player sees.
# 3. __The data__, which you input to create your own unique game.
# ## The Game Class
# The game keeps track of the state of the world, and describes what the player sees as they move through different locations.
# In[1]:
import pyjokes
import neuralcoref
import spacy
class Game:
"""The Game class represents the world. Internally, we use a
graph of Location objects and Item objects, which can be at a
Location or in the player's inventory. Each locations has a set of
exits which are the directions that a player can move to get to an
adjacent location. The player can move from one location to another
location by typing a command like "Go North".
"""
def __init__(self, start_at):
# start_at is the location in the game where the player starts
self.curr_location = start_at
self.curr_location.has_been_visited = True
# inventory is the set of objects that the player has collected/
self.inventory = {}
# Print the special commands associated with items in the game (helpful
# for debugging and for novice players).
self.print_commands = True
def describe(self):
"""Describe the current game state by first describing the current
location, then listing any exits, and then describing any objects
in the current location."""
self.describe_current_location()
self.describe_exits()
self.describe_items()
def describe_current_location(self):
"""Describe the current location by printing its description field."""
# MARKER
print(self.curr_location.description)
def describe_exits(self):
"""List the directions that the player can take to exit from the current
location."""
exits = []
for exit in self.curr_location.connections.keys():
exits.append(exit.capitalize())
if len(exits) > 0:
print("Exits: ", end = '')
print(*exits, sep = ", ",)
def describe_items(self):
"""Describe what objects are in the current location."""
if len(self.curr_location.items) > 0:
print("You see: ")
for item_name in self.curr_location.items:
item = self.curr_location.items[item_name]
print(item.description)
if self.print_commands:
special_commands = item.get_commands()
for cmd in special_commands:
print('\t', cmd)
def add_to_inventory(self, item):
"""Add an item to the player's inventory."""
self.inventory[item.name] = item
def is_in_inventory(self,item):
return item.name in self.inventory
def get_items_in_scope(self):
"""Returns a list of items in the current location and in the inventory"""
items_in_scope = []
for item_name in self.curr_location.items:
items_in_scope.append(self.curr_location.items[item_name])
for item_name in self.inventory:
items_in_scope.append(self.inventory[item_name])
return items_in_scope
# ## Locations
#
# Locations Locations are the places in the game that a player can visit. They contain connects to other locations and items that the player can interact with.
# In[2]:
class Location:
"""Locations are the places in the game that a player can visit.
Internally they are represented nodes in a graph. Each location stores
a description of the location, any items in the location, its connections
to adjacent locations, and any blocks that prevent movement to an adjacent
location. The connections is a dictionary whose keys are directions and
whose values are the location that is the result of traveling in that
direction. The travel_descriptions also has directions as keys, and its
values are an optional short desciption of traveling to that location.
"""
def __init__(self, name, description, end_game=False):
# A short name for the location
self.name = name
# A description of the location
self.description = description
# True if entering this location should end the game
self.end_game = end_game
# Dictionary mapping from directions to other Location objects
self.connections = {}
# Dictionary mapping from directions to text description of the path there
self.travel_descriptions = {}
# Dictionary mapping from item name to Item objects present in this location
self.items = {}
# Dictionary mapping from direction to Block object in that direction
self.blocks = {}
# Flag that gets set to True once this location has been visited by player
self.has_been_visited = False
def add_connection(self, direction, connected_location, travel_description=""):
"""Add a connection from the current location to a connected location.
Direction is a string that the player can use to get to the connected
location. If the direction is a cardinal direction, then we also
automatically make a connection in the reverse direction."""
self.connections[direction] = connected_location
self.travel_descriptions[direction] = travel_description
if direction == 'north':
connected_location.connections["south"] = self
connected_location.travel_descriptions["south"] = ""
if direction == 'south':
connected_location.connections["north"] = self
connected_location.travel_descriptions["north"] = ""
if direction == 'east':
connected_location.connections["west"] = self
connected_location.travel_descriptions["west"] = ""
if direction == 'west':
connected_location.connections["east"] = self
connected_location.travel_descriptions["east"] = ""
if direction == 'up':
connected_location.connections["down"] = self
connected_location.travel_descriptions["down"] = ""
if direction == 'down':
connected_location.connections["up"] = self
connected_location.travel_descriptions["up"] = ""
if direction == 'in':
connected_location.connections["out"] = self
connected_location.travel_descriptions["out"] = ""
if direction == 'out':
connected_location.connections["in"] = self
connected_location.travel_descriptions["in"] = ""
def add_item(self, name, item):
"""Put an item in this location."""
self.items[name] = item
def remove_item(self, item):
"""Remove an item from this location (for instance, if the player picks it
up and puts it in their inventory)."""
self.items.pop(item.name)
def is_blocked(self, direction, game):
"""Check to if there is an obstacle in this direction."""
if not direction in self.blocks:
return False
(block_description, preconditions) = self.blocks[direction]
if check_preconditions(preconditions, game):
# All the preconditions have been met. You may pass.
return False
else:
# There are still obstalces to overcome or puzzles to solve.
return True
def get_block_description(self, direction):
"""Check to if there is an obstacle in this direction."""
if not direction in self.blocks:
return ""
else:
(block_description, preconditions) = self.blocks[direction]
return block_description
def add_block(self, blocked_direction, block_description, preconditions):
"""Create an obstacle that prevents a player from moving in the blocked
location until the preconditions are all met."""
self.blocks[blocked_direction] = (block_description, preconditions)
# ## Checking Preconditions
# In text adventure games it's common to block a player's progress by creating blocks that prevent them from moving to a location. For instance, a drawbridge might have a troll that you need to get rig of before you can cross into the castle, or a locked door might prevent you from entering a building until you have a key.
#
# This is a function that you can modify to include other preconditions.
# In[3]:
def check_preconditions(preconditions, game, print_failure_reasons=True):
"""Checks whether the player has met all of the specified preconditions"""
all_conditions_met = True
for check in preconditions:
if check == "inventory_contains":
item = preconditions[check]
if not game.is_in_inventory(item):
all_conditions_met = False
if print_failure_reasons:
print("You don't have the %s" % item.name)
if check == "inventory_contains_silent":
item = preconditions[check]
if not game.is_in_inventory(item):
all_conditions_met = False
if check == "in_location":
location = preconditions[check]
if not game.curr_location == location:
all_conditions_met = False
if print_failure_reasons:
print("You aren't in the correct location")
if check == "location_has_item":
item = preconditions[check]
if not item.name in game.curr_location.items:
all_conditions_met = False
if print_failure_reasons:
print("The %s isn't in this location" % item.name)
if check == "location_has_item_silent":
item = preconditions[check]
if not item.name in game.curr_location.items:
all_conditions_met = False
# todo - add other types of preconditions
return all_conditions_met
# ## Items
# Items are objects that a player can get, or scenery that a player can examine. We could also implement people as items.
# In[4]:
class Item:
"""Items are objects that a player can get, or scenery that a player can
examine."""
def __init__(self,
name,
description,
examine_text="",
take_text="",
start_at=None,
gettable=True,
end_game=False):
# The name of the object
self.name = name
# The default description of the object.
self.description = description
# The detailed description of the player examines the object.
self.examine_text = examine_text
# Text that displays when player takes an object.
self.take_text = take_text if take_text else ("You take the %s." % self.name)
# Indicates whether a player can get the object and put it in their inventory.
self.gettable = gettable
# True if entering this location should end the game.
self.end_game = end_game
# The location in the Game where the object starts.
if start_at:
start_at.add_item(name, self)
self.commands = {}
def get_commands(self):
"""Returns a list of special commands associated with this object"""
return self.commands.keys()
def add_action(self, command_text, function, arguments, preconditions={}):
"""Add a special action associated with this item"""
self.commands[command_text] = (function, arguments, preconditions)
def do_action(self, command_text, game):
"""Perform a special action associated with this item"""
end_game = False # Switches to True if this action ends the game.
if command_text in self.commands:
function, arguments, preconditions = self.commands[command_text]
if check_preconditions(preconditions, game):
end_game = function(game, arguments)
else:
print("Cannot perform the action %s" % command_text)
return end_game
# ## The Parser
# The parser is the module that handles the natural language understanding in the game. The players enter commands in text, and the parser interprets them and performs the actions that the player intends. This is the module with the most potential for improvement using modern natural language processing. The implementation that I have given below only uses simple keyword matching.
# In[5]:
class Parser:
"""The Parser is the class that handles the player's input. The player
writes commands, and the parser performs natural language understanding
in order to interpret what the player intended, and how that intent
is reflected in the simulated world.
"""
def __init__(self, game):
# A list of all of the commands that the player has issued.
self.command_history = []
# A pointer to the game.
self.game = game
def get_player_intent(self,command):
command = command.lower()
if "," in command:
# Let the player type in a comma separted sequence of commands
return "sequence"
elif self.get_direction(command):
# Check for the direction intent
return "direction"
elif command.lower() == "look" or command.lower() == "l":
# when the user issues a "look" command, re-describe what they see
return "redescribe"
elif "examine " in command or command.lower().startswith("x "):
return "examine"
elif "take " in command or "get " in command:
return "take"
elif "drop " in command:
return "drop"
elif "inventory" in command or command.lower() == "i":
return "inventory"
else:
for item in self.game.get_items_in_scope():
special_commands = item.get_commands()
for special_command in special_commands:
if command == special_command.lower():
return "special"
def parse_command(self, command):
# add this command to the history
self.command_history.append(command)
# By default, none of the intents end the game. The following are ways this
# flag can be changed to True.
# * Going to a certain place.
# * Entering a certain special command
# * Picking up a certain object.
end_game = False
# Intents are functions that can be executed
intent = self.get_player_intent(command)
if intent == "direction":
end_game = self.go_in_direction(command)
elif intent == "redescribe":
self.game.describe()
elif intent == "examine":
self.examine(command)
elif intent == "take":
end_game = self.take(command)
elif intent == "drop":
self.drop(command)
elif intent == "inventory":
self.check_inventory(command)
elif intent == "special":
end_game = self.run_special_command(command)
elif intent == "sequence":
end_game = self.execute_sequence(command)
else:
print("I'm not sure what you want to do.")
return end_game
### Intent Functions ###
def go_in_direction(self, command):
""" The user wants to in some direction """
direction = self.get_direction(command)
if direction:
if direction in self.game.curr_location.connections:
if self.game.curr_location.is_blocked(direction, self.game):
# check to see whether that direction is blocked.
print(self.game.curr_location.get_block_description(direction))
else:
# if it's not blocked, then move there
self.game.curr_location = self.game.curr_location.connections[direction]
# If moving to this location ends the game, only describe the location
# and not the available items or actions.
if self.game.curr_location.end_game:
self.game.describe_current_location()
else:
self.game.describe()
else:
print("You can't go %s from here." % direction.capitalize())
return self.game.curr_location.end_game
def check_inventory(self,command):
""" The player wants to check their inventory"""
if len(self.game.inventory) == 0:
print("You don't have anything.")
else:
descriptions = []
for item_name in self.game.inventory:
item = self.game.inventory[item_name]
descriptions.append(item.description)
print("You have: ", end = '')
print(*descriptions, sep = ", ",)
def examine(self, command):
""" The player wants to examine something """
command = command.lower()
matched_item = False
# check whether any of the items at this location match the command
for item_name in self.game.curr_location.items:
if item_name in command:
item = self.game.curr_location.items[item_name]
if item.examine_text:
print(item.examine_text)
matched_item = True
break
# check whether any of the items in the inventory match the command
for item_name in self.game.inventory:
if item_name in command:
item = self.game.inventory[item_name]
if item.examine_text:
print(item.examine_text)
matched_item = True
# fail
if not matched_item:
print("You don't see anything special.")
def take(self, command):
""" The player wants to put something in their inventory """
command = command.lower()
matched_item = False
# This gets set to True if posession of this object ends the game.
end_game = False
# check whether any of the items at this location match the command
for item_name in self.game.curr_location.items:
if item_name in command:
item = self.game.curr_location.items[item_name]
if item.gettable:
self.game.add_to_inventory(item)
self.game.curr_location.remove_item(item)
print(item.take_text)
end_game = item.end_game
else:
print("You cannot take the %s." % item_name)
matched_item = True
break
# check whether any of the items in the inventory match the command
if not matched_item:
for item_name in self.game.inventory:
if item_name in command:
print("You already have the %s." % item_name)
matched_item = True
# fail
if not matched_item:
print("You can't find it.")
return end_game
def drop(self, command):
""" The player wants to remove something from their inventory """
command = command.lower()
matched_item = False
# check whether any of the items in the inventory match the command
if not matched_item:
for item_name in self.game.inventory:
if item_name in command:
matched_item = True
item = self.game.inventory[item_name]
self.game.curr_location.add_item(item_name, item)
self.game.inventory.pop(item_name)
print("You drop the %s." % item_name)
break
# fail
if not matched_item:
print("You don't have that.")
def run_special_command(self, command):
"""Run a special command associated with one of the items in this location
or in the player's inventory"""
for item in self.game.get_items_in_scope():
special_commands = item.get_commands()
for special_command in special_commands:
if command == special_command.lower():
return item.do_action(special_command, self.game)
def execute_sequence(self, command):
for cmd in command.split(","):
cmd = cmd.strip()
self.parse_command(cmd)
def get_direction(self, command):
command = command.lower()
if command == "n" or "north" in command:
return "north"
if command == "s" or "south" in command:
return "south"
if command == "e" or "east" in command:
return "east"
if command == "w" or "west" in command:
return "west"
if command == "up":
return "up"
if command == "down":
return "down"
if command.startswith("go out"):
return "out"
if command.startswith("go in"):
return "in"
for exit in self.game.curr_location.connections.keys():
if command == exit.lower() or command == "go " exit.lower():
return exit
return None
# ## Special functions
# Many times we want to add special behavior to items in the game. For instance, we might want to be able to _pick a rose_ from a _rosebush_, or the _eat_ a _fish_. In this implementation we do this in a pretty generic way by allowing the game developer to call ```Item.add_action(cmd,function,argment,preconditions)``` where ```function``` is any Python function. Some example of functions are defined below.
#
# These functions should return True if the game is ended by the action, False otherwise.
# In[6]:
def add_item_to_inventory(game, *args):
""" Add a newly created Item and add it to your inventory."""
(item, action_description, already_done_description) = args[0]
if(not game.is_in_inventory(item)):
print(action_description)
game.add_to_inventory(item)
else:
print(already_done_description)
return False
def describe_something(game, *args):
"""Describe some aspect of the Item"""
(description) = args[0]
print(description)
return False
def destroy_item(game, *args):
"""Removes an Item from the game by setting its location is set to None."""
(item, action_description) = args[0]
if game.is_in_inventory(item):
game.inventory.pop(item.name)
print(action_description)
elif item.name in game.curr_location.items:
game.curr_location.remove_item(item)
print(action_description)
else:
pass
# print(already_done_description)
return False
def destroy_item_location(game, *args):
item, description, location = args[0]
location.remove_item(item)
return False
def create_item(game, *args):
item, description = args[0]
game.curr_location.add_item(item.name, item)
print(description)
def create_item_location(game, *args):
item, description, location = args[0]
location.add_item(item.name, item)
print(description)
def end_game(game, *args):
"""Ends the game."""
end_message = args[0]
print(end_message)
return True
def perform_multiple_actions(game, *args):
actions = args[0]
for func, arg in actions:
func(game, arg)
return False
# ## Game Data
#
# Here's where you can define the locations and items in your game. To get you started, I defined a super-simple fishing game, which contains the first 3 locations of __Action Castle__ by Jared A. Sorensen, which is part of the awesome book [Parsley](http://www.memento-mori.com/parsely-products/parsely-pdf).
#
# You can play through the whole game with the following commands:
# 1. take pole
# 2. go out
# 3. south
# 4. catch fish with pole
# 5. eat fish
# In[7]:
basement = Location("Towne Basement", "You are standing in a creepy basement. There is an eternal loud humming sound.")
towne327 = Location("Towne 327", "You are standing in a classroom. There is an awkward silence as people try to understand what 'AI' actually means. There's an ethernet outlet here, but who ever brings ethernet cables?")
broken_hub = Item("wifi hub", "a broken wifi hub", "the wifi hub isn't connecting devices to the internet", start_at=None, gettable=False)
ethernet_cable = Item("ethernet cable", "a short ethernet cable", "the ethernet cable conveniently has USB-C", start_at=basement)
laptop = Item("laptop", "your laptop", "your laptop already has Github and your IDE open")
laptop.add_action("finish homework", end_game, ("Daphne calls CETS and they take long enough for class to get delayed. You finish your homework with your wired internet connection. You win! Start earlier next time!"), preconditions={"in_location": towne327, "inventory_contains": ethernet_cable, "location_has_item": broken_hub})
def build_game():
# Locations
hallway = Location("Towne Hallway", "Your assignment is due in 15 minutes. You are standing in a hallway. Dozens of undergraduates complain loudly about CIS 160. There is also a staircase at the end of the hall.")
towne100 = Location("Towne 100", "You are standing in a lecture hall. It recently got renovated, but it's still the colour of overripe banana and smells like food truck.")
stairs = Location("Towne Staircase", "You are standing in a staircase. It looks vaguely decrepit, but you can't tell how old.")
upper_hallway= Location("Towne Upstairs Hallway", "You are standing in a hallway. It's weirdly quiet and all the rooms are locked except for one.")
hallway.add_connection("in", towne100)
hallway.add_connection("north", stairs)
stairs.add_connection("up", upper_hallway)
stairs.add_connection("south", hallway)
stairs.add_connection("down", basement)
basement.add_connection("up", stairs)
upper_hallway.add_connection("in", towne327)
# Items
router = Item("router", "a big internet router", "the router is plugged into the wall", start_at=basement, gettable=False)
unplugged_router = Item("unplugged Router", "an unplugged internet router", "the router looks lifeless", start_at=None, gettable=False)
hub = Item("wifi hub", "a wifi hub", "the wifi hub is relaying signal in the room", start_at=towne327, gettable=False)
fire_alarm = Item("fire alarm", "a red fire alarm switch", "the switch looks easy to pull", start_at=towne100, gettable=False)
ccb = Item("chris", "chris", "a professor is standing here, wearing a floral shirt", start_at=towne327, gettable=False)
daphne = Item("daphne", "daphne", "a PhD instructor is standing here, checking course material and reveling in her fast internet connection", start_at=towne327, gettable=False)
ccb.add_action("talk to chris", describe_something, ("He says: " pyjokes.get_joke()))
daphne.add_action("talk to daphne", describe_something, ("She says: " pyjokes.get_joke()))
router.add_action("unplug the router", perform_multiple_actions, ([
(destroy_item, (router, "You unplug the router from the wall.")),
(create_item, (unplugged_router, "The router is unplugged. Your phone starts bugging you about connecting to the internet.")),
(destroy_item_location, (hub, "You wonder what's happening in your classroom.", towne327)),
(create_item_location, (broken_hub, "Do you have enough time to get your attendance grade AND finish the assignment?", towne327))
]), preconditions={"in_location": basement, "location_has_item": router})
fire_alarm.add_action("pull the fire alarm", end_game, ("You pull the fire alarm and the police arrive, diverting units from a serious situation. You die from grief. Game over."))
return Game(hallway)
# # Play the game
# This small snippet of code is what you need to run the game. Behold! The magestic prompt!
# In[ ]:
def game_loop():
nlp = spacy.load("en")
neuralcoref.add_to_pipe(nlp)
game = build_game()
parser = Parser(game)
game.describe()
game.add_to_inventory(laptop)
command = ""
while not (command.lower() == "exit" or command.lower == "q"):
command = input(">")
corpus = nlp(command)
resolved = corpus._.coref_resolved
sentences = resolved.split("and" if "and" in resolved else ".")
for sentence in sentences:
# print("parsed", sentence)
end_game = parser.parse_command(sentence.strip())
if end_game:
return
game_loop()
print('THE GAME HAS ENDED.')
# # Visualize your game
# The code below allows you to create a directed graph that shows the locations in your game and how they are connected. You can also save a PDF of your graph to your Google Drive with the `save_to_drive` method. The output file will be called `game-visualization.pdf`.
# In[ ]:
#!pip install graphviz
# from graphviz import Digraph
# from IPython.display import Image
# import queue
def DFS(game, graph):
"""Do a depth-first-search traversal of the locations in the game
starting at the start location, and create a GraphViz graph
to vizualize the connections between the locations, and the items
that are located at each location."""
start_location = game.curr_location
frontier = queue.Queue()
frontier.put(start_location)
visited = {}
visited[start_location.name] = True
while not frontier.empty():
current_location = frontier.get()
game.curr_location = current_location
name = current_location.name
description = current_location.description
items = current_location.items
items_html = describe_items(current_location)
html = "<<b>%s</b><br />%s<br />%s>" % (name, description, items_html)
# Create a new node in the graph for this location
graph.node(name, label=html)
connections = current_location.connections
for direction in connections.keys():
next_location = connections[direction]
if not current_location.is_blocked(direction, game):
# Create an edge between the current location and its successor
graph.edge(name, next_location.name, label=direction.capitalize())
else:
# Create a dotted edge for connected locations that are blocked
block_description = "%s\n%s" % (direction.capitalize(), current_location.get_block_description(direction))
graph.edge(name, next_location.name, label=block_description, style="dotted")
if not next_location.name in visited:
visited[next_location.name] = True
frontier.put(next_location)
def describe_items(location, print_commands=True):
"""Describe what objects are in the current location."""
items_html = ""
if len(location.items.keys()) > 0:
items_html = "You see: "
for item_name in location.items:
item = location.items[item_name]
items_html = item.description
if print_commands:
special_commands = item.get_commands()
for cmd in special_commands:
items_html = "<br/><i>%s</i>" % cmd
return items_html
def save_to_drive(graph):
from google.colab import drive
drive.mount('/content/drive/')
graph.render('/content/drive/My Drive/game-visualization', view=True)
"""graph = Digraph(node_attr={'color': 'lightblue2', 'style': 'filled'})
game = build_game()
DFS(game, graph)
#save_to_drive(graph)
graph"""