├── .gitignore ├── .ipynb_checkpoints └── testing_stuff-checkpoint.ipynb ├── InstanceKey.xlsx ├── LICENSE ├── README.md ├── T SNE.ipynb ├── action.py ├── agent.py ├── app.py ├── double_qnet.py ├── download.sh ├── hyperparameters.py ├── qnet.py ├── requirements.txt ├── static ├── Rakefile ├── common.css ├── common.js ├── images │ ├── background.js │ ├── background.png │ ├── background │ │ ├── background.svg │ │ ├── hills.png │ │ ├── sky.png │ │ └── trees.png │ ├── mute.png │ ├── sprites.js │ ├── sprites.png │ └── sprites │ │ ├── billboard01.png │ │ ├── billboard02.png │ │ ├── billboard03.png │ │ ├── billboard04.png │ │ ├── billboard05.png │ │ ├── billboard06.png │ │ ├── billboard07.png │ │ ├── billboard08.png │ │ ├── billboard09.png │ │ ├── boulder1.png │ │ ├── boulder2.png │ │ ├── boulder3.png │ │ ├── bush1.png │ │ ├── bush2.png │ │ ├── cactus.png │ │ ├── car01.png │ │ ├── car02.png │ │ ├── car03.png │ │ ├── car04.png │ │ ├── column.png │ │ ├── dead_tree1.png │ │ ├── dead_tree2.png │ │ ├── palm_tree.png │ │ ├── player_left.png │ │ ├── player_right.png │ │ ├── player_straight.png │ │ ├── player_uphill_left.png │ │ ├── player_uphill_right.png │ │ ├── player_uphill_straight.png │ │ ├── semi.png │ │ ├── stump.png │ │ ├── tree1.png │ │ ├── tree2.png │ │ └── truck.png ├── index.html ├── jquery-1.12.0.min.js ├── music │ ├── racer.mp3 │ └── racer.ogg ├── stats.js ├── v1.straight.html ├── v2.curves.html ├── v3.hills.html ├── v4.final.html └── worker.js ├── testing_stuff.ipynb ├── tf_test.py └── transition_table.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .env/* 3 | -------------------------------------------------------------------------------- /.ipynb_checkpoints/testing_stuff-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 19, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from transition_table import TransitionTable\n", 12 | "from action import Action\n", 13 | "import numpy as np" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 20, 19 | "metadata": { 20 | "collapsed": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "table = TransitionTable()" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 21, 30 | "metadata": { 31 | "collapsed": false 32 | }, 33 | "outputs": [ 34 | { 35 | "ename": "ValueError", 36 | "evalue": "too many values to unpack", 37 | "output_type": "error", 38 | "traceback": [ 39 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 40 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 41 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mimg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrand\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m84\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m84\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtable\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_transition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 42 | "\u001b[0;32m/Users/raphie/Dropbox/Code/cs231n-project/transition_table.py\u001b[0m in \u001b[0;36madd_transition\u001b[0;34m(self, *args)\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0madd_transition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0mt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransitions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 43 | "\u001b[0;32m/Users/raphie/Dropbox/Code/cs231n-project/transition_table.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, action, reward, image, terminal, was_start)\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mclass\u001b[0m \u001b[0mTransition\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mterminal\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maction\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreward\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwas_start\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0mpdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_trace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maction\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0maction\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 44 | "\u001b[0;31mValueError\u001b[0m: too many values to unpack" 45 | ] 46 | } 47 | ], 48 | "source": [ 49 | "img = np.random.rand(84, 84)\n", 50 | "table.add_transition(img, False, Action(2), 0.5, True)" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": { 57 | "collapsed": true 58 | }, 59 | "outputs": [], 60 | "source": [] 61 | } 62 | ], 63 | "metadata": { 64 | "kernelspec": { 65 | "display_name": "Python 2", 66 | "language": "python", 67 | "name": "python2" 68 | }, 69 | "language_info": { 70 | "codemirror_mode": { 71 | "name": "ipython", 72 | "version": 2 73 | }, 74 | "file_extension": ".py", 75 | "mimetype": "text/x-python", 76 | "name": "python", 77 | "nbconvert_exporter": "python", 78 | "pygments_lexer": "ipython2", 79 | "version": "2.7.10" 80 | } 81 | }, 82 | "nbformat": 4, 83 | "nbformat_minor": 0 84 | } 85 | -------------------------------------------------------------------------------- /InstanceKey.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/InstanceKey.xlsx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, 2013, 2014, 2015, 2016 Jake Gordon and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | =============================================================================== 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ~~~ Under Construction ~~~ 2 | 3 | Huge thanks to Jake Gordon for the game! (https://github.com/jakesgordon/javascript-racer) 4 | -------------------------------------------------------------------------------- /action.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import hyperparameters as hp 3 | 4 | class ActionMeta(type): 5 | def __init__(cls, name, bases, d): 6 | type.__init__(cls, name, bases, d) 7 | cls.action_to_num = dict() 8 | cls.num_to_action = dict() 9 | options = [True, False] 10 | counter = 0 11 | for left in options: 12 | for right in options: 13 | for faster in options: 14 | for slower in options: 15 | if left and right: 16 | continue 17 | # if faster and slower: 18 | if slower: 19 | continue 20 | if not faster: #and not left and not right: 21 | continue 22 | a = (left, right, faster, slower) 23 | cls.action_to_num[a] = counter 24 | cls.num_to_action[counter] = a 25 | counter += 1 26 | cls.num_actions = counter 27 | 28 | class Action(object): 29 | __metaclass__ = ActionMeta 30 | 31 | def __init__(self, num=None, left=False, right=False, faster=False, slower=False): 32 | if num is not None: 33 | if num > hp.TOTAL_ACTIONS-1 or num < 0: 34 | raise ValueError("Invalid num, must be 0-5") 35 | self.num = num 36 | else: 37 | if left and right: 38 | raise ValueError("Invalid action, cannot press both left and right") 39 | if faster and slower: 40 | raise ValueError("Invalid action, cannot press both faster and slower") 41 | self.num = self.action_to_num[(left, right, faster, slower)] 42 | 43 | @classmethod 44 | def random_action(self): 45 | return Action(np.random.randint(0, self.num_actions)) 46 | 47 | def to_onehot(self): 48 | a = np.zeros(self.num_actions) 49 | a[self.num] = 1 50 | return a 51 | 52 | def to_dict(self): 53 | left, right, faster, slower = self.num_to_action[self.num] 54 | return { 55 | "keyLeft": left, 56 | "keyRight": right, 57 | "keyFaster": faster, 58 | "keySlower": slower 59 | } -------------------------------------------------------------------------------- /agent.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from action import Action 3 | import hyperparameters as hp 4 | import tensorflow as tf 5 | from double_qnet import update_target, minimize_loss, loss, best_action, s, sp, actions, rewards, terminals, all_vars, avg_q_val 6 | from transition_table import TransitionTable 7 | import time 8 | import pickle 9 | import sys 10 | from sys import platform as _platform 11 | 12 | class Agent(object): 13 | def __init__(self): 14 | self.frame_count = -1 15 | self.sess = tf.Session() 16 | self.transitions = TransitionTable() 17 | self.tfSaver = tf.train.Saver() 18 | self.timer = dict() 19 | self.timer[-1] = time.time() 20 | self.test_mode = False 21 | 22 | if len(sys.argv) > 2: 23 | if sys.argv[2] == "--run": 24 | path = sys.argv[1] 25 | self.tfSaver.restore(self.sess, path) 26 | print "RESTORED MODEL FROM PATH: %s" % path 27 | self.test_mode = True 28 | elif sys.argv[2] == "--train": 29 | path = sys.argv[1] 30 | f = open(path, 'r') 31 | to_restore = pickle.load(f) 32 | f.close() 33 | self.frame_count, self.transitions = to_restore['frame_count'], to_restore['transitions'] 34 | print "RESTORED TRANSITIONS FROM PATH %s to FRAME COUNT %d" % (path, self.frame_count) 35 | self.sess.run(tf.initialize_all_variables()) 36 | elif sys.argv[2] == '--moreframes': 37 | path = sys.argv[1] 38 | self.tfSaver.restore(self.sess, path) 39 | print "RESTORED MODEL FROM PATH: %s" % path 40 | self.sess.run(tf.initialize_all_variables()) 41 | else: 42 | path = sys.argv[1] 43 | self.tfSaver.restore(self.sess, path) 44 | print "RESTORED MODEL FROM PATH: %s" % path 45 | f = open(sys.argv[2], 'r') 46 | to_restore = pickle.load(f) 47 | f.close() 48 | self.frame_count, self.transitions = to_restore['frame_count'], to_restore['transitions'] 49 | print "RESTORED TRANSITIONS FROM PATH %s to FRAME COUNT %d" % (path, self.frame_count) 50 | else: 51 | self.sess.run(tf.initialize_all_variables()) 52 | 53 | def in_lane(self, pos): 54 | pos = abs(pos) 55 | return pos <= 0.2 or (pos >= 0.5 and pos <= 0.8) 56 | 57 | def frame_reward(self, frame): 58 | # (modified) RAPHIE REWARD FUNC 59 | 60 | if hp.REWARD_FUNC == 'raphie': 61 | if frame['collision']: 62 | return -1.0 63 | elif abs(frame['position']) > 0.8: 64 | return -0.8 65 | elif float(frame['speed']) == 0: 66 | return -1.0 67 | else: 68 | multiplier = 1.0 if self.in_lane(frame['position']) else 0.8 69 | return multiplier * (float(frame['speed']) / float(frame['max_speed'])) 70 | 71 | elif hp.REWARD_FUNC == 'rishi': 72 | if frame['collision'] or abs(frame['position']) > 0.8: 73 | return -5.0 74 | elif frame['speed'] == 0: 75 | return -10.0 76 | else: 77 | return min(10, .2 + (5 * float(frame['speed']) / float(frame['max_speed']))) 78 | 79 | def reward(self, telemetry): 80 | return sum([self.frame_reward(frame) for frame in telemetry]) / float(len(telemetry)) 81 | 82 | def save_all(self): 83 | self.save_model() 84 | print "Model saved at frame %d" % self.frame_count 85 | self.save_transitions() 86 | print "Transitions saved at frame %d" % self.frame_count 87 | 88 | def save_model(self): 89 | path = "" 90 | if _platform == "linux" or _platform == "linux2": 91 | path = "/data/q-net" 92 | elif _platform == "darwin": 93 | path = "./data/q-net" 94 | 95 | path = self.tfSaver.save(self.sess, path, self.frame_count) 96 | print "SAVED MODEL TO PATH: %s" % path 97 | 98 | def save_transitions(self): 99 | path = "" 100 | if _platform == "linux" or _platform == "linux2": 101 | path = "/data/transitions.pickle" 102 | elif _platform == "darwin": 103 | path = "./data/transitions.pickle" 104 | 105 | f = open(path, 'w+') 106 | to_dump = {'frame_count': self.frame_count, 'transitions': self.transitions} 107 | pickle.dump(to_dump, f) 108 | f.close() 109 | 110 | def save_initial(self): 111 | path = "" 112 | if _platform == "linux" or _platform == "linux2": 113 | path = "/data/transitions50k.pickle" 114 | elif _platform == "darwin": 115 | path = "./data/transitions50k.pickle" 116 | 117 | f = open(path, 'w+') 118 | to_dump = {'frame_count': self.frame_count, 'transitions': self.transitions} 119 | pickle.dump(to_dump, f) 120 | f.close() 121 | 122 | def epsilon(self): 123 | return ((hp.FINAL_EXPLORATION - hp.INITIAL_EXPLORATION) / hp.FINAL_EXPLORATION_FRAME) * self.frame_count + hp.INITIAL_EXPLORATION 124 | 125 | def step(self, image, reward, terminal, was_start, action, telemetry): 126 | t = time.time() 127 | print "Roundtrip from browser took %.2f ms" % ((t - self.timer[-1]) * 1000) 128 | 129 | self.frame_count += 1 130 | 131 | self.transitions.add_transition(image, terminal, action, reward, was_start, telemetry) 132 | 133 | if self.test_mode: 134 | if self.frame_count < hp.TEST_RANDOMNESS: 135 | return Action.random_action() 136 | img = self.transitions.get_recent() 137 | print "Getting recent transitions took %.2f ms" % ((time.time() - t) * 1000) 138 | t = time.time() 139 | best = Action(self.sess.run(best_action, feed_dict={s: img})[0]) 140 | print "Forward pass took %.2f ms" % ((time.time() - t) * 1000) 141 | self.timer[-1] = time.time() 142 | return best 143 | 144 | if self.frame_count == hp.REPLAY_START_SIZE: 145 | self.save_initial() 146 | elif self.frame_count % hp.CHECKPOINT_FREQUENCY == 0 and self.frame_count < 250000: 147 | self.save_all() 148 | elif self.frame_count % hp.CHECKPOINT_FREQUENCY == 0: 149 | self.save_model() 150 | 151 | if self.frame_count < hp.REPLAY_START_SIZE: 152 | return Action.random_action() 153 | 154 | if self.frame_count % hp.UPDATE_FREQUENCY == 0: 155 | s_, t_, a_, r_, sp_ = self.transitions.get_minibatch(self.frame_count) 156 | minimize_loss_, loss_, avg_q_val_ = self.sess.run([minimize_loss, loss, avg_q_val], feed_dict={s: s_, sp: sp_, actions: a_, rewards: r_, terminals: t_}) 157 | print "Loss: %.2f" % loss_ 158 | print "Update took %.2f ms" % ((time.time() - t) * 1000) 159 | print "AverageQValue: %.2f" % avg_q_val_ 160 | 161 | if self.frame_count % (hp.UPDATE_FREQUENCY * hp.TARGET_UPDATE_FREQUENCY) == 0: 162 | self.sess.run(update_target) 163 | 164 | if np.random.rand() < self.epsilon(): 165 | return Action.random_action() 166 | t = time.time() 167 | img = self.transitions.get_recent() 168 | print "Getting recent transitions took %.2f ms" % ((time.time() - t) * 1000) 169 | t = time.time() 170 | best = Action(self.sess.run(best_action, feed_dict={s: img})[0]) 171 | print "Forward pass took %.2f ms" % ((time.time() - t) * 1000) 172 | self.timer[-1] = time.time() 173 | return best 174 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import tornado.ioloop 2 | import tornado.web 3 | from tornado import gen 4 | import os 5 | import base64 6 | import re 7 | import json 8 | import numpy as np 9 | import time 10 | import hyperparameters as hp 11 | from agent import Agent 12 | from action import Action 13 | from PIL import Image 14 | from io import BytesIO 15 | 16 | static_path = os.path.join(os.getcwd(), "static") 17 | agent = Agent() 18 | 19 | class MainHandler(tornado.web.RequestHandler): 20 | def get(self): 21 | self.redirect("/static/v2.curves.html") 22 | # self.redirect("/static/v4.final.html") 23 | 24 | class FrameHandler(tornado.web.RequestHandler): 25 | def post(self): 26 | data = json.loads(self.get_arguments("telemetry")[0]) 27 | ar = np.fromstring(base64.decodestring(self.request.body), dtype=np.uint8) 28 | image = ar.reshape(hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS) 29 | left, right, faster, slower = data["action"] 30 | terminal, action, all_data, was_start = ( 31 | data["terminal"], 32 | Action(left=left, right=right, faster=faster, slower=slower), 33 | data["all_data"], 34 | data["was_start"] 35 | ) 36 | 37 | print "FRAME NUM: %d" % (agent.frame_count + 1), terminal, action.to_dict(), was_start 38 | 39 | # all_data = {collision, position, speed, max_speed} x 4 40 | # abs(position) > 0.8 implies off road 41 | reward = agent.reward(all_data) 42 | print "Current reward = %.2f" % reward 43 | 44 | result_action = agent.step(image=image, reward=reward, terminal=terminal, was_start=was_start, action=action, telemetry=all_data) 45 | self.write(json.dumps(result_action.to_dict())) 46 | 47 | 48 | def make_app(): 49 | return tornado.web.Application([ 50 | (r"/", MainHandler), 51 | (r"/frame", FrameHandler), 52 | (r"/static/(.*)", tornado.web.StaticFileHandler, {"path": static_path}) 53 | ], debug=True) 54 | 55 | if __name__ == "__main__": 56 | app = make_app() 57 | if "SERVER_PORT" in os.environ: 58 | port = int(os.environ["SERVER_PORT"]) 59 | else: 60 | port = 8000 61 | print "LISTENING ON PORT: %d" % port 62 | app.listen(port) 63 | tornado.ioloop.IOLoop.current().start() 64 | -------------------------------------------------------------------------------- /double_qnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import hyperparameters as hp 4 | from action import Action 5 | 6 | def weight_variable(shape, name): 7 | initial = tf.truncated_normal(shape, stddev=0.1) 8 | return tf.Variable(initial, name=name) 9 | 10 | def bias_variable(shape, name): 11 | initial = tf.constant(0.1, shape=shape) 12 | return tf.Variable(initial, name=name) 13 | 14 | def conv2d(x, W, s): 15 | return tf.nn.conv2d(x, W, strides=[1, s, s, 1], padding="VALID") 16 | 17 | def output_size(in_size, filter_size, stride): 18 | return (in_size - filter_size)/stride + 1 19 | 20 | conv1_out_size = output_size(hp.INPUT_SIZE, hp.CONV_1_SIZE, hp.CONV_1_STRIDE) 21 | conv2_out_size = output_size(conv1_out_size, hp.CONV_2_SIZE, hp.CONV_2_STRIDE) 22 | conv3_out_size = output_size(conv2_out_size, hp.CONV_3_SIZE, hp.CONV_3_STRIDE) 23 | conv3_out_len = hp.CONV_3_DEPTH * (conv3_out_size ** 2) 24 | 25 | with tf.name_scope("input"): 26 | s = tf.placeholder(tf.float32, shape=[ 27 | None, 28 | hp.INPUT_SIZE, 29 | hp.INPUT_SIZE, 30 | hp.NUM_CHANNELS 31 | ], name="s") 32 | 33 | sp = tf.placeholder(tf.float32, shape=[ 34 | None, 35 | hp.INPUT_SIZE, 36 | hp.INPUT_SIZE, 37 | hp.NUM_CHANNELS 38 | ], name="sp") 39 | 40 | # this corresponds to Q 41 | with tf.name_scope("regular_net"): 42 | r_W_conv1 = weight_variable([ 43 | hp.CONV_1_SIZE, 44 | hp.CONV_1_SIZE, 45 | hp.NUM_CHANNELS, 46 | hp.CONV_1_DEPTH 47 | ], name="r_W_conv1") 48 | r_b_conv1 = bias_variable([hp.CONV_1_DEPTH], name="r_b_conv1") 49 | 50 | r_W_conv2 = weight_variable([ 51 | hp.CONV_2_SIZE, 52 | hp.CONV_2_SIZE, 53 | hp.CONV_1_DEPTH, 54 | hp.CONV_2_DEPTH 55 | ], name="r_W_conv2") 56 | r_b_conv2 = bias_variable([hp.CONV_2_DEPTH], name="r_b_conv2") 57 | 58 | r_W_conv3 = weight_variable([ 59 | hp.CONV_3_SIZE, 60 | hp.CONV_3_SIZE, 61 | hp.CONV_2_DEPTH, 62 | hp.CONV_3_DEPTH 63 | ], name="r_W_conv3") 64 | r_b_conv3 = bias_variable([hp.CONV_3_DEPTH], name="r_b_conv3") 65 | 66 | r_W_fc1 = weight_variable([conv3_out_len, hp.FC_SIZE], name="r_W_fc1") 67 | r_b_fc1 = bias_variable([hp.FC_SIZE], name="r_b_fc1") 68 | 69 | r_W_out = weight_variable([hp.FC_SIZE, Action.num_actions], name="r_W_out") 70 | r_b_out = bias_variable([Action.num_actions], name="b_out") 71 | 72 | r_h_conv1 = tf.nn.relu(conv2d(s, r_W_conv1, hp.CONV_1_STRIDE) + r_b_conv1) 73 | r_h_conv2 = tf.nn.relu(conv2d(r_h_conv1, r_W_conv2, hp.CONV_2_STRIDE) + r_b_conv2) 74 | r_h_conv3 = tf.nn.relu(conv2d(r_h_conv2, r_W_conv3, hp.CONV_3_STRIDE) + r_b_conv3) 75 | r_resized = tf.reshape(r_h_conv3, [-1, conv3_out_len], name="r_resized") 76 | r_h_fc1 = tf.nn.relu(tf.matmul(r_resized, r_W_fc1) + r_b_fc1) 77 | 78 | # minibatch_size x # of actions 79 | # position (i,j) in r_actions is score for action j in minibatch item i 80 | r_actions = tf.matmul(r_h_fc1, r_W_out) + r_b_out 81 | best_action = tf.argmax(r_actions, 1) 82 | avg_q_val = tf.reduce_mean(r_actions) 83 | 84 | # this corresponds to Q_hat 85 | with tf.name_scope("target_params"): 86 | t_W_conv1 = tf.Variable(r_W_conv1.initialized_value(), trainable=False) 87 | t_W_conv2 = tf.Variable(r_W_conv2.initialized_value(), trainable=False) 88 | t_W_conv3 = tf.Variable(r_W_conv3.initialized_value(), trainable=False) 89 | t_W_fc1 = tf.Variable(r_W_fc1.initialized_value(), trainable=False) 90 | t_W_out = tf.Variable(r_W_out.initialized_value(), trainable=False) 91 | t_b_conv1 = tf.Variable(r_b_conv1.initialized_value(), trainable=False) 92 | t_b_conv2 = tf.Variable(r_b_conv2.initialized_value(), trainable=False) 93 | t_b_conv3 = tf.Variable(r_b_conv3.initialized_value(), trainable=False) 94 | t_b_fc1 = tf.Variable(r_b_fc1.initialized_value(), trainable=False) 95 | t_b_out = tf.Variable(r_b_out.initialized_value(), trainable=False) 96 | 97 | t_h_conv1 = tf.nn.relu(conv2d(sp, t_W_conv1, hp.CONV_1_STRIDE) + t_b_conv1) 98 | t_h_conv2 = tf.nn.relu(conv2d(t_h_conv1, t_W_conv2, hp.CONV_2_STRIDE) + t_b_conv2) 99 | t_h_conv3 = tf.nn.relu(conv2d(t_h_conv2, t_W_conv3, hp.CONV_3_STRIDE) + t_b_conv3) 100 | t_resized = tf.reshape(t_h_conv3, [-1, conv3_out_len], name="t_resized") 101 | t_h_fc1 = tf.nn.relu(tf.matmul(t_resized, t_W_fc1) + t_b_fc1) 102 | t_actions = tf.matmul(t_h_fc1, t_W_out) + t_b_out 103 | 104 | # if you call update_target, it copies Q to Q_hat 105 | with tf.name_scope("updaters"): 106 | regular = [ 107 | r_W_conv1, 108 | r_W_conv2, 109 | r_W_conv3, 110 | r_W_fc1, 111 | r_W_out, 112 | r_b_conv1, 113 | r_b_conv2, 114 | r_b_conv3, 115 | r_b_fc1, 116 | r_b_out, 117 | ] 118 | 119 | target = [ 120 | t_W_conv1, 121 | t_W_conv2, 122 | t_W_conv3, 123 | t_W_fc1, 124 | t_W_out, 125 | t_b_conv1, 126 | t_b_conv2, 127 | t_b_conv3, 128 | t_b_fc1, 129 | t_b_out, 130 | ] 131 | 132 | all_vars = regular + target 133 | 134 | 135 | target_update = [] 136 | 137 | for i in range(len(regular)): 138 | t, r = target[i], regular[i] 139 | # generate the graph and assign nodes from one to the other 140 | target_update.append(tf.assign(t, r)) 141 | 142 | # tf.group executes all the nodes which are passed to it 143 | update_target = tf.group(*target_update) 144 | 145 | with tf.name_scope("loss"): 146 | actions = tf.placeholder(tf.int32, hp.MINIBATCH_SIZE, name="actions") 147 | rewards = tf.placeholder(tf.float32, hp.MINIBATCH_SIZE, name="rewards") 148 | 149 | # array of zeros/ones 150 | terminals = tf.placeholder(tf.int32, hp.MINIBATCH_SIZE, name="terminals") 151 | gamma = tf.constant(hp.DISCOUNT_FACTOR, dtype=tf.float32) 152 | 153 | # ys is a vector of size minibatch_size which corresponds to y_j in algorithm 1 154 | 155 | # DOUBLE DQN IMPLEMENTATION 156 | selected_actions = tf.argmax(r_actions, 1) 157 | t_actions_flat = tf.reshape(t_actions, [-1]) 158 | t_actions_selected = tf.gather(t_actions_flat, Action.num_actions * np.arange(hp.MINIBATCH_SIZE) + selected_actions) 159 | 160 | ys = rewards + tf.to_float(1 - terminals) * gamma * t_actions_selected 161 | # ys = rewards + tf.to_float(1 - terminals) * gamma * tf.reduce_max(t_actions, reduction_indices=1) 162 | 163 | 164 | r_actions_flat = tf.reshape(r_actions, [-1]) 165 | 166 | # Q(s)[a] 167 | # vector of size minibatch, each element is the Q value of taking the action that we took 168 | gathered = tf.gather(r_actions_flat, (Action.num_actions * np.arange(hp.MINIBATCH_SIZE)) + actions) 169 | 170 | # unclipped version of loss 171 | # loss = tf.reduce_mean(tf.square(ys - gathered)) 172 | 173 | # Huber version of loss (Andrej's suggestion) 174 | unsquared = tf.abs(ys - gathered) 175 | squared = tf.square(ys - gathered) 176 | loss = tf.reduce_mean(tf.minimum(unsquared, squared)) 177 | 178 | # actually perform one gradient descent step 179 | if hp.UPDATE_RULE == 'rms_nomom': 180 | optimizer = tf.train.RMSPropOptimizer(hp.LEARNING_RATE) #momentum=hp.GRADIENT_MOMENTUM, epsilon=0.01, decay=hp.SQUARED_GRADIENT_MOMENTUM) 181 | elif hp.UPDATE_RULE == 'rms_mom': 182 | optimizer = tf.train.RMSPropOptimizer(hp.LEARNING_RATE, momentum=hp.GRADIENT_MOMENTUM, epsilon=0.01, decay=hp.SQUARED_GRADIENT_MOMENTUM) 183 | elif hp.UPDATE_RULE == 'adam': 184 | optimizer = tf.train.AdamOptimizer() 185 | minimize_loss = optimizer.minimize(loss, var_list=regular) 186 | 187 | -------------------------------------------------------------------------------- /download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | scp -i "$1" ubuntu@"$2":/data/q-net-"$3"000 ./checkpoints/q-net-"$4"-"$3"k 4 | scp -i "$1" ubuntu@"$2":/data/q-net-"$3"000.meta ./checkpoints/q-net-"$4"-"$3"k.meta 5 | if [ "$5" != 'nolog' ] 6 | then 7 | scp -i "$1" ubuntu@"$2":~/project/cs231n-project/logfile ./checkpoints/"$4"-"$3"k.log 8 | fi 9 | -------------------------------------------------------------------------------- /hyperparameters.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | MINIBATCH_SIZE = 32 4 | REPLAY_MEMORY_SIZE = 300000 5 | AGENT_HISTORY_LENGTH = 1 6 | TARGET_UPDATE_FREQUENCY = 10000 # C 7 | DISCOUNT_FACTOR = 0.99 8 | ACTION_REPEAT = 4 9 | UPDATE_FREQUENCY = 4 10 | 11 | GRADIENT_MOMENTUM = 0.95 12 | SQUARED_GRADIENT_MOMENTUM = 0.95 13 | MIN_SQUARED_GRADIENT = 0.01 14 | INITIAL_EXPLORATION = 1 15 | FINAL_EXPLORATION = 0.1 16 | FINAL_EXPLORATION_FRAME = 500000 17 | REPLAY_START_SIZE = 0#50000 18 | NO_OP_MAX = 30 19 | 20 | TEST_RANDOMNESS = 20 21 | 22 | CHECKPOINT_FREQUENCY = 50000 23 | 24 | TOTAL_ACTIONS = 3 25 | 26 | INPUT_SIZE = 84 27 | NUM_CHANNELS = 3 28 | 29 | CONV_1_SIZE = 8 30 | CONV_1_STRIDE = 4 31 | CONV_1_DEPTH = 32 32 | 33 | CONV_2_SIZE = 4 34 | CONV_2_STRIDE = 2 35 | CONV_2_DEPTH = 64 36 | 37 | CONV_3_SIZE = 3 38 | CONV_3_STRIDE = 1 39 | CONV_3_DEPTH = 64 40 | 41 | FC_SIZE = 512 42 | 43 | UPDATE_RULES = ['rms_mom', 'rms_nomom', 'adam'] 44 | REWARD_FUNCS = ['rishi', 'raphie'] 45 | 46 | ###### Things to change on each instance 47 | 48 | UPDATE_RULE = UPDATE_RULES[int(os.environ.get('UPDATE_RULE', 0))] 49 | REWARD_FUNC = REWARD_FUNCS[int(os.environ.get('REWARD_FUNC', 1))] 50 | LEARNING_RATE = float(os.environ.get('LR', 0.0001)) 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /qnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import hyperparameters as hp 4 | from action import Action 5 | 6 | def weight_variable(shape, name): 7 | initial = tf.truncated_normal(shape, stddev=0.1) 8 | return tf.Variable(initial, name=name) 9 | 10 | def bias_variable(shape, name): 11 | initial = tf.constant(0.1, shape=shape) 12 | return tf.Variable(initial, name=name) 13 | 14 | def conv2d(x, W, s): 15 | return tf.nn.conv2d(x, W, strides=[1, s, s, 1], padding="VALID") 16 | 17 | with tf.name_scope("input"): 18 | input_images = tf.placeholder(tf.float32, shape=[ 19 | None, 20 | hp.INPUT_SIZE, 21 | hp.INPUT_SIZE, 22 | hp.AGENT_HISTORY_LENGTH 23 | ], name="input_images") 24 | 25 | 26 | with tf.name_scope("conv_1"): 27 | W_conv1 = weight_variable([ 28 | hp.CONV_1_SIZE, 29 | hp.CONV_1_SIZE, 30 | hp.AGENT_HISTORY_LENGTH, 31 | hp.CONV_1_DEPTH 32 | ], name="W_conv1") 33 | b_conv1 = bias_variable([hp.CONV_1_DEPTH], name="b_conv1") 34 | h_conv1 = tf.nn.relu(conv2d(input_images, W_conv1, hp.CONV_1_STRIDE) + b_conv1) 35 | 36 | with tf.name_scope("conv_2"): 37 | W_conv2 = weight_variable([ 38 | hp.CONV_2_SIZE, 39 | hp.CONV_2_SIZE, 40 | hp.CONV_1_DEPTH, 41 | hp.CONV_2_DEPTH 42 | ], name="W_conv2") 43 | b_conv2 = bias_variable([hp.CONV_2_DEPTH], name="b_conv2") 44 | h_conv2 = tf.nn.relu(conv2d(h_conv1, W_conv2, hp.CONV_2_STRIDE) + b_conv2) 45 | 46 | 47 | with tf.name_scope("conv_3"): 48 | W_conv3 = weight_variable([ 49 | hp.CONV_3_SIZE, 50 | hp.CONV_3_SIZE, 51 | hp.CONV_2_DEPTH, 52 | hp.CONV_3_DEPTH 53 | ], name="W_conv3") 54 | b_conv3 = bias_variable([hp.CONV_3_DEPTH], name="b_conv3") 55 | h_conv3 = tf.nn.relu(conv2d(h_conv2, W_conv3, hp.CONV_3_STRIDE) + b_conv3) 56 | 57 | def output_size(in_size, filter_size, stride): 58 | return (in_size - filter_size)/stride + 1 59 | 60 | conv3_out_size = np.prod(h_conv3.get_shape().as_list()[1:]) 61 | conv1_out_size = output_size(hp.INPUT_SIZE, hp.CONV_1_SIZE, hp.CONV_1_STRIDE) 62 | conv2_out_size = output_size(conv1_out_size, hp.CONV_2_SIZE, hp.CONV_2_STRIDE) 63 | conv3_out_sizep = output_size(conv2_out_size, hp.CONV_3_SIZE, hp.CONV_3_STRIDE) 64 | conv3_out_len = hp.CONV_3_DEPTH * (conv3_out_sizep ** 2) 65 | print conv3_out_size, conv3_out_len 66 | 67 | with tf.name_scope("fc1"): 68 | W_fc1 = weight_variable([conv3_out_size, hp.FC_SIZE], name="W_fc1") 69 | b_fc1 = bias_variable([hp.FC_SIZE], name="b_fc1") 70 | resized = tf.reshape(h_conv3, [-1, conv3_out_size], name="resized") 71 | h_fc1 = tf.nn.relu(tf.matmul(resized, W_fc1) + b_fc1) 72 | 73 | 74 | with tf.name_scope("out"): 75 | W_out = weight_variable([hp.FC_SIZE, Action.num_actions], name="W_out") 76 | b_out = bias_variable([Action.num_actions], name="b_out") 77 | actions = tf.matmul(h_fc1, W_out) + b_out 78 | 79 | max_index = tf.argmax(actions, 1, name="max_index") 80 | 81 | tf.histogram_summary("actions", actions) 82 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.10.4 2 | Pillow==3.0.0 3 | tornado==4.3 4 | -------------------------------------------------------------------------------- /static/Rakefile: -------------------------------------------------------------------------------- 1 | 2 | desc 'recreate sprite sheets' 3 | task 'resprite' do 4 | require 'sprite_factory' 5 | 6 | SpriteFactory.run!('images/sprites', :layout => :packed, :output_style => 'images/sprites.js', :margin => 5, :nocomments => true) do |images| 7 | SpriteHelper.javascript_style("SPRITES", images) 8 | end 9 | 10 | SpriteFactory.run!('images/background', :layout => :vertical, :output_style => 'images/background.js', :margin => 5, :nocomments => true) do |images| 11 | SpriteHelper.javascript_style("BACKGROUND", images) 12 | end 13 | 14 | end 15 | 16 | #------------------------------------------------------------------------------ 17 | 18 | module SpriteHelper 19 | 20 | # slightly unusual use of sprite-factory to generate a javascript object structure instead of CSS attributes... 21 | def self.javascript_style(variable, images) 22 | maxname = images.keys.inject(0) {|n,key| [n,key.length].max } 23 | rules = [] 24 | images.each do |name, i| 25 | name = name.upcase 26 | whitespace = ' '*(maxname-name.length) 27 | x = '%4d' % i[:cssx] 28 | y = '%4d' % i[:cssy] 29 | w = '%4d' % i[:cssw] 30 | h = '%4d' % i[:cssh] 31 | rules << " #{name}: #{whitespace}{ x: #{x}, y: #{y}, w: #{w}, h: #{h} }" 32 | end 33 | "var #{variable} = {\n#{rules.join(",\n")}\n};" 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /static/common.css: -------------------------------------------------------------------------------- 1 | 2 | /****************************************/ 3 | /* common styles used for v1 through v4 */ 4 | /****************************************/ 5 | 6 | body { font-family: Arial, Helvetica, sans-serif; } 7 | #stats { border: 2px solid black; } 8 | #controls { width: 28em; float: left; padding: 1em; font-size: 0.7em; } 9 | #controls th { text-align: right; vertical-align: middle; } 10 | #instructions { clear: left; float: left; width: 17em; padding: 1em; border: 1px solid black; box-shadow: 0 0 5px black; } 11 | #racer { position: relative; z-index: 0; width: 640px; height: 480px; margin-left: 20em; border: 2px solid black; } 12 | #canvas { position: absolute; z-index: 0; width: 640px; height: 480px; z-index: 0; background-color: #72D7EE; } 13 | #mute { background-position: 0px 0px; width: 32px; height: 32px; background: url(images/mute.png); display: inline-block; cursor: pointer; position: absolute; margin-left: 20em; } 14 | #mute.on { background-position: -32px 0px; } 15 | 16 | /**************************************************/ 17 | /* rudimentary heads up display (only used in v4) */ 18 | /**************************************************/ 19 | 20 | #hud { position: absolute; z-index: 1; width: 640px; padding: 5px 0; font-family: Verdana, Geneva, sans-serif; font-size: 0.8em; background-color: rgba(255,0,0,0.4); color: black; border-bottom: 2px solid black; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } 21 | #hud .hud { background-color: rgba(255,255,255,0.6); padding: 5px; border: 1px solid black; margin: 0 5px; transition-property: background-color; transition-duration: 2s; -webkit-transition-property: background-color; -webkit-transition-duration: 2s; } 22 | #hud #speed { float: right; } 23 | #hud #current_lap_time { float: left; } 24 | #hud #last_lap_time { float: left; display: none; } 25 | #hud #fast_lap_time { display: block; width: 12em; margin: 0 auto; text-align: center; transition-property: background-color; transition-duration: 2s; -webkit-transition-property: background-color; -webkit-transition-duration: 2s; } 26 | #hud .value { color: black; font-weight: bold; } 27 | #hud .fastest { background-color: rgba(255,215,0,0.5); } 28 | 29 | -------------------------------------------------------------------------------- /static/common.js: -------------------------------------------------------------------------------- 1 | //========================================================================= 2 | // minimalist DOM helpers 3 | //========================================================================= 4 | 5 | var COLLISION_OCCURED = false; 6 | 7 | var Dom = { 8 | 9 | get: function(id) { return ((id instanceof HTMLElement) || (id === document)) ? id : document.getElementById(id); }, 10 | set: function(id, html) { Dom.get(id).innerHTML = html; }, 11 | on: function(ele, type, fn, capture) { Dom.get(ele).addEventListener(type, fn, capture); }, 12 | un: function(ele, type, fn, capture) { Dom.get(ele).removeEventListener(type, fn, capture); }, 13 | show: function(ele, type) { Dom.get(ele).style.display = (type || 'block'); }, 14 | blur: function(ev) { ev.target.blur(); }, 15 | 16 | addClassName: function(ele, name) { Dom.toggleClassName(ele, name, true); }, 17 | removeClassName: function(ele, name) { Dom.toggleClassName(ele, name, false); }, 18 | toggleClassName: function(ele, name, on) { 19 | ele = Dom.get(ele); 20 | var classes = ele.className.split(' '); 21 | var n = classes.indexOf(name); 22 | on = (typeof on == 'undefined') ? (n < 0) : on; 23 | if (on && (n < 0)) 24 | classes.push(name); 25 | else if (!on && (n >= 0)) 26 | classes.splice(n, 1); 27 | ele.className = classes.join(' '); 28 | }, 29 | 30 | storage: window.localStorage || {} 31 | 32 | } 33 | 34 | //========================================================================= 35 | // general purpose helpers (mostly math) 36 | //========================================================================= 37 | 38 | var Util = { 39 | 40 | timestamp: function() { return new Date().getTime(); }, 41 | toInt: function(obj, def) { if (obj !== null) { var x = parseInt(obj, 10); if (!isNaN(x)) return x; } return Util.toInt(def, 0); }, 42 | toFloat: function(obj, def) { if (obj !== null) { var x = parseFloat(obj); if (!isNaN(x)) return x; } return Util.toFloat(def, 0.0); }, 43 | limit: function(value, min, max) { return Math.max(min, Math.min(value, max)); }, 44 | randomInt: function(min, max) { return Math.round(Util.interpolate(min, max, Math.random())); }, 45 | randomChoice: function(options) { return options[Util.randomInt(0, options.length-1)]; }, 46 | percentRemaining: function(n, total) { return (n%total)/total; }, 47 | accelerate: function(v, accel, dt) { return v + (accel * dt); }, 48 | interpolate: function(a,b,percent) { return a + (b-a)*percent }, 49 | easeIn: function(a,b,percent) { return a + (b-a)*Math.pow(percent,2); }, 50 | easeOut: function(a,b,percent) { return a + (b-a)*(1-Math.pow(1-percent,2)); }, 51 | easeInOut: function(a,b,percent) { return a + (b-a)*((-Math.cos(percent*Math.PI)/2) + 0.5); }, 52 | exponentialFog: function(distance, density) { return 1 / (Math.pow(Math.E, (distance * distance * density))); }, 53 | 54 | increase: function(start, increment, max) { // with looping 55 | var result = start + increment; 56 | while (result >= max) 57 | result -= max; 58 | while (result < 0) 59 | result += max; 60 | return result; 61 | }, 62 | 63 | project: function(p, cameraX, cameraY, cameraZ, cameraDepth, width, height, roadWidth) { 64 | p.camera.x = (p.world.x || 0) - cameraX; 65 | p.camera.y = (p.world.y || 0) - cameraY; 66 | p.camera.z = (p.world.z || 0) - cameraZ; 67 | p.screen.scale = cameraDepth/p.camera.z; 68 | p.screen.x = Math.round((width/2) + (p.screen.scale * p.camera.x * width/2)); 69 | p.screen.y = Math.round((height/2) - (p.screen.scale * p.camera.y * height/2)); 70 | p.screen.w = Math.round( (p.screen.scale * roadWidth * width/2)); 71 | }, 72 | 73 | overlap: function(x1, w1, x2, w2, percent) { 74 | var half = (percent || 1)/2; 75 | var min1 = x1 - (w1*half); 76 | var max1 = x1 + (w1*half); 77 | var min2 = x2 - (w2*half); 78 | var max2 = x2 + (w2*half); 79 | return ! ((max1 < min2) || (min1 > max2)); 80 | } 81 | 82 | } 83 | 84 | //========================================================================= 85 | // POLYFILL for requestAnimationFrame 86 | //========================================================================= 87 | 88 | if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 89 | window.requestAnimationFrame = window.webkitRequestAnimationFrame || 90 | window.mozRequestAnimationFrame || 91 | window.oRequestAnimationFrame || 92 | window.msRequestAnimationFrame || 93 | function(callback, element) { 94 | window.setTimeout(callback, 1000 / 60); 95 | } 96 | } 97 | 98 | //========================================================================= 99 | // GAME LOOP helpers 100 | //========================================================================= 101 | 102 | var downsizeCanvas = document.createElement("canvas"); 103 | var downsizeCtx = downsizeCanvas.getContext("2d"); 104 | downsizeCanvas.width = 84; 105 | downsizeCanvas.height = 84; 106 | var downsizeImage = new Image() 107 | 108 | function encode() { 109 | var imageData = ctx.getImageData(0, 0, 360, 480); 110 | var downsized = ""; 111 | for (var i = 0; i < imageData.data.length; i++) { 112 | var d = imageData.data[i]; 113 | downsized += String.fromCharCode(d); 114 | } 115 | return downsized; 116 | } 117 | 118 | function processFrame(foobaz) { 119 | // console.time("Process") 120 | downsizeImage.src = canvas.toDataURL() 121 | downsizeCtx.drawImage(downsizeImage, 0, 0, 84, 84) 122 | var imageData = downsizeCtx.getImageData(0, 0, 84, 84); 123 | var counter = 0; 124 | var downsized = "" 125 | // var lum = [0.2126, 0.7152, 0.0722]; 126 | // var acc = 0; 127 | for (var i = 0; i < imageData.data.length; i++) { 128 | var d = imageData.data[i]; 129 | if (i % 4 == 3){ 130 | continue; 131 | } 132 | else{ 133 | downsized += String.fromCharCode(Math.round(d)); 134 | } 135 | } 136 | // console.timeEnd("Process") 137 | return btoa(downsized); 138 | } 139 | 140 | function reward() { 141 | var COLLISION_COST = -1; 142 | var OFF_ROAD_COST = -0.8; 143 | var LANE_PENALTY = 0.5; 144 | 145 | if (COLLISION_OCCURED) { 146 | return {reward: COLLISION_COST, terminal: true} 147 | } 148 | var pos = Math.abs(playerX); 149 | if (pos > 0.8) { 150 | return {reward: OFF_ROAD_COST, terminal: true} 151 | } 152 | var inLane = pos <= 0.1 || (pos >= 0.6 && pos <= 0.8) 153 | var penalty = inLane ? 1 : LANE_PENALTY; 154 | return {reward: penalty * (speed / maxSpeed), terminal: false}; 155 | } 156 | 157 | var actRep = 4; 158 | var repCount = 0; 159 | var datas = [] 160 | var WAS_START = true; 161 | keyFaster = true; 162 | function telemetry(frame) { 163 | var r = reward() 164 | var all_data = { 165 | collision: COLLISION_OCCURED, 166 | position: playerX, 167 | speed: speed, 168 | max_speed: maxSpeed 169 | } 170 | if (r.terminal) { 171 | $.ajax({ 172 | type: 'POST', 173 | url: '/frame?telemetry=' + JSON.stringify({ 174 | all_data: [all_data], 175 | terminal: true, 176 | was_start: WAS_START, 177 | action: [keyLeft, keyRight, keyFaster, keySlower] 178 | }), 179 | data: processFrame(), 180 | contentType: "application/json" 181 | }).done(function(data) { 182 | location.reload(); 183 | }); 184 | return; 185 | } 186 | datas.push(all_data) 187 | if (repCount == actRep) { 188 | var stringified = JSON.stringify({ 189 | all_data: datas, 190 | terminal: false, 191 | was_start: WAS_START, 192 | action: [keyLeft, keyRight, keyFaster, keySlower] 193 | }) 194 | $.ajax({ 195 | type: 'POST', 196 | url: '/frame?telemetry=' + stringified, 197 | data: processFrame(), 198 | contentType: "application/json" 199 | }).done(function(data) { 200 | data = JSON.parse(data); 201 | keyLeft = data["keyLeft"] 202 | keyRight = data["keyRight"] 203 | keyFaster = data["keyFaster"] 204 | keySlower = data["keySlower"] 205 | requestAnimationFrame(frame, canvas); 206 | WAS_START = false; 207 | datas = []; 208 | }); 209 | rewardTotal = 0; 210 | repCount = 0; 211 | } else { 212 | requestAnimationFrame(frame, canvas); 213 | } 214 | repCount++; 215 | } 216 | 217 | 218 | var Game = { // a modified version of the game loop from my previous boulderdash game - see http://codeincomplete.com/posts/2011/10/25/javascript_boulderdash/#gameloop 219 | 220 | run: function(options) { 221 | 222 | Game.loadImages(options.images, function(images) { 223 | 224 | options.ready(images); // tell caller to initialize itself because images are loaded and we're ready to rumble 225 | 226 | Game.setKeyListener(options.keys); 227 | 228 | var canvas = options.canvas, // canvas render target is provided by caller 229 | update = options.update, // method to update game logic is provided by caller 230 | render = options.render, // method to render the game is provided by caller 231 | step = options.step, // fixed frame step (1/fps) is specified by caller 232 | stats = options.stats, // stats instance is provided by caller 233 | now = null, 234 | last = Util.timestamp(), 235 | dt = 0, 236 | gdt = 0; 237 | 238 | window.debugFrame = frame; 239 | window.debugRender = render; 240 | function frame() { 241 | now = Util.timestamp(); 242 | dt = 0.05; 243 | // dt = Math.min(1, (now - last) / 1000); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab 244 | gdt = gdt + dt; 245 | while (gdt > step) { 246 | gdt = gdt - step; 247 | update(step); 248 | } 249 | render(); 250 | stats.update(); 251 | last = now; 252 | // requestAnimationFrame(frame, canvas); 253 | telemetry(frame); 254 | } 255 | frame(); // lets get this party started 256 | // Game.playMusic(); 257 | }); 258 | }, 259 | 260 | //--------------------------------------------------------------------------- 261 | 262 | loadImages: function(names, callback) { // load multiple images and callback when ALL images have loaded 263 | var result = []; 264 | var count = names.length; 265 | 266 | var onload = function() { 267 | if (--count == 0) 268 | callback(result); 269 | }; 270 | 271 | for(var n = 0 ; n < names.length ; n++) { 272 | var name = names[n]; 273 | result[n] = document.createElement('img'); 274 | Dom.on(result[n], 'load', onload); 275 | result[n].src = "images/" + name + ".png"; 276 | } 277 | }, 278 | 279 | //--------------------------------------------------------------------------- 280 | 281 | setKeyListener: function(keys) { 282 | var onkey = function(keyCode, mode) { 283 | var n, k; 284 | for(n = 0 ; n < keys.length ; n++) { 285 | k = keys[n]; 286 | k.mode = k.mode || 'up'; 287 | if ((k.key == keyCode) || (k.keys && (k.keys.indexOf(keyCode) >= 0))) { 288 | if (k.mode == mode) { 289 | k.action.call(); 290 | } 291 | } 292 | } 293 | }; 294 | Dom.on(document, 'keydown', function(ev) { onkey(ev.keyCode, 'down'); } ); 295 | Dom.on(document, 'keyup', function(ev) { onkey(ev.keyCode, 'up'); } ); 296 | }, 297 | 298 | //--------------------------------------------------------------------------- 299 | 300 | stats: function(parentId, id) { // construct mr.doobs FPS counter - along with friendly good/bad/ok message box 301 | 302 | var result = new Stats(); 303 | result.domElement.id = id || 'stats'; 304 | Dom.get(parentId).appendChild(result.domElement); 305 | 306 | var msg = document.createElement('div'); 307 | msg.style.cssText = "border: 2px solid gray; padding: 5px; margin-top: 5px; text-align: left; font-size: 1.15em; text-align: right;"; 308 | msg.innerHTML = "Your canvas performance is "; 309 | Dom.get(parentId).appendChild(msg); 310 | 311 | var value = document.createElement('span'); 312 | value.innerHTML = "..."; 313 | msg.appendChild(value); 314 | 315 | setInterval(function() { 316 | var fps = result.current(); 317 | var ok = (fps > 50) ? 'good' : (fps < 30) ? 'bad' : 'ok'; 318 | var color = (fps > 50) ? 'green' : (fps < 30) ? 'red' : 'gray'; 319 | value.innerHTML = ok; 320 | value.style.color = color; 321 | msg.style.borderColor = color; 322 | }, 5000); 323 | return result; 324 | }, 325 | 326 | //--------------------------------------------------------------------------- 327 | 328 | playMusic: function() { 329 | var music = Dom.get('music'); 330 | music.loop = true; 331 | music.volume = 0.05; // shhhh! annoying music! 332 | music.muted = (Dom.storage.muted === "true"); 333 | music.play(); 334 | Dom.toggleClassName('mute', 'on', music.muted); 335 | Dom.on('mute', 'click', function() { 336 | Dom.storage.muted = music.muted = !music.muted; 337 | Dom.toggleClassName('mute', 'on', music.muted); 338 | }); 339 | } 340 | 341 | } 342 | 343 | //========================================================================= 344 | // canvas rendering helpers 345 | //========================================================================= 346 | 347 | var Render = { 348 | 349 | polygon: function(ctx, x1, y1, x2, y2, x3, y3, x4, y4, color) { 350 | ctx.fillStyle = color; 351 | ctx.beginPath(); 352 | ctx.moveTo(x1, y1); 353 | ctx.lineTo(x2, y2); 354 | ctx.lineTo(x3, y3); 355 | ctx.lineTo(x4, y4); 356 | ctx.closePath(); 357 | ctx.fill(); 358 | }, 359 | 360 | //--------------------------------------------------------------------------- 361 | 362 | segment: function(ctx, width, lanes, x1, y1, w1, x2, y2, w2, fog, color) { 363 | 364 | var r1 = Render.rumbleWidth(w1, lanes), 365 | r2 = Render.rumbleWidth(w2, lanes), 366 | l1 = Render.laneMarkerWidth(w1, lanes), 367 | l2 = Render.laneMarkerWidth(w2, lanes), 368 | lanew1, lanew2, lanex1, lanex2, lane; 369 | 370 | ctx.fillStyle = color.grass; 371 | ctx.fillRect(0, y2, width, y1 - y2); 372 | 373 | Render.polygon(ctx, x1-w1-r1, y1, x1-w1, y1, x2-w2, y2, x2-w2-r2, y2, color.rumble); 374 | Render.polygon(ctx, x1+w1+r1, y1, x1+w1, y1, x2+w2, y2, x2+w2+r2, y2, color.rumble); 375 | Render.polygon(ctx, x1-w1, y1, x1+w1, y1, x2+w2, y2, x2-w2, y2, color.road); 376 | 377 | if (color.lane) { 378 | lanew1 = w1*2/lanes; 379 | lanew2 = w2*2/lanes; 380 | lanex1 = x1 - w1 + lanew1; 381 | lanex2 = x2 - w2 + lanew2; 382 | for(lane = 1 ; lane < lanes ; lanex1 += lanew1, lanex2 += lanew2, lane++) 383 | Render.polygon(ctx, lanex1 - l1/2, y1, lanex1 + l1/2, y1, lanex2 + l2/2, y2, lanex2 - l2/2, y2, color.lane); 384 | } 385 | 386 | Render.fog(ctx, 0, y1, width, y2-y1, fog); 387 | }, 388 | 389 | //--------------------------------------------------------------------------- 390 | 391 | background: function(ctx, background, width, height, layer, rotation, offset) { 392 | 393 | rotation = rotation || 0; 394 | offset = offset || 0; 395 | 396 | var imageW = layer.w/2; 397 | var imageH = layer.h; 398 | 399 | var sourceX = layer.x + Math.floor(layer.w * rotation); 400 | var sourceY = layer.y 401 | var sourceW = Math.min(imageW, layer.x+layer.w-sourceX); 402 | var sourceH = imageH; 403 | 404 | var destX = 0; 405 | var destY = offset; 406 | var destW = Math.floor(width * (sourceW/imageW)); 407 | var destH = height; 408 | 409 | ctx.drawImage(background, sourceX, sourceY, sourceW, sourceH, destX, destY, destW, destH); 410 | if (sourceW < imageW) 411 | ctx.drawImage(background, layer.x, sourceY, imageW-sourceW, sourceH, destW-1, destY, width-destW, destH); 412 | }, 413 | 414 | //--------------------------------------------------------------------------- 415 | 416 | sprite: function(ctx, width, height, resolution, roadWidth, sprites, sprite, scale, destX, destY, offsetX, offsetY, clipY) { 417 | 418 | // scale for projection AND relative to roadWidth (for tweakUI) 419 | var destW = (sprite.w * scale * width/2) * (SPRITES.SCALE * roadWidth); 420 | var destH = (sprite.h * scale * width/2) * (SPRITES.SCALE * roadWidth); 421 | 422 | destX = destX + (destW * (offsetX || 0)); 423 | destY = destY + (destH * (offsetY || 0)); 424 | 425 | var clipH = clipY ? Math.max(0, destY+destH-clipY) : 0; 426 | if (clipH < destH) 427 | ctx.drawImage(sprites, sprite.x, sprite.y, sprite.w, sprite.h - (sprite.h*clipH/destH), destX, destY, destW, destH - clipH); 428 | 429 | }, 430 | 431 | //--------------------------------------------------------------------------- 432 | 433 | player: function(ctx, width, height, resolution, roadWidth, sprites, speedPercent, scale, destX, destY, steer, updown) { 434 | 435 | var bounce = (1.5 * Math.random() * speedPercent * resolution) * Util.randomChoice([-1,1]); 436 | var sprite; 437 | if (steer < 0) 438 | sprite = (updown > 0) ? SPRITES.PLAYER_UPHILL_LEFT : SPRITES.PLAYER_LEFT; 439 | else if (steer > 0) 440 | sprite = (updown > 0) ? SPRITES.PLAYER_UPHILL_RIGHT : SPRITES.PLAYER_RIGHT; 441 | else 442 | sprite = (updown > 0) ? SPRITES.PLAYER_UPHILL_STRAIGHT : SPRITES.PLAYER_STRAIGHT; 443 | 444 | Render.sprite(ctx, width, height, resolution, roadWidth, sprites, sprite, scale, destX, destY + bounce, -0.5, -1); 445 | }, 446 | 447 | //--------------------------------------------------------------------------- 448 | 449 | fog: function(ctx, x, y, width, height, fog) { 450 | if (fog < 1) { 451 | ctx.globalAlpha = (1-fog) 452 | ctx.fillStyle = COLORS.FOG; 453 | ctx.fillRect(x, y, width, height); 454 | ctx.globalAlpha = 1; 455 | } 456 | }, 457 | 458 | rumbleWidth: function(projectedRoadWidth, lanes) { return projectedRoadWidth/Math.max(6, 2*lanes); }, 459 | laneMarkerWidth: function(projectedRoadWidth, lanes) { return projectedRoadWidth/Math.max(32, 8*lanes); } 460 | 461 | } 462 | 463 | //============================================================================= 464 | // RACING GAME CONSTANTS 465 | //============================================================================= 466 | 467 | var KEY = { 468 | LEFT: 37, 469 | UP: 38, 470 | RIGHT: 39, 471 | DOWN: 40, 472 | A: 65, 473 | D: 68, 474 | S: 83, 475 | W: 87 476 | }; 477 | 478 | var COLORS = { 479 | SKY: '#72D7EE', 480 | TREE: '#005108', 481 | FOG: '#005108', 482 | LIGHT: { road: '#6B6B6B', grass: '#10AA10', rumble: '#555555', lane: '#CCCCCC' }, 483 | DARK: { road: '#696969', grass: '#009A00', rumble: '#BBBBBB' }, 484 | START: { road: 'white', grass: 'white', rumble: 'white' }, 485 | FINISH: { road: 'black', grass: 'black', rumble: 'black' } 486 | }; 487 | 488 | var BACKGROUND = { 489 | HILLS: { x: 5, y: 5, w: 1280, h: 480 }, 490 | SKY: { x: 5, y: 495, w: 1280, h: 480 }, 491 | TREES: { x: 5, y: 985, w: 1280, h: 480 } 492 | }; 493 | 494 | var SPRITES = { 495 | PALM_TREE: { x: 5, y: 5, w: 215, h: 540 }, 496 | BILLBOARD08: { x: 230, y: 5, w: 385, h: 265 }, 497 | TREE1: { x: 625, y: 5, w: 360, h: 360 }, 498 | DEAD_TREE1: { x: 5, y: 555, w: 135, h: 332 }, 499 | BILLBOARD09: { x: 150, y: 555, w: 328, h: 282 }, 500 | BOULDER3: { x: 230, y: 280, w: 320, h: 220 }, 501 | COLUMN: { x: 995, y: 5, w: 200, h: 315 }, 502 | BILLBOARD01: { x: 625, y: 375, w: 300, h: 170 }, 503 | BILLBOARD06: { x: 488, y: 555, w: 298, h: 190 }, 504 | BILLBOARD05: { x: 5, y: 897, w: 298, h: 190 }, 505 | BILLBOARD07: { x: 313, y: 897, w: 298, h: 190 }, 506 | BOULDER2: { x: 621, y: 897, w: 298, h: 140 }, 507 | TREE2: { x: 1205, y: 5, w: 282, h: 295 }, 508 | BILLBOARD04: { x: 1205, y: 310, w: 268, h: 170 }, 509 | DEAD_TREE2: { x: 1205, y: 490, w: 150, h: 260 }, 510 | BOULDER1: { x: 1205, y: 760, w: 168, h: 248 }, 511 | BUSH1: { x: 5, y: 1097, w: 240, h: 155 }, 512 | CACTUS: { x: 929, y: 897, w: 235, h: 118 }, 513 | BUSH2: { x: 255, y: 1097, w: 232, h: 152 }, 514 | BILLBOARD03: { x: 5, y: 1262, w: 230, h: 220 }, 515 | BILLBOARD02: { x: 245, y: 1262, w: 215, h: 220 }, 516 | STUMP: { x: 995, y: 330, w: 195, h: 140 }, 517 | SEMI: { x: 1365, y: 490, w: 122, h: 144 }, 518 | TRUCK: { x: 1365, y: 644, w: 100, h: 78 }, 519 | CAR03: { x: 1383, y: 760, w: 88, h: 55 }, 520 | CAR02: { x: 1383, y: 825, w: 80, h: 59 }, 521 | CAR04: { x: 1383, y: 894, w: 80, h: 57 }, 522 | CAR01: { x: 1205, y: 1018, w: 80, h: 56 }, 523 | PLAYER_UPHILL_LEFT: { x: 1383, y: 961, w: 80, h: 45 }, 524 | PLAYER_UPHILL_STRAIGHT: { x: 1295, y: 1018, w: 80, h: 45 }, 525 | PLAYER_UPHILL_RIGHT: { x: 1385, y: 1018, w: 80, h: 45 }, 526 | PLAYER_LEFT: { x: 995, y: 480, w: 80, h: 41 }, 527 | PLAYER_STRAIGHT: { x: 1085, y: 480, w: 80, h: 41 }, 528 | PLAYER_RIGHT: { x: 995, y: 531, w: 80, h: 41 } 529 | }; 530 | 531 | SPRITES.SCALE = 0.3 * (1/SPRITES.PLAYER_STRAIGHT.w) // the reference sprite width should be 1/3rd the (half-)roadWidth 532 | 533 | SPRITES.BILLBOARDS = [SPRITES.BILLBOARD01, SPRITES.BILLBOARD02, SPRITES.BILLBOARD03, SPRITES.BILLBOARD04, SPRITES.BILLBOARD05, SPRITES.BILLBOARD06, SPRITES.BILLBOARD07, SPRITES.BILLBOARD08, SPRITES.BILLBOARD09]; 534 | SPRITES.PLANTS = [SPRITES.TREE1, SPRITES.TREE2, SPRITES.DEAD_TREE1, SPRITES.DEAD_TREE2, SPRITES.PALM_TREE, SPRITES.BUSH1, SPRITES.BUSH2, SPRITES.CACTUS, SPRITES.STUMP, SPRITES.BOULDER1, SPRITES.BOULDER2, SPRITES.BOULDER3]; 535 | SPRITES.CARS = [SPRITES.CAR01, SPRITES.CAR02, SPRITES.CAR03, SPRITES.CAR04, SPRITES.SEMI, SPRITES.TRUCK]; 536 | 537 | -------------------------------------------------------------------------------- /static/images/background.js: -------------------------------------------------------------------------------- 1 | var BACKGROUND = { 2 | HILLS: { x: 5, y: 5, w: 1280, h: 480 }, 3 | SKY: { x: 5, y: 495, w: 1280, h: 480 }, 4 | TREES: { x: 5, y: 985, w: 1280, h: 480 } 5 | }; 6 | -------------------------------------------------------------------------------- /static/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/background.png -------------------------------------------------------------------------------- /static/images/background/hills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/background/hills.png -------------------------------------------------------------------------------- /static/images/background/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/background/sky.png -------------------------------------------------------------------------------- /static/images/background/trees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/background/trees.png -------------------------------------------------------------------------------- /static/images/mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/mute.png -------------------------------------------------------------------------------- /static/images/sprites.js: -------------------------------------------------------------------------------- 1 | var SPRITES = { 2 | PALM_TREE: { x: 5, y: 5, w: 215, h: 540 }, 3 | BILLBOARD08: { x: 230, y: 5, w: 385, h: 265 }, 4 | TREE1: { x: 625, y: 5, w: 360, h: 360 }, 5 | DEAD_TREE1: { x: 5, y: 555, w: 135, h: 332 }, 6 | BILLBOARD09: { x: 150, y: 555, w: 328, h: 282 }, 7 | BOULDER3: { x: 230, y: 280, w: 320, h: 220 }, 8 | COLUMN: { x: 995, y: 5, w: 200, h: 315 }, 9 | BILLBOARD01: { x: 625, y: 375, w: 300, h: 170 }, 10 | BILLBOARD06: { x: 488, y: 555, w: 298, h: 190 }, 11 | BILLBOARD05: { x: 5, y: 897, w: 298, h: 190 }, 12 | BILLBOARD07: { x: 313, y: 897, w: 298, h: 190 }, 13 | BOULDER2: { x: 621, y: 897, w: 298, h: 140 }, 14 | TREE2: { x: 1205, y: 5, w: 282, h: 295 }, 15 | BILLBOARD04: { x: 1205, y: 310, w: 268, h: 170 }, 16 | DEAD_TREE2: { x: 1205, y: 490, w: 150, h: 260 }, 17 | BOULDER1: { x: 1205, y: 760, w: 168, h: 248 }, 18 | BUSH1: { x: 5, y: 1097, w: 240, h: 155 }, 19 | CACTUS: { x: 929, y: 897, w: 235, h: 118 }, 20 | BUSH2: { x: 255, y: 1097, w: 232, h: 152 }, 21 | BILLBOARD03: { x: 5, y: 1262, w: 230, h: 220 }, 22 | BILLBOARD02: { x: 245, y: 1262, w: 215, h: 220 }, 23 | STUMP: { x: 995, y: 330, w: 195, h: 140 }, 24 | SEMI: { x: 1365, y: 490, w: 122, h: 144 }, 25 | TRUCK: { x: 1365, y: 644, w: 100, h: 78 }, 26 | CAR03: { x: 1383, y: 760, w: 88, h: 55 }, 27 | CAR02: { x: 1383, y: 825, w: 80, h: 59 }, 28 | CAR04: { x: 1383, y: 894, w: 80, h: 57 }, 29 | CAR01: { x: 1205, y: 1018, w: 80, h: 56 }, 30 | PLAYER_UPHILL_LEFT: { x: 1383, y: 961, w: 80, h: 45 }, 31 | PLAYER_UPHILL_STRAIGHT: { x: 1295, y: 1018, w: 80, h: 45 }, 32 | PLAYER_UPHILL_RIGHT: { x: 1385, y: 1018, w: 80, h: 45 }, 33 | PLAYER_LEFT: { x: 995, y: 480, w: 80, h: 41 }, 34 | PLAYER_STRAIGHT: { x: 1085, y: 480, w: 80, h: 41 }, 35 | PLAYER_RIGHT: { x: 995, y: 531, w: 80, h: 41 } 36 | }; 37 | -------------------------------------------------------------------------------- /static/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites.png -------------------------------------------------------------------------------- /static/images/sprites/billboard01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard01.png -------------------------------------------------------------------------------- /static/images/sprites/billboard02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard02.png -------------------------------------------------------------------------------- /static/images/sprites/billboard03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard03.png -------------------------------------------------------------------------------- /static/images/sprites/billboard04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard04.png -------------------------------------------------------------------------------- /static/images/sprites/billboard05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard05.png -------------------------------------------------------------------------------- /static/images/sprites/billboard06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard06.png -------------------------------------------------------------------------------- /static/images/sprites/billboard07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard07.png -------------------------------------------------------------------------------- /static/images/sprites/billboard08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard08.png -------------------------------------------------------------------------------- /static/images/sprites/billboard09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/billboard09.png -------------------------------------------------------------------------------- /static/images/sprites/boulder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/boulder1.png -------------------------------------------------------------------------------- /static/images/sprites/boulder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/boulder2.png -------------------------------------------------------------------------------- /static/images/sprites/boulder3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/boulder3.png -------------------------------------------------------------------------------- /static/images/sprites/bush1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/bush1.png -------------------------------------------------------------------------------- /static/images/sprites/bush2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/bush2.png -------------------------------------------------------------------------------- /static/images/sprites/cactus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/cactus.png -------------------------------------------------------------------------------- /static/images/sprites/car01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/car01.png -------------------------------------------------------------------------------- /static/images/sprites/car02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/car02.png -------------------------------------------------------------------------------- /static/images/sprites/car03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/car03.png -------------------------------------------------------------------------------- /static/images/sprites/car04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/car04.png -------------------------------------------------------------------------------- /static/images/sprites/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/column.png -------------------------------------------------------------------------------- /static/images/sprites/dead_tree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/dead_tree1.png -------------------------------------------------------------------------------- /static/images/sprites/dead_tree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/dead_tree2.png -------------------------------------------------------------------------------- /static/images/sprites/palm_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/palm_tree.png -------------------------------------------------------------------------------- /static/images/sprites/player_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_left.png -------------------------------------------------------------------------------- /static/images/sprites/player_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_right.png -------------------------------------------------------------------------------- /static/images/sprites/player_straight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_straight.png -------------------------------------------------------------------------------- /static/images/sprites/player_uphill_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_uphill_left.png -------------------------------------------------------------------------------- /static/images/sprites/player_uphill_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_uphill_right.png -------------------------------------------------------------------------------- /static/images/sprites/player_uphill_straight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/player_uphill_straight.png -------------------------------------------------------------------------------- /static/images/sprites/semi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/semi.png -------------------------------------------------------------------------------- /static/images/sprites/stump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/stump.png -------------------------------------------------------------------------------- /static/images/sprites/tree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/tree1.png -------------------------------------------------------------------------------- /static/images/sprites/tree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/tree2.png -------------------------------------------------------------------------------- /static/images/sprites/truck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/images/sprites/truck.png -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Javascript Racer 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /static/music/racer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/music/racer.mp3 -------------------------------------------------------------------------------- /static/music/racer.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaphiePS/cs231n-project/2c520fd79fabbba09ad995360c1e21f49e10a52a/static/music/racer.ogg -------------------------------------------------------------------------------- /static/stats.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var Stats = function () { 6 | 7 | var startTime = Date.now(), prevTime = startTime; 8 | var ms = 0, msMin = 1000, msMax = 0; 9 | var fps = 0, fpsMin = 1000, fpsMax = 0; 10 | var frames = 0, mode = 0;mode 11 | var container = document.createElement( 'div' ); 12 | container.id = 'stats'; 13 | container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); 14 | container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; 15 | 16 | var fpsDiv = document.createElement( 'div' ); 17 | fpsDiv.id = 'fps'; 18 | fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; 19 | container.appendChild( fpsDiv ); 20 | 21 | var fpsText = document.createElement( 'div' ); 22 | fpsText.id = 'fpsText'; 23 | fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 24 | fpsText.innerHTML = 'FPS'; 25 | fpsDiv.appendChild( fpsText ); 26 | 27 | var fpsGraph = document.createElement( 'div' ); 28 | fpsGraph.id = 'fpsGraph'; 29 | fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; 30 | fpsDiv.appendChild( fpsGraph ); 31 | 32 | while ( fpsGraph.children.length < 74 ) { 33 | 34 | var bar = document.createElement( 'span' ); 35 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; 36 | fpsGraph.appendChild( bar ); 37 | 38 | } 39 | 40 | var msDiv = document.createElement( 'div' ); 41 | msDiv.id = 'ms'; 42 | msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; 43 | container.appendChild( msDiv ); 44 | 45 | var msText = document.createElement( 'div' ); 46 | msText.id = 'msText'; 47 | msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 48 | msText.innerHTML = 'MS'; 49 | msDiv.appendChild( msText ); 50 | 51 | var msGraph = document.createElement( 'div' ); 52 | msGraph.id = 'msGraph'; 53 | msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; 54 | msDiv.appendChild( msGraph ); 55 | 56 | while ( msGraph.children.length < 74 ) { 57 | 58 | var bar = document.createElement( 'span' ); 59 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; 60 | msGraph.appendChild( bar ); 61 | 62 | } 63 | 64 | var setMode = function ( value ) { 65 | 66 | mode = value; 67 | 68 | switch ( mode ) { 69 | 70 | case 0: 71 | fpsDiv.style.display = 'block'; 72 | msDiv.style.display = 'none'; 73 | break; 74 | case 1: 75 | fpsDiv.style.display = 'none'; 76 | msDiv.style.display = 'block'; 77 | break; 78 | } 79 | 80 | } 81 | 82 | var updateGraph = function ( dom, value ) { 83 | 84 | var child = dom.appendChild( dom.firstChild ); 85 | child.style.height = value + 'px'; 86 | 87 | } 88 | 89 | return { 90 | 91 | domElement: container, 92 | 93 | setMode: setMode, 94 | 95 | current: function() { return fps; }, 96 | 97 | begin: function () { 98 | 99 | startTime = Date.now(); 100 | 101 | }, 102 | 103 | end: function () { 104 | 105 | var time = Date.now(); 106 | 107 | ms = time - startTime; 108 | msMin = Math.min( msMin, ms ); 109 | msMax = Math.max( msMax, ms ); 110 | 111 | msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; 112 | updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); 113 | 114 | frames ++; 115 | 116 | if ( time > prevTime + 1000 ) { 117 | 118 | fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); 119 | fpsMin = Math.min( fpsMin, fps ); 120 | fpsMax = Math.max( fpsMax, fps ); 121 | 122 | fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; 123 | updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); 124 | 125 | prevTime = time; 126 | frames = 0; 127 | 128 | } 129 | 130 | return time; 131 | 132 | }, 133 | 134 | update: function () { 135 | 136 | startTime = this.end(); 137 | 138 | } 139 | 140 | } 141 | 142 | }; 143 | 144 | -------------------------------------------------------------------------------- /static/v1.straight.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Javascript Racer - v1 (straight) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
15 | straight | 16 | curves | 17 | hills | 18 | final 19 |
25 | 31 |
36 | 42 |
65 | 66 |
67 |

