I've just released MObject. It's a tiny library to construct objects and object trees for mocking and stubbing in Python.
Go check it out!
Go check it out!
# gameoflife.py """ Simple Game of Life implementation for a fixed size board that wraps at the edges. All cells, both alive and dead are part of the representation. """ ALIVE = 1 DEAD = 0 class GameAnalyzer(object): directions = ((-1,-1), (0,-1), (1,-1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)) def __init__(self, board): self.board = board def cell_at(self, x, y): y_wrapped = y % len(self.board) x_wrapped = x % len(self.board[y_wrapped]) return self.board[y_wrapped][x_wrapped] def neighbour_count(self, x, y): return sum([self.cell_at(x + dx, y + dy) for dx, dy in self.directions]) def judge_cell(self, x, y): rules = (DEAD, DEAD, self.cell_at(x, y), ALIVE, DEAD, DEAD, DEAD, DEAD, DEAD) neighbour_count = self.neighbour_count(x, y) return rules[neighbour_count] def evolve(board): a = GameAnalyzer(board) return [[a.judge_cell(x, y) for x, _ in enumerate(row)] for y, row in enumerate(board)]
# gameoflife_test.py from gameoflife import evolve, GameAnalyzer, ALIVE as x, DEAD as o from nose.tools import assert_equal def test_empty_board_remains_empty(): assert_equal(evolve([[o, o, o], [o, o, o], [o, o, o]]), [[o, o, o], [o, o, o], [o, o, o]]) def test_single_cell_dies(): assert_equal(evolve([[o, o, o], [o, x, o], [o, o, o]]), [[o, o, o], [o, o, o], [o, o, o]]) def test_stable_formation_remains(): assert_equal(evolve([[o, o, o], [o, x, x], [o, x, x]]), [[o, o, o], [o, x, x], [o, x, x]]) def test_blinker_blinks(): assert_equal(evolve([[o, o, o, o, o], [o, o, o, o, o], [o, x, x, x, o], [o, o, o, o, o], [o, o, o, o, o]]), [[o, o, o, o, o], [o, o, x, o, o], [o, o, x, o, o], [o, o, x, o, o], [o, o, o, o, o]]) assert_equal(evolve([[o, o, o, o, o], [o, o, x, o, o], [o, o, x, o, o], [o, o, x, o, o], [o, o, o, o, o]]), [[o, o, o, o, o], [o, o, o, o, o], [o, x, x, x, o], [o, o, o, o, o], [o, o, o, o, o]]) def test_board_wraps_around(): # South -> North assert_equal(evolve([[o, o, o, o, o], [o, o, o, o, o], [o, o, o, o, o], [o, o, o, o, o], [o, x, x, x, o]]), [[o, o, x, o, o], [o, o, o, o, o], [o, o, o, o, o], [o, o, x, o, o], [o, o, x, o, o]]) # North -> South assert_equal(evolve([[o, x, x, x, o], [o, o, o, o, o], [o, o, o, o, o], [o, o, o, o, o], [o, o, o, o, o]]), [[o, o, x, o, o], [o, o, x, o, o], [o, o, o, o, o], [o, o, o, o, o], [o, o, x, o, o]]) # East -> West assert_equal(evolve([[o, o, o, o, o], [o, o, o, o, x], [o, o, o, o, x], [o, o, o, o, x], [o, o, o, o, o]]), [[o, o, o, o, o], [o, o, o, o, o], [x, o, o, x, x], [o, o, o, o, o], [o, o, o, o, o]]) # East -> West assert_equal(evolve([[o, o, o, o, o], [x, o, o, o, o], [x, o, o, o, o], [x, o, o, o, o], [o, o, o, o, o]]), [[o, o, o, o, o], [o, o, o, o, o], [x, x, o, o, x], [o, o, o, o, o], [o, o, o, o, o]]) def check_neighbour_count(board, at, expected): (x, y) = at a = GameAnalyzer(board) assert_equal(a.neighbour_count(x, y), expected) def test_correct_neighbour_count_to_the_right(): check_neighbour_count([[o, o, o], [o, o, x], [o, o, o]], (1, 1), expected=1) def test_correct_neighbour_count_to_the_right_and_right_down(): check_neighbour_count([[o, o, o], [o, o, x], [o, o, x]], (1, 1), expected=2) def test_zero_neighbour_count_with_no_cells(): check_neighbour_count([[o, o, o], [o, o, o], [o, o, o]], (1, 1), expected=0) def test_correct_neighbour_count_with_alive_cell_on_the_board_but_no_neighbours(): check_neighbour_count([[o, o, o], [o, x, o], [o, o, o]], (1, 1), expected=0) def test_correct_neighbour_count_with_alive_cells_in_all_neighbour_positions(): check_neighbour_count([[x, x, x], [x, x, x], [x, x, x]], (1, 1), expected=8) def test_correct_neighbour_count_for_corner_cell(): check_neighbour_count([[o, o, o], [o, x, x], [o, x, o]], (2, 2), expected=3)Representing the whole board makes the tests easy to read (no additional comments needed, both the existing and expected board are all fleshed out), but input data may be on the large size.
# gameoflife2.py """ Game of Life implementation for an expanding game. Live cells are represented as x and y tuples stored in a set. """ class Game(object): directions = ((-1,-1), (0,-1), (1,-1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)) def __init__(self, live_cells): self.live_cells = live_cells def next_generation(self): return set.union(self.survivors(), self.births()) def births(self): return set([(x, y) for x, y in self.birth_candidates() if len(self.live_neighbours(x, y)) == 3]) def birth_candidates(self): return set.difference(self.all_neighbours(), self.live_cells) def all_neighbours(self): neighbours = [self.neighbours(x, y) for x, y in self.live_cells] or [set()] return set.union(*neighbours) def survivors(self): return set([(x, y) for x, y in self.live_cells if len(self.live_neighbours(x, y)) in (2, 3)]) def live_neighbours(self, x, y): return set.intersection(self.live_cells, self.neighbours(x, y)) def neighbours(self, x, y): return set([(x + dx, y + dy) for dx, dy in self.directions]) def game_generator(initial_state): state = initial_state while True: state = Game(state).next_generation() yield state
# gameoflife2_test.py from gameoflife2 import game_generator, Game def test_game_with_no_live_cells_remains_dead(): assert game_generator(set()).next() == set() def test_a_single_live_cell_dies(): game = game_generator(set([(1, 1)])) assert game.next() == set() def test_stable_formation_remains(): """ xxo xxo xxo -> xxo ooo ooo """ stable = set([(0, 0), (0, 1), (1, 0), (1, 1)]) game = game_generator(stable) assert game.next() == stable def test_blinker_blinks(): """ ooo oxo ooo xxx -> oxo -> xxx ooo oxo ooo """ game = game_generator(set([(0, 1), (1, 1), (2, 1)])) assert game.next() == set([(1, 0), (1, 1), (1, 2)]) assert game.next() == set([(0, 1), (1, 1), (2, 1)]) def test_game_plan_expands(): """ oxo xxx oxo ooo -> oxo ooo ooo """ game = game_generator(set([(0, 0), (1, 0), (2, 0)])) assert game.next() == set([(1,-1), (1, 0), (1, 1)]) def test_Game_survivors_live_cell_with_two_and_three_neighbours_survive(): """ xxo xxo xxo -survivors-> oox oxo oxo """ state = set([(0, 0), (0, 1), (1, 0), (1, 1), (1, 2)]) assert Game(state).survivors() == set([(0, 0), (1, 0), (1, 2)]) def test_Game_births_dead_cell_with_three_neighbours_come_alive(): """ oxo ooo oxo -births-> xox oxo ooo """ state = set([(1, 0), (1, 1), (1, 2)]) assert Game(state).births() == set([(0, 1), (2, 1)]) def test_Game_birth_candidates_all_dead_cells_with_with_live_neighbour(): """ ooo ooo ooo -birth_candidates-> xxx oxo xox """ state = set([(1, 2)]) assert Game(state).birth_candidates() == set([(0, 1), (1, 1), (2, 1), (0, 2), (2, 2), (0, 3), (1, 3), (2, 3)]) def test_Game_live_neighbours_counts_correctly(): state = set([(0, 0), (0, 1), (1, 0)]) game = Game(state) assert game.live_neighbours(0, 0) == set([(0, 1), (1, 0)]) assert game.live_neighbours(1, 1) == set([(0, 0), (0, 1), (1, 0)])
CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;CREATE USER 'sonar' IDENTIFIED BY 'sonar';GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar';GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar';FLUSH PRIVILEGES;
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>datalogger</groupId> <artifactId>DataLogger</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>DataLogger</name> <url>http://maven.apache.org</url> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.7.2</version> <configuration> <test>**/*.java</test> </configuration> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.5.10.201208310627</version> <executions> <execution> <id>jacoco-initialize</id> <goals> <goal>prepare-agent</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.4</version> <executions> <execution> <goals> <goal>compile</goal> <!-- use this goal to weave all your main classes --> <goal>test-compile</goal> <!-- use this goal to weave all your test classes --> </goals> </execution> </executions> <configuration> <complianceLevel>1.6</complianceLevel> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>sonar-maven-plugin</artifactId> <version>2.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.7</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <artifactSet> <excludes> <exclude>junit:junit</exclude> <exclude>org.aspectj:aspectjrt</exclude> <exclude>org.slf4j:slf4j-simple</exclude> </excludes> </artifactSet> </configuration> </execution> </executions> </plugin> </plugins> </build> <properties> <coverage.reports.dir>${basedir}/target/coverage-reports</coverage.reports.dir> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis> </properties> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.6.4</version> </dependency> </dependencies> </project>