diff --git a/day11/common.rs b/day11/common.rs
new file mode 100644
index 0000000..35f2cdc
--- /dev/null
+++ b/day11/common.rs
@@ -0,0 +1,197 @@
+// Copyright 2022 Christian Ulrich
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use std::io;
+
+#[derive(Debug, Clone)]
+enum Operation {
+ Add { arg: u64 },
+ Multiply { arg: u64 },
+ Square,
+}
+
+#[derive(Debug, Clone)]
+pub struct Monkey {
+ items: Vec,
+ operation: Operation,
+ modulus: u64,
+ target_devisible: usize,
+ target_indevisible: usize,
+ item_count: usize,
+}
+
+pub struct Game {
+ monkeys: Vec,
+ divisor: u64,
+}
+
+pub struct Round {
+ monkeys: Vec,
+}
+
+impl Monkey {
+ fn from_stdin() -> Result, &'static str> {
+ const ERROR: &str = "cannot parse monkey";
+ let mut line = String::new();
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if line.len() == 0 {
+ return Ok(None);
+ }
+ if !line.starts_with("Monkey ") {
+ return Err(ERROR);
+ }
+ line.clear();
+
+ // parse starting items
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if !line.starts_with(" Starting items: ") {
+ return Err(ERROR);
+ }
+ let mut items = vec![];
+ for part in line[18..].split(',') {
+ items.push(part.trim().parse::().map_err(|_| ERROR)?);
+ }
+ line.clear();
+
+ // parse operation
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if !line.starts_with(" Operation: new = old ") {
+ return Err(ERROR);
+ }
+ let operation = match line[23..].trim() {
+ "* old" => Operation::Square,
+ arg if { arg.starts_with("+ ") } => Operation::Add {
+ arg: arg[2..].parse().map_err(|_| ERROR)?,
+ },
+ arg if { arg.starts_with("* ") } => Operation::Multiply {
+ arg: arg[2..].parse().map_err(|_| ERROR)?,
+ },
+ _ => return Err(ERROR),
+ };
+ line.clear();
+
+ // parse modulus
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if !line.starts_with(" Test: divisible by ") {
+ return Err(ERROR);
+ }
+ let modulus = line[21..].trim().parse().map_err(|_| ERROR)?;
+ line.clear();
+
+ // parse action if devisible
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if !line.starts_with(" If true: throw to monkey ") {
+ return Err(ERROR);
+ }
+ let target_devisible = line[29..].trim().parse().map_err(|_| ERROR)?;
+ line.clear();
+
+ // parse action if indevisible
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if !line.starts_with(" If false: throw to monkey ") {
+ return Err(ERROR);
+ }
+ let target_indevisible = line[30..].trim().parse().map_err(|_| ERROR)?;
+ line.clear();
+ let _ = io::stdin().read_line(&mut line).map_err(|_| ERROR)?;
+ if line.trim().len() > 0 {
+ return Err(ERROR);
+ }
+ Ok(Some(Self {
+ items: items,
+ operation: operation,
+ modulus: modulus,
+ target_devisible: target_devisible,
+ target_indevisible: target_indevisible,
+ item_count: 0,
+ }))
+ }
+
+ fn throw_item(&mut self, divisor: u64) -> Result, &'static str> {
+ const ERROR: &str = "integer overflow";
+ if self.items.len() == 0 {
+ return Ok(None);
+ }
+ let mut item = self.items.remove(0);
+ match self.operation {
+ Operation::Add { arg } => item = item.checked_add(arg).ok_or(ERROR)?,
+ Operation::Multiply { arg } => item = item.checked_mul(arg).ok_or(ERROR)?,
+ Operation::Square => item = item.checked_mul(item).ok_or(ERROR)?,
+ };
+ item /= divisor;
+ let target = match item % self.modulus {
+ 0 => self.target_devisible,
+ _ => self.target_indevisible,
+ };
+ self.item_count += 1;
+ Ok(Some((item, target)))
+ }
+
+ pub fn add_item(&mut self, item: u64) {
+ self.items.push(item);
+ }
+
+ pub fn items(&self) -> &[u64] {
+ &self.items[..]
+ }
+
+ pub fn item_count(&self) -> usize {
+ self.item_count
+ }
+}
+
+impl Game {
+ pub fn from_stdin(divisor: u64) -> Result {
+ let mut monkeys = vec![];
+ while let Some(monkey) = Monkey::from_stdin()? {
+ monkeys.push(monkey);
+ }
+ Ok(Self {
+ monkeys: monkeys,
+ divisor: divisor,
+ })
+ }
+
+ pub fn monkeys(&self) -> &[Monkey] {
+ &self.monkeys[..]
+ }
+}
+
+impl Iterator for Game {
+ type Item = Result;
+
+ fn next<'a>(&'a mut self) -> Option {
+ for i in 0..self.monkeys.len() {
+ loop {
+ match self.monkeys[i].throw_item(self.divisor) {
+ Ok(None) => break,
+ Ok(Some((item, target))) => {
+ self.monkeys[target].add_item(item);
+ }
+ Err(e) => return Some(Err(e)),
+ }
+ }
+ }
+ Some(Ok(Round {
+ monkeys: self.monkeys.clone(),
+ }))
+ }
+}
+
+impl Round {
+ pub fn monkeys(&self) -> &[Monkey] {
+ &self.monkeys[..]
+ }
+}
diff --git a/day11/input b/day11/input
new file mode 100644
index 0000000..f7e9bf8
--- /dev/null
+++ b/day11/input
@@ -0,0 +1,56 @@
+Monkey 0:
+ Starting items: 98, 70, 75, 80, 84, 89, 55, 98
+ Operation: new = old * 2
+ Test: divisible by 11
+ If true: throw to monkey 1
+ If false: throw to monkey 4
+
+Monkey 1:
+ Starting items: 59
+ Operation: new = old * old
+ Test: divisible by 19
+ If true: throw to monkey 7
+ If false: throw to monkey 3
+
+Monkey 2:
+ Starting items: 77, 95, 54, 65, 89
+ Operation: new = old + 6
+ Test: divisible by 7
+ If true: throw to monkey 0
+ If false: throw to monkey 5
+
+Monkey 3:
+ Starting items: 71, 64, 75
+ Operation: new = old + 2
+ Test: divisible by 17
+ If true: throw to monkey 6
+ If false: throw to monkey 2
+
+Monkey 4:
+ Starting items: 74, 55, 87, 98
+ Operation: new = old * 11
+ Test: divisible by 3
+ If true: throw to monkey 1
+ If false: throw to monkey 7
+
+Monkey 5:
+ Starting items: 90, 98, 85, 52, 91, 60
+ Operation: new = old + 7
+ Test: divisible by 5
+ If true: throw to monkey 0
+ If false: throw to monkey 4
+
+Monkey 6:
+ Starting items: 99, 51
+ Operation: new = old + 1
+ Test: divisible by 13
+ If true: throw to monkey 5
+ If false: throw to monkey 2
+
+Monkey 7:
+ Starting items: 98, 94, 59, 76, 51, 65, 75
+ Operation: new = old + 5
+ Test: divisible by 2
+ If true: throw to monkey 3
+ If false: throw to monkey 6
+
diff --git a/day11/part1.rs b/day11/part1.rs
new file mode 100644
index 0000000..1b387d5
--- /dev/null
+++ b/day11/part1.rs
@@ -0,0 +1,36 @@
+// Copyright 2022 Christian Ulrich
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// usage: ./part1 < input
+
+pub mod common;
+
+use common::{Game, Monkey};
+
+fn main() -> Result<(), &'static str> {
+ let game = Game::from_stdin(3)?;
+ let last_round = game.take(20).last().unwrap();
+ let mut item_counts: Vec<_> = last_round?
+ .monkeys()
+ .iter()
+ .map(Monkey::item_count)
+ .collect();
+ item_counts.sort();
+ println!(
+ "{}",
+ item_counts[item_counts.len() - 1] * item_counts[item_counts.len() - 2]
+ );
+ Ok(())
+}
diff --git a/day11/testinput b/day11/testinput
new file mode 100644
index 0000000..477d33b
--- /dev/null
+++ b/day11/testinput
@@ -0,0 +1,28 @@
+Monkey 0:
+ Starting items: 79, 98
+ Operation: new = old * 19
+ Test: divisible by 23
+ If true: throw to monkey 2
+ If false: throw to monkey 3
+
+Monkey 1:
+ Starting items: 54, 65, 75, 74
+ Operation: new = old + 6
+ Test: divisible by 19
+ If true: throw to monkey 2
+ If false: throw to monkey 0
+
+Monkey 2:
+ Starting items: 79, 60, 97
+ Operation: new = old * old
+ Test: divisible by 13
+ If true: throw to monkey 1
+ If false: throw to monkey 3
+
+Monkey 3:
+ Starting items: 74
+ Operation: new = old + 3
+ Test: divisible by 17
+ If true: throw to monkey 0
+ If false: throw to monkey 1
+