Use the arrow keys to drive the car.

68 |
69 | 70 |
71 | 72 | Sorry, this example cannot be run because your browser does not support the <canvas> element 73 | 74 | Loading... 75 |
76 | 77 | 81 | 82 | 83 | 84 | 85 | 312 | 313 | 314 | 315 | -------------------------------------------------------------------------------- /static/v2.curves.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Javascript Racer - v2 (curves) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
15 | straight | 16 | curves | 17 | hills | 18 | final 19 |
25 | 31 |
36 | 42 |
65 | 66 |
67 |

Use the arrow keys to drive the car.

68 |
69 | 70 |
71 | 72 | Sorry, this example cannot be run because your browser does not support the <canvas> element 73 | 74 | Loading... 75 |
76 | 77 | 81 | 82 | 83 | 84 | 85 | s 86 | 386 | 387 | 388 | 389 | -------------------------------------------------------------------------------- /static/v3.hills.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Javascript Racer - v3 (hills) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
15 | straight | 16 | curves | 17 | hills | 18 | final 19 |
25 | 31 |
36 | 42 |
65 | 66 |
67 |

Use the arrow keys to drive the car.

68 |
69 | 70 |
71 | 72 | Sorry, this example cannot be run because your browser does not support the <canvas> element 73 | 74 | Loading... 75 |
76 | 77 | 81 | 82 | 83 | 84 | 85 | 418 | 419 | 420 | -------------------------------------------------------------------------------- /static/v4.final.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Javascript Racer - v4 (final) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
15 | straight | 16 | curves | 17 | hills | 18 | final 19 |
25 | 31 |
36 | 42 |
65 | 66 |
67 |

