-
Notifications
You must be signed in to change notification settings - Fork 0
/
view.py
144 lines (117 loc) · 4.87 KB
/
view.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
# Assignment 2 - Puzzle Platform
#
# CSC148 Summer 2017, University of Toronto
# ---------------------------------------------
""" Assignment 2 - View classes
This module contains three classes responsible for displaying information
to the user and reacting to user actions.
Note that these views behave independently of which puzzle is being played,
and so the allowable user inputs (e.g., ':SOLVE') cannot depend on the
particular puzzle, either.
You should *not* change this file.
"""
# Extra imports to run a web-based view
import http.server
import socketserver
from urllib.parse import parse_qs, urlparse
class View:
"""Abstract class representing the view of a puzzle game.
Responsible for displaying state to the user and interpreting user input.
"""
# === Private attributes ===
# @type _controller: Controller
# The associated controller that interprets actions sent by the view.
def __init__(self, controller):
"""Create a new view.
@type self: View
@type controller: Controller
@rtype: None
"""
self._controller = controller
def run(self):
"""Start the game.
This is the method which is called to begin interacting with the user.
@type self: View
@rtype: None
"""
raise NotImplementedError()
class TextView(View):
"""View implementation based on console interaction.
Uses 'print' and 'input' to display information and get actions.
"""
# === Private attributes ===
# @type _welcome: str
# A message to be printed to the user when the game begins.
# @type _goodbye: str
# A message to be printed to the user when the game ends.
def __init__(self, controller):
View.__init__(self, controller)
self._welcome = 'Welcome to the puzzle game!'
self._goodbye = 'Hope you had fun playing!'
def run(self):
print(self._welcome)
print(self._controller.state())
while True:
print('Enter a command:')
user_input = input('> ')
msg, should_quit = self._controller.act(user_input.strip())
print(msg)
if should_quit:
break
print(self._goodbye)
# ----------------------------------------------------------------------------
# Web view. You are *NOT* responsible for understanding this code.
# ----------------------------------------------------------------------------
class WebView(View):
"""Web implementation of a game view.
Here is how to run this view:
1. In the "if __name__ == '__main__'" block for controller.py,
call the constructor with a second argument 'web'.
2. Run the program.
3. Open a web browser, and type in 'localhost:8000' in the URL bar.
4. Enjoy!
You aren't responsible for understanding this code, but you might have
some fun looking into how to modify the file 'game.html' to make the
webpage look more attractive.
"""
def __init__(self, controller):
View.__init__(self, controller)
def run(self):
"""Start the game with a web view."""
thisview = self
class GameRequestHandler(http.server.BaseHTTPRequestHandler):
"""Implementation of basic HTTP request handler for game view.
This exists as an inner class because I wanted to reference self
in a method here, but had to pass in the class to TCPServer below.
"""
done = False
def do_GET(self):
"""Overridden method for handling GET requests."""
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
if 'actions' in self.path:
query_params = parse_qs(urlparse(self.path).query)
action = query_params.get('action', [''])[0]
val = self.handle_action(action).replace('\n', '<br>')
self.wfile.write(bytes(val, 'UTF-8'))
else:
with open('game.html') as f:
self.wfile.write(bytes(f.read(), 'UTF-8'))
def handle_action(self, action):
"""Helper which calls controller actions based on query param.
@type self: GameRequestHandler
@type action: str
@rtype: str
"""
print(GameRequestHandler.done)
if not GameRequestHandler.done:
msg, should_quit = thisview._controller.act(action.strip())
GameRequestHandler.done = should_quit
return msg
else:
return ''
httpd = socketserver.TCPServer(('', 8000), GameRequestHandler)
print('Server running!')
print('Open a web browser and go to "http://localhost:8000"')
httpd.serve_forever()