def td_control(seed, env, num_episodes, epsilon, on_policy):
"""Q-learning and SARSA in one loop: they differ in a single symbol."""
rng = np.random.default_rng(seed)
Q, visits = np.zeros((16, 4)), np.zeros((16, 4))
env.reset(seed=seed)
for _ in range(num_episodes):
s, done = env.reset()[0], False
a = d2l.epsilon_greedy(Q[s], epsilon, rng)
while not done:
s2, r, terminated, truncated, _ = env.step(a)
a2 = d2l.epsilon_greedy(Q[s2], epsilon, rng)
target = Q[s2, a2] if on_policy else Q[s2].max() # the symbol
visits[s, a] += 1
Q[s, a] += (r + gamma * (1 - terminated) * target
- Q[s, a]) / (1 + 0.1 * visits[s, a])
s, a, done = s2, a2, terminated or truncated
return Q
Q_q = td_control(0, env, 8000, epsilon, on_policy=False)
Q_sarsa = td_control(0, env, 8000, epsilon, on_policy=True)
d2l.show_grid(env.unwrapped.desc, np.stack([Q_q.max(-1), Q_sarsa.max(-1)]),
np.stack([Q_q.argmax(-1), Q_sarsa.argmax(-1)]),
titles=['Q-learning, epsilon = 0.3', 'SARSA, epsilon = 0.3'])