Skip to content

Commit 7a10cd4

Browse files
committed
Started to work on reversi example
1 parent 1476e1a commit 7a10cd4

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

examples/reversi.rs

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
//! Reversi
2+
//!
3+
//! https://en.wikipedia.org/wiki/Reversi
4+
5+
extern crate turtle;
6+
7+
use std::f64::consts::PI;
8+
9+
use turtle::{Turtle, Event, Color};
10+
use turtle::event::{MouseButton};
11+
12+
/// None - empty tile
13+
/// Some(Piece::A) - occupied by piece A
14+
/// Some(Piece::B) - occupied by piece B
15+
///
16+
/// Each array in Board is a row of the board
17+
type Board = [[Option<Piece>; 8]; 8];
18+
19+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20+
enum Piece {
21+
A,
22+
B,
23+
}
24+
25+
impl Piece {
26+
fn other(self) -> Self {
27+
match self {
28+
Piece::A => Piece::B,
29+
Piece::B => Piece::A,
30+
}
31+
}
32+
33+
fn color(self) -> Color {
34+
match self {
35+
Piece::A => "#f44336".into(),
36+
Piece::B => "#2196F3".into(),
37+
}
38+
}
39+
}
40+
41+
#[derive(Debug, Clone)]
42+
struct Dimensions {
43+
pub width: f64,
44+
pub height: f64,
45+
pub rows: usize,
46+
pub cols: usize,
47+
pub tile_width: f64,
48+
pub tile_height: f64,
49+
}
50+
51+
fn main() {
52+
let mut turtle = Turtle::new();
53+
turtle.set_background_color("#B3E5FC");
54+
turtle.set_pen_color("#757575");
55+
turtle.set_pen_size(2.0);
56+
turtle.set_speed(8);
57+
58+
let width = 580.0;
59+
let height = 580.0;
60+
let board: Board = Default::default();
61+
let rows = board.len();
62+
let cols = board[0].len();
63+
64+
// These values are used quite often, so it makes sense to compute them in advance so that
65+
// we don't need to keep repeating ourselves
66+
let dim = Dimensions {
67+
width,
68+
height,
69+
rows,
70+
cols,
71+
tile_width: width / cols as f64,
72+
tile_height: height / rows as f64,
73+
};
74+
75+
turtle.pen_up();
76+
turtle.forward(height / 2.0);
77+
turtle.right(90.0);
78+
turtle.backward(width / 2.0);
79+
turtle.pen_down();
80+
81+
println!("Drawing the board...\n");
82+
draw_board(&mut turtle, &dim);
83+
// Get rid of any events that may have accumulated while drawing
84+
drain_events(&mut turtle);
85+
86+
play_game(&mut turtle, board, &dim);
87+
}
88+
89+
fn draw_board(turtle: &mut Turtle, dim: &Dimensions) {
90+
turtle.forward(dim.width);
91+
for i in 0..dim.rows {
92+
turtle.right((i % 2) as f64 * -180.0 + 90.0);
93+
turtle.pen_up();
94+
turtle.forward(dim.height / dim.rows as f64);
95+
turtle.pen_down();
96+
turtle.right((i % 2) as f64 * -180.0 + 90.0);
97+
turtle.forward(dim.width);
98+
}
99+
100+
turtle.left(90.0);
101+
turtle.forward(dim.height);
102+
for i in 0..dim.cols {
103+
turtle.left((i % 2) as f64 * -180.0 + 90.0);
104+
turtle.pen_up();
105+
turtle.forward(dim.width / dim.cols as f64);
106+
turtle.pen_down();
107+
turtle.left((i % 2) as f64 * -180.0 + 90.0);
108+
turtle.forward(dim.height);
109+
}
110+
}
111+
112+
fn play_game(turtle: &mut Turtle, mut board: Board, dim: &Dimensions) {
113+
println!("Click on a tile to make a move.");
114+
turtle.set_speed(9);
115+
116+
let mut mouse = [0.0, 0.0];
117+
let mut current = Piece::A;
118+
loop {
119+
let event = turtle.poll_event();
120+
// Sometimes it is more convenient to use `if let` instead of `match`. In this case, it's
121+
// really up to your personal preference. We chose to demonstrate what `if let` would look
122+
// like if used for this code.
123+
if let Some(Event::MouseMove {x, y}) = event {
124+
mouse = [x, y];
125+
}
126+
else if let Some(Event::MouseButtonReleased(MouseButton::Left)) = event {
127+
// Figure out which row and column was clicked
128+
// If these formulas seem unclear, try some example values to see what you get
129+
let row = ((1.0 - (mouse[1] + dim.height/2.0) / dim.height) * dim.rows as f64).floor() as isize;
130+
let col = ((mouse[0] + dim.width/2.0) / dim.width * dim.cols as f64).floor() as isize;
131+
132+
if row >= 0 && row < dim.rows as isize && col >= 0 && col < dim.cols as isize
133+
&& board[row as usize][col as usize].is_none() {
134+
let row = row as usize;
135+
let col = col as usize;
136+
board[row][col] = Some(current);
137+
//TODO: Implement rules checking, winning, etc.
138+
139+
move_to_tile(turtle, row, col, &dim);
140+
draw_piece(turtle, current, &dim);
141+
current = current.other();
142+
143+
// Get rid of any events that may have accumulated while drawing
144+
drain_events(turtle);
145+
}
146+
}
147+
}
148+
}
149+
150+
/// Moves to the center of the given tile
151+
fn move_to_tile(turtle: &mut Turtle, row: usize, col: usize, dim: &Dimensions) {
152+
let x = col as f64 / dim.cols as f64 * dim.width + dim.tile_width / 2.0 - dim.width / 2.0;
153+
let y = -(row as f64) / dim.rows as f64 * dim.height - dim.tile_height / 2.0 + dim.height / 2.0;
154+
155+
turtle.pen_up();
156+
157+
turtle.turn_towards([x, y]);
158+
turtle.go_to([x, y]);
159+
turtle.set_heading(90.0);
160+
161+
turtle.pen_down();
162+
}
163+
164+
/// Draws the given piece
165+
fn draw_piece(turtle: &mut Turtle, piece: Piece, dim: &Dimensions) {
166+
let radius = dim.tile_width.min(dim.tile_height) / 2.0 * 0.9;
167+
168+
turtle.set_fill_color(piece.color());
169+
turtle.pen_up();
170+
turtle.begin_fill();
171+
172+
turtle.forward(radius);
173+
turtle.right(90.0);
174+
circle(turtle, radius);
175+
176+
turtle.end_fill();
177+
turtle.pen_down();
178+
}
179+
180+
fn circle(turtle: &mut Turtle, radius: f64) {
181+
let degrees = 180.0;
182+
183+
let circumference = 2.0*PI*radius;
184+
let step = circumference / degrees;
185+
let rotation = 360.0 / degrees;
186+
187+
for _ in 0..degrees as i32 {
188+
turtle.forward(step);
189+
turtle.right(rotation);
190+
}
191+
}
192+
193+
/// Clear out all events that may have accumulated
194+
fn drain_events(turtle: &mut Turtle) {
195+
while let Some(_) = turtle.poll_event() {}
196+
}

0 commit comments

Comments
 (0)