Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Ickaser committed Dec 12, 2020
1 parent 516cc21 commit 5d8948f
Show file tree
Hide file tree
Showing 127 changed files with 543,693 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
# adaptive_game_control
ChEn 436 Process Control final project: adaptive game difficulty

The basic file structure here is as follows:

`sim.py` implements the basic gameplay simulation, as well as classification system and PID control system.

`main.py` will run a simulation with `skill` and `style` parameters set inside the file, and generate and save some plots about that simulation. (It calls `plt.show`, so depending on where you run the code, it will probably also show you the plots.)

`params.py` is used to run a large number of simulations, for the purpose of gathering statistics; it also uses those simulations to determine values for process gain $K_p$ and time constant $\tau_p$. (The generated values are stored in `params.txt` here, so you do not need to run this unless you want to recalculate $K_p$ and $\tau_p$. The simulation results are all stored in `sim_results` folder.

`trends_gen.py` generates the reference file which our classification system uses. (Again, we have provided this output, `trendslist.data`, which is a pickled Python list, so you do not need to run this file.) It uses saved output files from `params.py`, so if you choose to run this, you should run `params.py` first.


110 changes: 110 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy.random as rnd
import pickle
# %matplotlib inline

# from google.colab import drive
# drive.mount('/content/gdrive')


# Other files for this project
import sim
# import params

# proj_dir = "/content/gdrive/My Drive/ProcControl Project/"
proj_dir = "./"

style = "reckless"
skill = 5

Npts = 6000 # seconds
time = np.linspace(0,Npts-1,Npts)
dt = time[1]-time[0]

#Initialize Character Stats array
# At_char = np.ones(Npts)*10 #Character Attack
HP0 = 100
At_char = 1
skill = 5
style = "conservative"
# style = "reckless"
# style = "moderate"
HP_char = np.zeros(Npts) #Character Health
HP_char[0] = HP0



#Enemy Initial Stats
Enemy0 = [10,1] #Enemy0 = [Health, Attack] #
Enemy = list(Enemy0)
At_enem = np.ones(Npts)
HP_enem = np.ones(Npts) * Enemy0[0]


#If we use average damage per time as our set point we will use the following
SP_DPS = HP0/100 #the PID will attempt to have the player loose this much health per time (damage/second)
SP_DPS = HP0/150

#########

tauD = 0

dt = 1

# Run a simulation
HP_char, At_enem, HP_enem, etod, interr_arr = sim.sim_gameplay(style, skill, control=True)
filterwidth = 20
# DPS = -(HP_char[filterwidth:] - HP_char[:-filterwidth])/filterwidth
DPS = -(HP_char[1:] - HP_char[0]) / time[1:]
DPS[0] = 0
# print(At_enem[:etod])
err = SP_DPS - DPS
SAE = np.sum(np.abs(err[:etod]))
# print(err[:etod])
print("SAE", SAE)

# Plot results up until time of death

plt.plot(time[0:etod],HP_char[0:etod],'k',label='HP')
plt.title('Character Health',fontsize=24)
plt.xlabel('Time (sec)',fontsize=18)
plt.ylabel('Health',fontsize=18)
plt.axvline(150, color="gray", ls="--", label="target time")
plt.text(etod*.8, 80, f"skill={skill}")
plt.text(etod*.7, 60, f"style={style}")
plt.legend(fontsize=14)
plt.ylim(0, 100)
plt.xlim(0, etod)
plt.savefig(proj_dir + f"health_skill{skill:d}_style{style[0]}.png");
plt.show()

plt.title("Damage per Second",fontsize=24)
plt.plot(time[0:etod], DPS[0:etod])
# plt.plot(time[0:etod], err[0:etod])
plt.text(0, 1.2, f"SAE={SAE}")
# plt.plot(time[0:etod], interr_arr[0:etod])
plt.plot([0,etod],[SP_DPS,SP_DPS])
plt.xlabel('Time (sec)',fontsize=18)
plt.ylabel('Damage per second',fontsize=18)
plt.ylim(0, 1.5)
plt.axvline(150, color="gray", ls="--", label="")
plt.savefig(proj_dir + f"dps_skill{skill:d}_style{style[0]}.png");
plt.show()

plt.plot(time[0:etod],At_enem[0:etod],'k',label='Enemy attack')
plt.title('Enemy Attack',fontsize=24)
plt.xlabel('Time (sec)',fontsize=18)
plt.ylabel('Attack',fontsize=18)
plt.savefig(proj_dir + f"eatk_skill{skill:d}_style{style[0]}.png");
plt.show();

plt.plot(time[0:etod],HP_enem[0:etod],'k',label='HP')
plt.title('Enemy Health',fontsize=24)
plt.xlabel('Time (sec)',fontsize=18)
plt.ylabel('Health',fontsize=18)
plt.show();


174 changes: 174 additions & 0 deletions params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@

import numpy as np
from scipy.integrate import odeint
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy.random as rnd
import pickle

import sim

HP0 = 100
Npts = 6000
time = np.arange(Npts+1)
Enemy0 = [10, 1]
At_char = 1
proj_dir = "./"


# Run a set of simulations, info for each, save to file
N_sim = 100
sk_list = range(1, 11)
st_list = ["conservative", "moderate", "reckless"]
for skill in sk_list:
for style in st_list:
# etod_list = []
# for n in range(N_sim):
# HP_char, At_enem, HP_enem, etod = sim.sim_gameplay(style, skill)
# plt.plot(time[0:etod],HP_char[0:etod],'k',label='HP')
# etod_list.append(etod)
# etod_arr = np.array(etod_list)
HP_arr_arr = np.array([sim.sim_gameplay(style, skill, adj=True)[0] for n in range(N_sim)])
HP_arr = np.mean(HP_arr_arr, axis=0)
enem_arr_arr = np.array([sim.sim_gameplay(style, skill, adj=True)[2] for n in range(N_sim)])
etod_arr = np.array([sim.sim_gameplay(style, skill)[3] for n in range(N_sim)])

np.savetxt(proj_dir+"sim_results/"+f"sim_results_skill{skill}_style{style[0]}_mod.txt", HP_arr.T, fmt="%d")
np.savetxt(proj_dir+"sim_results/"+f"sim_results_skill{skill}_style{style[0]}.txt", etod_arr.T, fmt="%d")
np.savetxt(proj_dir+"sim_results/"+f"HP_results_skill{skill}_style{style[0]}.txt", HP_arr_arr.T, fmt="%d")
np.savetxt(proj_dir+"sim_results/"+f"enem_results_skill{skill}_style{style[0]}.txt", enem_arr_arr.T, fmt="%d")

# Generate a summary plot across skill level, style types
col_list = ["blue", "green", "red"]
lab_list = ["conservative", "moderate", "reckless"]
full_list = []
for i, st in enumerate(st_list):
sub_list = []
for sk in sk_list:
dat_aa = np.loadtxt(proj_dir+"sim_results/"+f"sim_results_skill{sk}_style{st[0]}.txt")
sub_list.append(dat_aa)
full_list.append(sub_list)
full_arr = np.array(full_list)
print(full_arr.shape)
ave_DPS = []
for i, st in enumerate(full_arr):
# print(f)
plt.plot(range(1, 11), st, "x", color=col_list[i])
for sk in st.T:

# plt.plot(range(1,11), sk, "x", color=col_list[i],)
pass
plt.plot(range(1, 11), np.mean(st, axis=1), "-", color=col_list[i], label=lab_list[i]+" playstyle")
ave_DPS.append(100/np.mean(st, axis=1))

plt.legend()
plt.ylabel("Time steps before death")
plt.xlabel("Skill level")
plt.title("Comparison of game time vs. skill level and play style")

print(ave_DPS)

# Generate a summary plot across skill level, style types
col_list = ["blue", "green", "red"]
lab_list = ["conservative", "moderate", "reckless"]
full_list = []
for i, st in enumerate(st_list):
sub_list = []
for sk in sk_list:
dat_aa = np.loadtxt(proj_dir+"sim_results/"+f"HP_results_skill{sk}_style{st[0]}.txt")
sub_list.append(dat_aa)
full_list.append(sub_list)
full_arr_step = np.array(full_list)
print(full_arr_step.shape)
tau_arr = []
gain_arr = []
for i, st in enumerate(full_arr_step):
# print(f)
# plt.plot(st, "x", color=col_list[i])
# print(st.shape)
for j, sk in enumerate(st):
# print(len(sk))
tau_list = []
gain_list = []
for sim in sk.T:

etod = np.where(sim==0)[0][0]
step = np.where(sim<=50)[0][0]
qd = np.where(sim<=25)[0][0]
tau_list.append(qd-step)
DPS = (HP0 - sim[step:etod])/time[step:etod]
alt_etod = full_arr[i, j]
alt_DPS = 100/alt_etod
gain = DPS[-1]-alt_DPS
gain_list.append(gain)
plt.plot(time[:etod-step], DPS[:etod])
# plt.plot(range(1,11), sim, "x", color=col_list[i],)
pass
tau_arr.append(np.mean(tau_list))
gain_arr.append(np.mean(gain_list))
plt.title(f"skill {j+1}, style {lab_list[i][:3]}")
plt.show()
# plt.plot(range(1, 11), np.mean(st, axis=1), "-", color=col_list[i], label=lab_list[i]+" playstyle")
tau_arr = np.array(tau_arr)
gain_arr = np.array(gain_arr)
print("tau", tau_arr)
print("gain", gain_arr)
dat = np.column_stack([tau_arr, gain_arr])
np.savetxt("params.txt", dat)
# plt.legend()
# plt.ylabel("DPS")
# plt.xlabel("Time after step change")
# plt.xlim(0, 100)
# plt.ylim()
# plt.title("Comparison of game time vs. skill level and play style")

gain1 = gain_arr[0:10] #conservative
gain2 = gain_arr[10:20] #moderate
gain3 = gain_arr[20:30] #reckless
tau1 = tau_arr[0:10] #conservative
tau2 = tau_arr[10:20] #moderate
tau3 = tau_arr[20:30] #reckless
plt.plot(sk_list, gain1, label=lab_list[0])
plt.plot(sk_list, gain2, label=lab_list[1])
plt.plot(sk_list, gain3, label=lab_list[2])
plt.legend()
plt.ylabel("Gain $K_p$")
plt.xlabel("Skill")

def line(x, m, b):
return m*x+b
Kp1_fit, covar = curve_fit(line, sk_list, gain1)
Kp2_fit, covar = curve_fit(line, sk_list, gain2)
Kp3_fit, covar = curve_fit(line, sk_list, gain3)
# plt.plot(sk_list, line(sk_list, *Kp1_fit))
# plt.plot(sk_list, line(sk_list, *Kp2_fit))
# plt.plot(sk_list, line(sk_list, *Kp3_fit))

plt.show()
print(Kp1_fit)
print(Kp2_fit)
print(Kp3_fit)

def exp_c(x, c1, c2, offset):
return c1*np.exp(x*c2) + offset
tau1_fit, covar = curve_fit(exp_c, sk_list, tau1)
tau2_fit, covar = curve_fit(exp_c, sk_list, tau2)
tau3_fit, covar = curve_fit(exp_c, sk_list, tau3)

print(tau1_fit)
print(tau2_fit)
print(tau3_fit)



plt.plot(sk_list, tau1, label=lab_list[0])
plt.plot(sk_list, tau2, label=lab_list[1])
plt.plot(sk_list, tau3, label=lab_list[2])
# plt.plot(sk_list, exp_c(sk_list, *tau1_fit))
# plt.plot(sk_list, exp_c(sk_list, *tau2_fit))
# plt.plot(sk_list, exp_c(sk_list, *tau3_fit))

plt.legend()
plt.ylabel("Time constant $\\tau_p$")
plt.xlabel("Skill")
plt.show()
30 changes: 30 additions & 0 deletions params.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
6.185000000000000142e+01 9.110496310522270269e-02
6.135000000000000142e+01 1.147940699589847235e-01
5.800000000000000000e+01 1.198197093070172414e-01
6.820000000000000284e+01 1.526013081822418516e-01
6.665000000000000568e+01 1.582350139619470297e-01
7.190000000000000568e+01 1.700341781992531498e-01
7.979999999999999716e+01 1.788746883719655456e-01
7.879999999999999716e+01 1.855329733205805520e-01
1.056500000000000057e+02 1.902041469940962126e-01
1.228499999999999943e+02 1.682673875464476554e-01
3.400000000000000000e+01 5.366252242736072042e-02
3.454999999999999716e+01 8.786304769087074917e-02
4.395000000000000284e+01 7.382434740133875239e-02
4.589999999999999858e+01 8.687011060051549882e-02
4.304999999999999716e+01 1.898921342488902875e-01
4.400000000000000000e+01 2.042359441643654405e-01
4.900000000000000000e+01 2.136238917251379599e-01
5.135000000000000142e+01 2.888511147237640686e-01
5.454999999999999716e+01 3.117799609850196996e-01
7.390000000000000568e+01 2.596296621685815764e-01
2.269999999999999929e+01 5.027830353079761061e-02
2.794999999999999929e+01 -3.151681375235237774e-03
2.789999999999999858e+01 7.877458372718487700e-02
3.454999999999999716e+01 6.615319001556019263e-02
3.764999999999999858e+01 1.092985999992179269e-01
4.275000000000000000e+01 1.403562012299598427e-01
4.495000000000000284e+01 1.919179507721606448e-01
4.525000000000000000e+01 2.400006823941317202e-01
5.160000000000000142e+01 3.100291448405274042e-01
4.460000000000000142e+01 3.326581837297094557e-01
Loading

0 comments on commit 5d8948f

Please sign in to comment.