jag

2048_rust

public

Small 2048 game in Rust

Star0
Watch0
494cb9caebb7c809a51c520546e8d2550105f2f7
1
ssh://git@git.jaglekon.de:30/jag/2048_rust.git
src/main.rsRust212 lines5.1 KB
1
use std::io::{self, Write};
2
use std::io::{Read, stdin};
3
use std::os::unix::io::AsRawFd;
4
use termios::*;
5
6
#[derive(Debug, PartialEq)]
7
enum Direction {
8
    Up,
9
    Down,
10
    Right,
11
    Left,
12
    None,
13
}
14
15
fn print_field(field: [[u16; 4]; 4]) {
16
    println!("┏━━━━┯━━━━┯━━━━┯━━━━┓");
17
18
    for i in 0..field.len() {
19
        print!("┃");
20
21
        for j in 0..field.len() {
22
            match field[i][j] {
23
                0 => print!("    "),
24
                n => print!("{:4}", n),
25
            };
26
27
            match j {
28
                3 => println!("┃"),
29
                _  => print!("│")
30
            };
31
32
        }
33
        //print!("\x1b[D┃\n┃    │    │    │    ┃\n");
34
35
        if i != 3 {
36
            println!("┠────┼────┼────┼────┨");
37
        }
38
    }
39
40
    println!("┗━━━━┷━━━━┷━━━━┷━━━━┛");
41
42
    io::stdout().flush().unwrap();
43
}
44
45
fn move_field(direction: Direction, field: [[u16; 4]; 4]) -> [[u16; 4]; 4] {
46
    if direction == Direction::None {
47
        return field;
48
    }
49
50
    let mut new_field = field;
51
52
    for i in 0..field.len() {
53
        let mut lock = false;
54
        for j in 1..field.len() {
55
            for k in (1..=j).rev() {
56
                let this = match direction {
57
                    Direction::Up => (k, i),
58
                    Direction::Down => (4 - k - 1, i),
59
                    Direction::Right => (i, 4 - k - 1),
60
                    Direction::Left => (i, k),
61
                    _ => (i, k),
62
                };
63
                let next = match direction {
64
                    Direction::Up => (k - 1, i),
65
                    Direction::Down => (4 - k, i),
66
                    Direction::Right => (i, 4 - k),
67
                    Direction::Left => (i, k - 1),
68
                    _ => (i, k),
69
                };
70
71
                if new_field[this.0][this.1] == 0 {
72
                    break;
73
                }
74
75
                if new_field[this.0][this.1] == new_field[next.0][next.1] {
76
                    if lock {
77
                        lock = false;
78
                        break;
79
                    }
80
                    new_field[this.0][this.1] = 0;
81
                    new_field[next.0][next.1] *= 2;
82
                    lock = true;
83
                    break;
84
                } else if new_field[next.0][next.1] == 0 {
85
                    new_field[next.0][next.1] = new_field[this.0][this.1];
86
                    new_field[this.0][this.1] = 0;
87
                }
88
            }
89
        }
90
    }
91
    new_field
92
}
93
94
fn make_rand_num(field: &mut [[u16; 4]; 4]) {
95
    let what_value = rand::random_range(0..10);
96
97
    let mut coord = rand::random_range(0..16);
98
99
    while field[coord / 4][coord % 4] != 0 {
100
        coord = rand::random_range(0..16);
101
    }
102
103
    field[coord / 4][coord % 4] = match what_value {
104
        0 => 4,
105
        _ => 2,
106
    }
107
}
108
109
fn field_has_empty(field: [[u16; 4]; 4]) -> bool {
110
    for i in 0..field.len() {
111
        for j in 0..field.len() {
112
            if field[i][j] == 0 {
113
                return true;
114
            }
115
        }
116
    }
117
    false
118
}
119
120
fn has_lost(field: [[u16; 4]; 4]) -> bool {
121
    if field_has_empty(field) {
122
        return false;
123
    }
124
125
    for i in 0..field.len() {
126
        for j in 0..field.len() {
127
            if i > 0 && field[i][j] == field[i - 1][j] {
128
                return false;
129
            }
130
131
            if j > 0 && field[i][j] == field[i][j - 1] {
132
                return false;
133
            }
134
135
            if i < 3 && field[i][j] == field[i + 1][j] {
136
                return false;
137
            }
138
139
            if j < 3 && field[i][j] == field[i][j + 1] {
140
                return false;
141
            }
142
        }
143
    }
144
145
    true
146
}
147
148
fn main() {
149
    let fd = stdin().as_raw_fd();
150
151
    let old = Termios::from_fd(fd).unwrap();
152
    let mut new = old.clone();
153
154
    new.c_lflag &= !(ECHO | ICANON);
155
    new.c_cc[VMIN] = 1;
156
    new.c_cc[VTIME] = 0;
157
158
    tcsetattr(fd, TCSANOW, &new).unwrap();
159
160
    let mut field: [[u16; 4]; 4] = [[0; 4]; 4];
161
162
    for _ in 0..2 {
163
        make_rand_num(&mut field);
164
    };
165
166
    let mut stdin = stdin();
167
    let mut buf = [0u8; 10];
168
169
    print!("\x1b[?25l\x1b[?1049h\x1b[2J\x1b[H");
170
    io::stdout().flush().unwrap();
171
172
    loop {
173
        print!("\x1b[1;1H");
174
        print_field(field);
175
176
        let n = stdin.read(&mut buf).unwrap();
177
178
        if n > 0 && (buf[0] == b'q' || buf[0] == b'Q') {
179
            break;
180
        }
181
182
        if n == 3 && buf[0] == 0x1b && buf[1] == 0x5b {
183
            let direction: Direction = match buf[2] {
184
                0x41 => Direction::Up,
185
                0x42 => Direction::Down,
186
                0x43 => Direction::Right,
187
                0x44 => Direction::Left,
188
                _ => Direction::None,
189
            };
190
191
            let tmp = move_field(direction, field);
192
193
            if tmp != field {
194
                field = tmp;
195
196
                if field_has_empty(field) {
197
                    make_rand_num(&mut field);
198
                }
199
            }
200
201
            if has_lost(field) {
202
                break;
203
            }
204
        }
205
    }
206
207
    print!("\x1b[?1049l\x1b[?25h");
208
    print_field(field);
209
    io::stdout().flush().unwrap();
210
211
    tcsetattr(fd, TCSANOW, &old).unwrap();
212
}