Files
chatgpt/chatgpt.exs
2026-01-06 14:11:06 +01:00

164 lines
5.0 KiB
Elixir

Mix.install([
{:jason, "~> 1.4"},
{:matplotex, "~> 0.4.71"}
])
defmodule ZombieApocalypse do
@moduledoc """
Simulation zombie complète.
- Chaque zombie a un niveau de faim.
- Faim augmente de 5 chaque heure.
- Si un zombie mange un humain, sa faim revient à 0 et l'humain devient un zombie.
- Certains zombies peuvent mourir.
- Sauvegarde JSON à chaque heure.
- Affichage dans le terminal avec pourcentages.
- Génération graphique final avec Matplotex.
"""
@state_file "states.json"
# =====================================
# Démarrage de la simulation
# =====================================
def start(humans \\ 10, zombies \\ 3, max_hours \\ 100) do
File.write!(@state_file, "[]")
IO.puts("🧟 Lancement de la simulation...")
zombie_list = for _ <- 1..max(zombies, 0), do: 0
loop(0, humans, zombie_list, max_hours, humans, zombies)
# Génération graphique
plot_final()
IO.puts("✅ Simulation terminée. JSON et graphique générés (zombie_final.png).")
end
# =====================================
# Boucle principale
# =====================================
defp loop(hour, humans, zombie_list, max_hours, initial_humans, initial_zombies)
when hour < max_hours do
state = %{
hour: hour,
humans: humans,
zombies: length(zombie_list),
timestamp: DateTime.utc_now()
}
append_state(state)
percent_humans =
if initial_humans > 0, do: humans / initial_humans * 100, else: 0
percent_zombies =
if initial_zombies > 0, do: length(zombie_list) / initial_zombies * 100, else: 0
IO.puts(
"Heure #{hour} : Humains = #{humans} (#{Float.round(percent_humans, 1)}%), " <>
"Zombies = #{length(zombie_list)} (#{Float.round(percent_zombies, 1)}%)"
)
cond do
humans <= 0 or length(zombie_list) == 0 ->
{humans, zombie_list}
true ->
{new_humans, new_zombies} = simulate_hour(humans, zombie_list)
loop(hour + 1, new_humans, new_zombies, max_hours, initial_humans, initial_zombies)
end
end
defp loop(_, humans, zombie_list, _, _, _), do: {humans, zombie_list}
# =====================================
# Simulation d'une heure
# =====================================
defp simulate_hour(humans, zombie_list) do
new_zombie_list = Enum.map(zombie_list, &(&1 + 5))
{remaining_humans, zombies_after_hour} =
Enum.reduce(new_zombie_list, {humans, []}, fn hunger, {hum_left, acc} ->
if hum_left > 0 and :rand.uniform() <= 0.4 + hunger / 100 do
# zombie mange humain → nouveau zombie
{hum_left - 1, [0, 0 | acc]}
else
{hum_left, [hunger | acc]}
end
end)
# Certains zombies peuvent mourir
killed = Enum.count(zombies_after_hour, fn _ -> :rand.uniform() <= 0.15 end)
final_zombies = Enum.drop(zombies_after_hour, killed)
{remaining_humans, final_zombies}
end
# =====================================
# Sauvegarde JSON
# =====================================
defp append_state(state) do
states =
File.read!(@state_file)
|> Jason.decode!()
File.write!(@state_file, Jason.encode!(states ++ [state], pretty: false))
end
# =====================================
# Graphique final
# =====================================
defp plot_final do
states =
File.read!(@state_file)
|> Jason.decode!()
humans = Enum.map(states, & &1["humans"]) |> Enum.filter(&is_number/1)
zombies = Enum.map(states, & &1["zombies"]) |> Enum.filter(&is_number/1)
hours = Enum.map(states, & &1["hour"]) |> Enum.filter(&is_number/1)
if length(hours) > 0 and length(humans) == length(hours) and length(zombies) == length(hours) do
infection_rate =
if length(humans) >= 2 do
humans
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [prev, next] -> prev - next end)
else
[]
end
inf_hours = Enum.drop(hours, 1)
fig = Matplotex.plot(hours, humans, color: "blue", label: "Humains")
fig = Matplotex.plot(fig, hours, zombies, color: "red", label: "Zombies")
if infection_rate != [] and length(inf_hours) == length(infection_rate) do
fig =
Matplotex.plot(fig, inf_hours, infection_rate,
color: "green",
label: "Vélocité Infection"
)
end
fig_opts = %{figsize: {8, 5}}
fig = Matplotex.figure(fig, fig_opts)
fig = Matplotex.set_title(fig, "Simulation Zombie Apocalypse")
fig = Matplotex.set_xlabel(fig, "Heure")
fig = Matplotex.set_ylabel(fig, "Population / Infection rate")
svg = Matplotex.show(fig)
File.write!("zombie_final.svg", svg)
System.cmd("rsvg-convert", ["zombie_final.svg", "-o", "zombie_final.png"])
IO.puts("🖼️ Graphique généré : zombie_final.png")
else
IO.puts("⚠️ Données insuffisantes pour tracer le graphique.")
end
end
end
# =====================================
# Lancement
# =====================================
ZombieApocalypse.start(10_000_000, 3, 100)