input: Write a python function to set up a Q-learning agent for the CartPole-v0 environment in OpenAI Gym.
  assert len(q_learning_cartpole().shape) == 2
  assert q_learning_cartpole().shape[0] > 0
  assert q_learning_cartpole().shape[1] > 0
output: import numpy as np
  import gym
  
  def q_learning_cartpole():
      env = gym.make('CartPole-v0')
      n_actions = env.action_space.n
      n_states = (1, 1, 6, 3)  # Discretize the state space
  
      q_table = np.zeros(n_states + (n_actions,))
      
      def discretize_state(state):
          cart_pos, cart_vel, pole_angle, pole_vel = state
          cart_pos_bin = int(np.digitize(cart_pos, np.linspace(-4.8, 4.8, n_states[0] - 1)))
          cart_vel_bin = int(np.digitize(cart_vel, np.linspace(-3.4, 3.4, n_states[1] - 1)))
          pole_angle_bin = int(np.digitize(pole_angle, np.linspace(-0.209, 0.209, n_states[2] - 1)))
          pole_vel_bin = int(np.digitize(pole_vel, np.linspace(-2, 2, n_states[3] - 1)))
          return (cart_pos_bin, cart_vel_bin, pole_angle_bin, pole_vel_bin)
      
      alpha = 0.1
      gamma = 0.99
      epsilon = 0.1
      n_episodes = 10000
  
      for episode in range(n_episodes):
          state = discretize_state(env.reset())
          done = False
          
          while not done:
              if np.random.rand() < epsilon:
                  action = env.action_space.sample()
              else:
                  action = np.argmax(q_table[state])
              
              next_state_raw, reward, done, _ = env.step(action)
              next_state = discretize_state(next_state_raw)
  
              best_next_action = np.argmax(q_table[next_state])
              td_target = reward + gamma * q_table[next_state][best_next_action]
              td_error = td_target - q_table[state][action]
              q_table[state][action] += alpha * td_error
  
              state = next_state
      
      return q_table