Model animal conflict in R with the hawk-dove game: the mixed evolutionarily stable strategy, the invasion criterion, and replicator dynamics converging to it.
Author
Tidy Ecology
Published
2026-08-05
When two animals contest a resource, the best move depends on what everyone else is doing. Escalate against a peaceful rival and you win; escalate against another fighter and you both get hurt. There is no single best strategy, only a best strategy given the population. This is what evolutionary game theory formalises, and the hawk-dove game of Maynard Smith and Price (1973) is its founding example. This post builds the game in base R, finds its evolutionarily stable strategy, and watches replicator dynamics settle onto it.
The game
Two contestants meet over a resource worth V. A hawk always escalates; a dove displays and retreats if the other escalates. Hawk against dove: the hawk takes V, the dove gets nothing. Dove against dove: they share, V/2 each. Hawk against hawk: they fight, and the loser pays an injury cost C, so each expects (V - C) / 2. The interesting case is V < C: fighting costs more than the prize.
V <-2; C <-5hawk_pay <-function(p) p * ((V - C) /2) + (1- p) * V # payoff to a hawk when hawks are at frequency pdove_pay <-function(p) p *0+ (1- p) * (V /2)pstar <- V / Ccat(sprintf("mixed ESS: fraction of hawks p* = V/C = %.3f\n", pstar))
At a hawk frequency of V/C = 0.4, hawks and doves earn exactly the same, 0.6. That equality is the signature of a mixed evolutionarily stable strategy: when neither type does better, neither can spread, and the population sits still.
The invasion criterion
An ESS is a strategy that, once common, cannot be invaded by any rare alternative. The test is direct: compare the payoffs away from p*.
cat(sprintf("hawks rare (p=0.2): hawk %.3f vs dove %.3f -> hawks do better\n", hawk_pay(0.2), dove_pay(0.2)))
hawks rare (p=0.2): hawk 1.300 vs dove 0.800 -> hawks do better
cat(sprintf("hawks common (p=0.6): hawk %.3f vs dove %.3f -> doves do better\n", hawk_pay(0.6), dove_pay(0.6)))
hawks common (p=0.6): hawk -0.100 vs dove 0.400 -> doves do better
When hawks are rare they mostly meet doves and win easily, so they invade. When hawks are common they mostly meet each other and pay the injury cost (the hawk payoff even goes negative, -0.1), so doves invade instead. Each type is favoured when rare: this is negative frequency-dependent selection, the same balancing force that lets a rare strategy hold its place. Neither pure hawk nor pure dove is stable; only the 0.4 mix is.
Dynamics: getting there
The invasion argument says the mix is stable, but does a population actually reach it? The replicator equation answers this by letting each strategy grow in proportion to how far its payoff beats the population average.
replicate_hd <-function(p0, dt =0.01, tmax =60) { p <- p0; trace <-numeric(tmax / dt)for (i inseq_along(trace)) { wbar <- p *hawk_pay(p) + (1- p) *dove_pay(p) p <- p + dt * p * (hawk_pay(p) - wbar) trace[i] <- p } trace}tr <-replicate_hd(0.05)cat(sprintf("starting from 5%% hawks, the population converges to %.3f (ESS = %.3f)\n",tail(tr, 1), pstar))
starting from 5% hawks, the population converges to 0.400 (ESS = 0.400)
From almost all doves, hawks spread until they hit 0.4 and then stop. The ESS is not just uninvadable; here it is also an attractor, the resting point the dynamics find on their own.
library(ggplot2)p <-seq(0, 1, 0.01)d <-rbind(data.frame(p = p, pay =hawk_pay(p), type ="hawk"),data.frame(p = p, pay =dove_pay(p), type ="dove"))ggplot(d, aes(p, pay, colour = type)) +geom_vline(xintercept = pstar, linetype ="dashed", colour ="#93a87f") +geom_line(linewidth =0.9) +scale_colour_manual(values =c(hawk ="#b5534e", dove ="#275139")) +annotate("text", x = pstar +0.02, y =-0.3, label ="ESS 0.4", colour ="#46604a", size =3.4, hjust =0) +labs(x ="Frequency of hawks", y ="Expected payoff", colour =NULL) +theme_minimal(base_size =12)
Figure 1: Payoffs to hawks and doves as the hawk frequency changes. They cross at the ESS (0.4): below it hawks win and spread, above it doves win, so the mix is stable.
An honest limit
The whole prediction rests on the numbers V and C, and those are assumed, not measured. The ESS is V/C exactly, so halving the injury cost moves the stable mix from 0.4 to something quite different, and in real animals the payoff of a fight is hard to put on the same scale as the value of the resource. The game also treats every contest as symmetric and anonymous; real disputes turn on who arrived first, who is larger, and who owns the territory, which changes the stable strategy entirely. The hawk-dove game explains why mixed populations of bold and cautious individuals persist; turning it into a quantitative forecast for a particular species needs payoffs that field data rarely provide. The checking post works through this and the trouble with finite populations.
Maynard Smith J, Price GR 1973. Nature 246(5427):15-18 (10.1038/246015a0)
Maynard Smith J 1982. Evolution and the Theory of Games. Cambridge University Press. ISBN 978-0521288842
Hofbauer J, Sigmund K 2003. Bulletin of the American Mathematical Society 40(4):479-519 (10.1090/S0273-0979-03-00988-1)
Newsletter
Get new tutorials by email
New R and QGIS tutorials for ecologists, straight to your inbox. No spam; unsubscribe anytime.
By subscribing you agree to receive these emails and confirm your address once. See the privacy policy.
Source Code
---title: "The hawk-dove game and the ESS"description: "Model animal conflict in R with the hawk-dove game: the mixed evolutionarily stable strategy, the invasion criterion, and replicator dynamics converging to it."date: "2026-08-05 09:00"categories: [evolutionary ecology, evolutionary game theory, natural selection, R, ecology tutorial]image: thumbnail.pngimage-alt: "Payoff to hawks and to doves plotted against the frequency of hawks, crossing at the evolutionarily stable mix"---When two animals contest a resource, the best move depends on what everyone else is doing. Escalate against a peaceful rival and you win; escalate against another fighter and you both get hurt. There is no single best strategy, only a best strategy given the population. This is what evolutionary game theory formalises, and the hawk-dove game of Maynard Smith and Price (1973) is its founding example. This post builds the game in base R, finds its evolutionarily stable strategy, and watches replicator dynamics settle onto it.## The gameTwo contestants meet over a resource worth `V`. A hawk always escalates; a dove displays and retreats if the other escalates. Hawk against dove: the hawk takes `V`, the dove gets nothing. Dove against dove: they share, `V/2` each. Hawk against hawk: they fight, and the loser pays an injury cost `C`, so each expects `(V - C) / 2`. The interesting case is `V < C`: fighting costs more than the prize.```{r}#| label: setupV <-2; C <-5hawk_pay <-function(p) p * ((V - C) /2) + (1- p) * V # payoff to a hawk when hawks are at frequency pdove_pay <-function(p) p *0+ (1- p) * (V /2)pstar <- V / Ccat(sprintf("mixed ESS: fraction of hawks p* = V/C = %.3f\n", pstar))cat(sprintf("at p*, hawk payoff = %.3f, dove payoff = %.3f\n", hawk_pay(pstar), dove_pay(pstar)))```At a hawk frequency of `V/C = 0.4`, hawks and doves earn exactly the same, 0.6. That equality is the signature of a mixed evolutionarily stable strategy: when neither type does better, neither can spread, and the population sits still.## The invasion criterionAn ESS is a strategy that, once common, cannot be invaded by any rare alternative. The test is direct: compare the payoffs away from `p*`.```{r}#| label: invasioncat(sprintf("hawks rare (p=0.2): hawk %.3f vs dove %.3f -> hawks do better\n", hawk_pay(0.2), dove_pay(0.2)))cat(sprintf("hawks common (p=0.6): hawk %.3f vs dove %.3f -> doves do better\n", hawk_pay(0.6), dove_pay(0.6)))```When hawks are rare they mostly meet doves and win easily, so they invade. When hawks are common they mostly meet each other and pay the injury cost (the hawk payoff even goes negative, -0.1), so doves invade instead. Each type is favoured when rare: this is negative frequency-dependent selection, the same balancing force that lets a [rare strategy hold its place](../rare-species-advantage-and-coexistence/). Neither pure hawk nor pure dove is stable; only the `0.4` mix is.## Dynamics: getting thereThe invasion argument says the mix is stable, but does a population actually reach it? The replicator equation answers this by letting each strategy grow in proportion to how far its payoff beats the population average.```{r}#| label: replicatorreplicate_hd <-function(p0, dt =0.01, tmax =60) { p <- p0; trace <-numeric(tmax / dt)for (i inseq_along(trace)) { wbar <- p *hawk_pay(p) + (1- p) *dove_pay(p) p <- p + dt * p * (hawk_pay(p) - wbar) trace[i] <- p } trace}tr <-replicate_hd(0.05)cat(sprintf("starting from 5%% hawks, the population converges to %.3f (ESS = %.3f)\n",tail(tr, 1), pstar))```From almost all doves, hawks spread until they hit 0.4 and then stop. The ESS is not just uninvadable; here it is also an attractor, the resting point the dynamics find on their own.```{r}#| label: fig-payoffs#| fig-cap: "Payoffs to hawks and doves as the hawk frequency changes. They cross at the ESS (0.4): below it hawks win and spread, above it doves win, so the mix is stable."#| fig-alt: "Two lines, hawk payoff falling and dove payoff falling more slowly, crossing at hawk frequency 0.4."library(ggplot2)p <-seq(0, 1, 0.01)d <-rbind(data.frame(p = p, pay =hawk_pay(p), type ="hawk"),data.frame(p = p, pay =dove_pay(p), type ="dove"))ggplot(d, aes(p, pay, colour = type)) +geom_vline(xintercept = pstar, linetype ="dashed", colour ="#93a87f") +geom_line(linewidth =0.9) +scale_colour_manual(values =c(hawk ="#b5534e", dove ="#275139")) +annotate("text", x = pstar +0.02, y =-0.3, label ="ESS 0.4", colour ="#46604a", size =3.4, hjust =0) +labs(x ="Frequency of hawks", y ="Expected payoff", colour =NULL) +theme_minimal(base_size =12)```## An honest limitThe whole prediction rests on the numbers `V` and `C`, and those are assumed, not measured. The ESS is `V/C` exactly, so halving the injury cost moves the stable mix from 0.4 to something quite different, and in real animals the payoff of a fight is hard to put on the same scale as the value of the resource. The game also treats every contest as symmetric and anonymous; real disputes turn on who arrived first, who is larger, and who owns the territory, which changes the stable strategy entirely. The hawk-dove game explains why mixed populations of bold and cautious individuals persist; turning it into a quantitative forecast for a particular species needs payoffs that field data rarely provide. The [checking post](../checking-a-game-theory-model/) works through this and the trouble with finite populations.## Related tutorials- [The replicator equation](../the-replicator-equation/)- [Sex ratio evolution and the ESS](../sex-ratio-evolution/)- [Evolutionary games in finite populations](../games-in-finite-populations/)- [Rare species advantage and coexistence](../rare-species-advantage-and-coexistence/)## ReferencesMaynard Smith J, Price GR 1973. Nature 246(5427):15-18 (10.1038/246015a0)Maynard Smith J 1982. Evolution and the Theory of Games. Cambridge University Press. ISBN 978-0521288842Hofbauer J, Sigmund K 2003. Bulletin of the American Mathematical Society 40(4):479-519 (10.1090/S0273-0979-03-00988-1)