Use the arrow keys to drive the car.

68 |
69 | 70 |
71 |
72 | 0 mph 73 | Time: 0.0 74 | Last Lap: 0.0 75 | Fastest Lap: 0.0 76 |
77 | 78 | Sorry, this example cannot be run because your browser does not support the <canvas> element 79 | 80 | Loading... 81 |
82 | 83 | 87 | 88 | 89 | 90 | 91 | 92 | 687 | 688 | 689 | 690 | 691 | -------------------------------------------------------------------------------- /static/worker.js: -------------------------------------------------------------------------------- 1 | onmessage = function(e) { 2 | console.log('Message received from main script'); 3 | } -------------------------------------------------------------------------------- /testing_stuff.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from transition_table import TransitionTable\n", 12 | "from action import Action\n", 13 | "import numpy as np\n", 14 | "\n", 15 | "table = TransitionTable()\n", 16 | "\n", 17 | "img = np.ones((84, 84))\n", 18 | "img2 = 2 * np.ones((84, 84))\n", 19 | "table.add_transition(img, False, Action(2), 0.5, True)\n", 20 | "table.add_transition(img2, False, Action(3), 0.7, False)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": { 27 | "collapsed": false 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "recent = table.get_recent()\n", 32 | "for i in range(4):\n", 33 | " print np.linalg.norm(recent[:, :, i])" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 14, 39 | "metadata": { 40 | "collapsed": false 41 | }, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "HELLO WE ARE DECREMENTING HERE\n", 48 | "[ 2. 1. 1. 1.]\n", 49 | "[ 1. 1. 1. 1.]\n" 50 | ] 51 | } 52 | ], 53 | "source": [ 54 | "s, t, a, r, sp = table.get_minibatch()\n", 55 | "print sp[0, 20, 20, :]\n", 56 | "print s[0, 20, 20, :]" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "collapsed": false 64 | }, 65 | "outputs": [], 66 | "source": [] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": { 72 | "collapsed": false 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "print table.get_recent()" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": { 83 | "collapsed": false 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "table.transitions[0].was_start" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "metadata": { 94 | "collapsed": true 95 | }, 96 | "outputs": [], 97 | "source": [] 98 | } 99 | ], 100 | "metadata": { 101 | "kernelspec": { 102 | "display_name": "Python 2", 103 | "language": "python", 104 | "name": "python2" 105 | }, 106 | "language_info": { 107 | "codemirror_mode": { 108 | "name": "ipython", 109 | "version": 2 110 | }, 111 | "file_extension": ".py", 112 | "mimetype": "text/x-python", 113 | "name": "python", 114 | "nbconvert_exporter": "python", 115 | "pygments_lexer": "ipython2", 116 | "version": "2.7.10" 117 | } 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 0 121 | } 122 | -------------------------------------------------------------------------------- /tf_test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.misc 4 | import time 5 | from double_qnet import r_actions, t_actions, s, sp, update_target, loss, actions, rewards, terminals, ys, minimize_loss, r_W_conv1, t_W_conv1, best_action 6 | 7 | with tf.Session() as sess: 8 | writer = tf.train.SummaryWriter("/tmp/bazbar_logs", sess.graph_def) 9 | sess.run(tf.initialize_all_variables()) 10 | # img = img[np.newaxis, :, :, np.newaxis] 11 | # img = np.tile(img, 4) 12 | img = np.ones((32, 84, 84, 4)) 13 | actions_ = np.ones(32) 14 | rewards_ = np.ones(32) * 0.5 15 | terminals_ = np.zeros(32) 16 | print map(np.linalg.norm, sess.run([r_W_conv1, t_W_conv1])) 17 | for i in range(100): 18 | t = time.time() 19 | # feed_dict takes placeholders and actually produces runtime values 20 | # substitutes in real variables for what are placeholders in the model (in (double)_qnet.py) 21 | sess.run([minimize_loss], feed_dict={s: img, sp: img, actions: actions_, rewards: rewards_, terminals: terminals_}) 22 | print (time.time() - t) * 1000 23 | print map(np.linalg.norm, sess.run([r_W_conv1, t_W_conv1])) 24 | # [ar, at] = sess.run([r_actions, t_actions], feed_dict={s: img, sp: img}) 25 | # print ar 26 | # print at 27 | # sess.run(update_target) 28 | # [ar, at] = sess.run([r_actions, t_actions], feed_dict={s: img, sp: img}) 29 | # print ar 30 | # print at 31 | # print r_b_outa, t_b_outa, b_outa 32 | 33 | 34 | ########################################################### 35 | 36 | # = to "reset Q_hat = Q", we need to do every C steps 37 | # update Q-Hat from Q 38 | sess.run(update_target) 39 | 40 | # perform gradient descent update 41 | # need to test w/ transition table 42 | sess.run([minimize_loss], feed_dict={s: img, sp: img, actions: actions_, rewards: rewards_, terminals: terminals_}) 43 | 44 | # picking the next action 45 | # will be index corresponding to best action (TF handles the argmax for us in double_qnet.py) 46 | sess.run(best_action, feed_dict={s: img}) 47 | -------------------------------------------------------------------------------- /transition_table.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import hyperparameters as hp 3 | from action import Action 4 | from collections import deque 5 | import pdb 6 | 7 | class Transition(object): 8 | def __init__(self, image, terminal, action, reward, was_start, telemetry): 9 | self.action = action 10 | self.reward = reward 11 | self.image = image 12 | self.terminal = terminal 13 | self.was_start = was_start 14 | self.telemetry = telemetry 15 | 16 | 17 | class TransitionTable(object): 18 | 19 | def __init__(self): 20 | self.capacity = hp.REPLAY_MEMORY_SIZE 21 | self.transitions = deque(maxlen = self.capacity) 22 | 23 | def get_index(self, transition_index): 24 | s = np.zeros((hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)) 25 | sp = np.zeros((hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)) 26 | 27 | last_frame = self.transitions[transition_index] 28 | current_index = transition_index 29 | current_transition = self.transitions[current_index] 30 | t = int(current_transition.terminal) 31 | a = current_transition.action.num 32 | r = current_transition.reward 33 | 34 | sp = current_transition.image 35 | if not current_transition.was_start: 36 | s = self.transitions[current_index - 1].image 37 | else: 38 | s = current_transition.image 39 | 40 | # for i in range(hp.AGENT_HISTORY_LENGTH + 1): 41 | # if i < hp.AGENT_HISTORY_LENGTH: 42 | # sp[:, :, :, i] = current_transition.image 43 | # if i > 0: 44 | # s[:, :, :, i - 1] = current_transition.image 45 | # if not current_transition.was_start: 46 | # current_index -= 1 47 | # current_transition = self.transitions[current_index] 48 | 49 | return (s, t, a, r, sp) 50 | 51 | def get_recent(self): 52 | # pick a new action 53 | s, t, a, r, sp = self.get_index(-1) 54 | return sp.reshape((1, hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)) 55 | 56 | def get_minibatch(self, frame_count): 57 | # gradient update 58 | size = hp.MINIBATCH_SIZE 59 | s = np.zeros((size, hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)) 60 | sp = np.zeros_like(s) 61 | t = np.zeros(size) 62 | a = np.zeros(size) 63 | r = np.zeros(size) 64 | 65 | for i in range(size): 66 | lower = 1 if frame_count >= self.capacity else 0 67 | index = np.random.randint(lower, len(self.transitions)) 68 | s[i], t[i], a[i], r[i], sp[i] = self.get_index(index) 69 | return s, t, a, r, sp 70 | 71 | def add_transition(self, image, terminal, action, reward, was_start, telemetry): 72 | t = Transition(image, terminal, action, reward, was_start, telemetry) 73 | self.transitions.append(t) 74 | --------------------------------------------------------------------------------