name | correct guesses | games together | ratio |
---|---|---|---|
seshoumara | 5 | 5 | 1.000 |
yui | 3 | 4 | 0.750 |
kimapr | 12 | 17 | 0.706 |
Palaiologos | 4 | 8 | 0.500 |
Olivia | 6 | 12 | 0.500 |
kotnen | 4 | 9 | 0.444 |
olus2000 | 7 | 17 | 0.412 |
LyricLy | 9 | 22 | 0.409 |
vspf | 2 | 5 | 0.400 |
moshikoi | 2 | 8 | 0.250 |
olive | 1 | 4 | 0.250 |
taswelll | 3 | 13 | 0.231 |
essaie | 1 | 5 | 0.200 |
Dolphy | 2 | 10 | 0.200 |
soup girl | 1 | 6 | 0.167 |
razetime | 1 | 10 | 0.100 |
JJRubes | 0 | 6 | 0.000 |
IFcoltransG | 0 | 4 | 0.000 |
theqwertiest | 0 | 4 | 0.000 |
name | correct guesses | games together | ratio |
---|---|---|---|
kimapr | 9 | 17 | 0.529 |
yui | 2 | 4 | 0.500 |
olive | 2 | 4 | 0.500 |
moshikoi | 3 | 7 | 0.429 |
LyricLy | 9 | 22 | 0.409 |
essaie | 2 | 5 | 0.400 |
Dolphy | 4 | 10 | 0.400 |
taswelll | 5 | 13 | 0.385 |
kotnen | 3 | 8 | 0.375 |
JJRubes | 2 | 6 | 0.333 |
Palaiologos | 2 | 6 | 0.333 |
olus2000 | 4 | 17 | 0.235 |
razetime | 2 | 9 | 0.222 |
vspf | 1 | 5 | 0.200 |
Olivia | 2 | 12 | 0.167 |
soup girl | 0 | 4 | 0.000 |
seshoumara | 0 | 5 | 0.000 |
theqwertiest | 0 | 4 | 0.000 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | local function suffix_reps(seq, suffix_len) assert(suffix_len <= #seq) local tail = #seq - suffix_len local reps = 1 while true do for offset = 0, suffix_len - 1 do if seq[tail - offset] ~= seq[#seq - offset] then return reps end end tail = tail - suffix_len reps = reps + 1 end end local function gen_seq(n) local seq = {} for i = 1, n do local max = 1 for j = 1, i / 2 do max = math.max(max, suffix_reps(seq, j)) end seq[i] = max end return seq end print(table.concat(gen_seq(tonumber((...))), ", ")) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // https://www.gamers.org/~fpv/doomlogo.html pub const oom = \\ =============== =============== ======== ======== \\ //. . . . . . .\\ //. . . . . . .\\ \\. . .\\// . . // \\ ||. . ._____. . .|| ||. . ._____. . .|| || . . .\/ . . .|| \\ || . .|| ||. . || || . .|| ||. . || ||. . . . . . . || \\ ||. . || || . .|| ||. . || || . .|| || . | . . . . .|| \\ ||-_ .|| ||. . || || . .|| ||. _-|| ||-_.|\ . . . . || \\ || `-|| || . .|| ||. . || ||-' || || `|\_ . .|. .|| \\ || || ||_ . || || . _|| || || || |\ `-_/| . || \\ || \|. || `-_|| ||_-' || .|/ || || | \ / |-_.|| \\ || `-_|| || || ||_-' || || | \ / | `|| \\ || `' || || `' || || | \ / | || \\ `===. .==='.`===. .===' /==. | \/ | || \\ |-_ `===. .===' _|_ `===. .===' _-|/ `== \/ | || \\ `-_ `=' _-' `-_ `=' _-' `-_ /| \/ | || \\ `-__\._-' `-_./__-' `' |. /| | || \\ `' | /==.|| \\ \/ `== \\ `-_ / \\ ``' \\ ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | const std = @import("std"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayListUnmanaged; const DynamicBitSet = std.bit_set.DynamicBitSet; const AutoHashMap = std.AutoArrayHashMapUnmanaged; fn CharMap(V: type) type { return AutoHashMap(u8, V); } pub fn DFA(V: type) type { const State = struct { const Self = @This(); out: CharMap(usize), accepting: bool, value: V, pub fn init(allocator: Allocator, accepting: bool, value: V) !Self { return .{ .out = try AutoHashMap(u8, usize).init(allocator, &.{}, &.{}), .accepting = accepting, .value = value, }; } pub fn deinit(self: *Self, allocator: Allocator) void { self.out.deinit(allocator); } }; return struct { const Self = @This(); states: ArrayList(State), allocator: Allocator, pub fn init(allocator: Allocator) Self { return .{ .states = ArrayList(State).initBuffer(&.{}), .allocator = allocator, }; } pub fn deinit(self: *Self) void { for (self.states.items) |*state| state.deinit(self.allocator); self.states.deinit(self.allocator); } pub fn addState(self: *Self, accepting: bool, value: V) !usize { try self.states.append(self.allocator, try State.init(self.allocator, accepting, value)); return self.states.items.len - 1; } pub fn addTransition(self: *Self, from: usize, via: u8, to: usize) !void { try self.states.items[from].out.put(self.allocator, via, to); } pub fn getTransition(self: Self, from: usize, via: u8) ?usize { return self.states.items[from].out.get(via); } pub fn accepts(self: Self, input: []const u8) bool { var state: usize = 0; for (input) |c| { if (self.getTransition(state, c)) |next_state| state = next_state else return false; } return self.states.items[state].accepting; } }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | const std = @import("std"); const Allocator = std.mem.Allocator; const NFAC = @import("nfa.zig").NFA; const DFAC = @import("dfa.zig").DFA; const CharSet = std.bit_set.IntegerBitSet(256); pub fn RegexReader(V: type) type { return struct { const NFA = NFAC(V); const DFA = DFAC(V); const Self = @This(); pub const SyntaxError = error{ UnexpectedEOF, UnclosedParenthesis, ExpectedOperand, UnexpectedChar, InvalidEscape, }; pub const ReadError = SyntaxError || Allocator.Error; nfa: *NFA, i: usize, buf: []const u8, pub fn init(nfa: *NFA, expr: []const u8) Self { return .{ .nfa = nfa, .i = 0, .buf = expr, }; } fn getch(self: *Self) ?u8 { if (self.eof()) return null; const c = self.buf[self.i]; self.i += 1; return c; } fn getch2(self: *Self) ReadError!u8 { return self.getch() orelse return SyntaxError.UnexpectedEOF; } fn ungetch(self: *Self) void { self.i -= 1; } fn eof(self: Self) bool { return self.i >= self.buf.len; } fn readEscape(self: *Self) ReadError!u8 { return switch (try self.getch2()) { 'x' => l: { const hi = try self.getch2(); const lo = try self.getch2(); break :l std.fmt.parseUnsigned(u8, &.{ hi, lo }, 16) catch |e| switch (e) { error.Overflow => unreachable, error.InvalidCharacter => return SyntaxError.InvalidEscape, }; }, else => |c| c, }; } fn readAtom(self: *Self) ReadError!?NFA.Sub { if (self.eof()) return null; switch (self.getch().?) { '(' => { const res = try self.readChoice(); return if (try self.getch2() != ')') SyntaxError.UnclosedParenthesis else res; }, '%' => return try self.nfa.str(&.{try self.readEscape()}), '[' => { var charset = CharSet.initEmpty(); const complement = try self.getch2() == '^'; if (!complement) self.ungetch(); while (true) { var c = try self.getch2(); if (c == ']') break; if (c == '%') c = try self.readEscape(); const c2 = try self.getch2(); if (c2 == '-') { const c3 = try self.getch2(); if (c > c3) continue; // empty range charset.setRangeValue(.{ .start = c, .end = c3 }, true); } else { charset.set(c); self.ungetch(); } } if (complement) charset = charset.complement(); return try self.nfa.charset(charset); }, ')', '?', '+', '*', '|' => { self.ungetch(); return null; }, else => |c| return try self.nfa.str(&.{c}), } } fn readQuantified(self: *Self) ReadError!?NFA.Sub { const base = try self.readAtom() orelse return null; return try switch (self.getch() orelse return base) { '?' => self.nfa.opt(base), '+' => self.nfa.rep(base), '*' => self.nfa.kleene(base), else => { self.ungetch(); return base; }, }; } fn readConcat(self: *Self) ReadError!NFA.Sub { var base = try self.readQuantified() orelse return SyntaxError.ExpectedOperand; while (try self.readQuantified()) |q| base = try self.nfa.concat(&.{ base, q }); return base; } fn readChoice(self: *Self) ReadError!NFA.Sub { var base = try self.readConcat(); while (true) { if (self.getch()) |c| { if (c == '|') base = try self.nfa.choice(&.{ base, try self.readConcat() }) else { self.ungetch(); return base; } } else return base; } } pub fn read(self: *Self) !NFA.Sub { const res = try self.readChoice(); if (!self.eof()) return error.UnexpectedChar; return res; } }; } fn nothing(_: void, _: void) void { return {}; } pub fn regexToDFA(allocator: Allocator, regex: []const u8) !DFAC(void) { var nfa = NFAC(void).init(allocator, {}); defer nfa.deinit(); var rr = RegexReader(void).init(&nfa, regex); const sub = try rr.read(); return nfa.toDFA(sub, nothing); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | const std = @import("std"); const Allocator = std.mem.Allocator; const CharSet = std.bit_set.IntegerBitSet(256); fn HashMap(K: type, V: type) type { return std.ArrayHashMapUnmanaged(K, V, struct { pub fn hash(_: @This(), k: K) u32 { var hasher = std.hash.Wyhash.init(1233543646); std.hash.autoHashStrat(&hasher, k, .DeepRecursive); return @truncate(hasher.final()); } pub fn eql(_: anytype, k1: K, k2: K, _: anytype) bool { return std.mem.eql(@typeInfo(K).Pointer.child, k1, k2); } }, true); } const AutoHashMap = std.AutoArrayHashMapUnmanaged; const ArrayList = std.ArrayListUnmanaged; const DFA = @import("dfa.zig").DFA; const Subset = []const usize; fn orderUsize(_: void, a: usize, b: usize) std.math.Order { return std.math.order(a, b); } fn contains(set: Subset, end_state: usize) bool { return std.sort.binarySearch(usize, end_state, set, {}, orderUsize) != null; } pub fn NFA(V: type) type { const Transition = struct { char: ?u8, to: usize }; const State = struct { const Self = @This(); out: ArrayList(Transition), value: V, pub fn init(value: V) Self { return .{ .out = ArrayList(Transition).initBuffer(&.{}), .value = value, }; } pub fn deinit(self: *Self, allocator: Allocator) void { self.out.deinit(allocator); } }; return struct { const Self = @This(); pub const Sub = struct { start: usize, end: usize, }; allocator: Allocator, states: ArrayList(State), value: V, // HACK this is lazy pub fn init(allocator: Allocator, value: V) Self { return .{ .allocator = allocator, .states = ArrayList(State).initBuffer(&.{}), .value = value, }; } pub fn deinit(self: *Self) void { for (self.states.items) |*state| state.deinit(self.allocator); self.states.deinit(self.allocator); } pub fn addState(self: *Self) Allocator.Error!usize { try self.states.append(self.allocator, State.init(self.value)); return self.states.items.len - 1; } pub fn addTransition(self: *Self, from: usize, char: ?u8, to: usize) Allocator.Error!void { try self.states.items[from].out.append(self.allocator, .{ .char = char, .to = to }); } pub fn rep(self: *Self, sub: Sub) Allocator.Error!Sub { try self.addTransition(sub.end, null, sub.start); return sub; } pub fn opt(self: *Self, sub: Sub) Allocator.Error!Sub { try self.addTransition(sub.start, null, sub.end); return sub; } pub fn kleene(self: *Self, sub: Sub) Allocator.Error!Sub { return self.rep(try self.opt(sub)); } pub fn choice(self: *Self, subs: []const Sub) Allocator.Error!Sub { const new = Sub{ .start = try self.addState(), .end = try self.addState() }; for (subs) |sub| { try self.addTransition(new.start, null, sub.start); try self.addTransition(sub.end, null, new.end); } return new; } pub fn concat(self: *Self, subs: []const Sub) Allocator.Error!Sub { var last_end = subs[0].end; for (subs[1..]) |sub| { try self.addTransition(last_end, null, sub.start); last_end = sub.end; } return .{ .start = subs[0].start, .end = last_end }; } pub fn str(self: *Self, s: []const u8) Allocator.Error!Sub { const start = try self.addState(); var end = start; for (s) |c| { const new_end = try self.addState(); try self.addTransition(end, c, new_end); end = new_end; } return .{ .start = start, .end = end }; } pub fn charset(self: *Self, set: CharSet) Allocator.Error!Sub { const start = try self.addState(); const end = try self.addState(); var chars = set.iterator(.{}); while (chars.next()) |c| try self.addTransition(start, @intCast(c), end); return .{ .start = start, .end = end }; } fn hull(self: Self, states: Subset, hull_allocator: Allocator) Allocator.Error![]usize { const allocator = self.allocator; // should maybe be separate (e.g. arena allocation while algo runs) but meh var level = try ArrayList(usize).initCapacity(allocator, 1); defer level.deinit(allocator); try level.appendSlice(allocator, states); var next_level = ArrayList(usize).initBuffer(&.{}); defer next_level.deinit(allocator); var seen = try AutoHashMap(usize, void).init(allocator, states, allocator.alloc(void, states.len) catch unreachable); defer seen.deinit(allocator); while (level.items.len > 0) { for (level.items) |state| { for (self.states.items[state].out.items) |transition| { if (transition.char == null and seen.get(transition.to) == null) { try seen.put(allocator, transition.to, {}); try next_level.append(allocator, transition.to); } } } level.clearRetainingCapacity(); const old_level = level; level = next_level; next_level = old_level; } const res = try hull_allocator.alloc(usize, seen.count()); var iter = seen.iterator(); var i: usize = 0; while (iter.next()) |e| { res[i] = e.key_ptr.*; i += 1; } return res; } pub fn toDFA(self: Self, sub: Sub, merge_values: fn (v1: V, v2: V) V) Allocator.Error!DFA(V) { const allocator = self.allocator; // same here var dfa = DFA(V).init(allocator); var subsets = std.heap.ArenaAllocator.init(allocator); defer subsets.deinit(); const start_subset = try self.hull(&.{sub.start}, subsets.allocator()); var nfa_to_dfa = try HashMap(Subset, usize).init(allocator, &.{start_subset}, &.{ try dfa.addState(contains(start_subset, sub.end), self.states.items[sub.start].value), }); defer nfa_to_dfa.deinit(allocator); var next_level = ArrayList(Subset).initBuffer(&.{}); defer next_level.deinit(allocator); var level = try ArrayList(Subset).initCapacity(allocator, 1); defer level.deinit(allocator); try level.append(allocator, start_subset); while (level.items.len > 0) { for (level.items) |subset| { var transitions = try AutoHashMap(u8, AutoHashMap(usize, void)).init(allocator, &.{}, &.{}); defer { for (transitions.values()) |*set| set.deinit(allocator); transitions.deinit(allocator); } for (subset) |state| { for (self.states.items[state].out.items) |transition| { if (transition.char) |char| { if (transitions.getPtr(char)) |set| { try set.put(allocator, transition.to, {}); } else { try transitions.put(allocator, char, try AutoHashMap(usize, void).init(allocator, &.{transition.to}, &.{{}})); } } } } var iter = transitions.iterator(); while (iter.next()) |e| { var buf: [256]usize = undefined; var i: usize = 0; for (e.value_ptr.keys()) |state| { buf[i] = state; i += 1; } const reached_states = try self.hull(buf[0..i], subsets.allocator()); std.sort.pdq(usize, reached_states, {}, std.sort.asc(usize)); const gop = try nfa_to_dfa.getOrPut(allocator, reached_states); if (!gop.found_existing) { var v = self.states.items[reached_states[0]].value; for (reached_states[1..]) |s| v = merge_values(v, self.states.items[s].value); const dfa_state = try dfa.addState(contains(reached_states, sub.end), v); gop.value_ptr.* = dfa_state; try next_level.append(allocator, reached_states); } try dfa.addTransition(nfa_to_dfa.get(subset).?, e.key_ptr.*, gop.value_ptr.*); } } level.clearRetainingCapacity(); const old_level = level; level = next_level; next_level = old_level; } return dfa; } }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | const std = @import("std"); const NFA = @import("nfa.zig").NFA(void); const DFA = @import("dfa.zig").DFA(void); const allocator = std.testing.allocator; fn initNFA() NFA { return NFA.init(allocator, {}); } fn nothing(_: void, _: void) void { return {}; } const expect = std.testing.expect; test "optional" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.opt(try nfa.str("test")); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("test")); try expect(dfa.accepts("")); try expect(!dfa.accepts("t")); } test "repetition" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.rep(try nfa.str("test")); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("test")); try expect(dfa.accepts("testtest")); try expect(!dfa.accepts("")); try expect(!dfa.accepts("t")); try expect(!dfa.accepts("testt")); } test "kleene" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.kleene(try nfa.str("test")); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("testtesttest")); try expect(dfa.accepts("test")); try expect(dfa.accepts("")); try expect(!dfa.accepts("t")); try expect(!dfa.accepts("testyay")); } test "concat" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.concat(&.{ try nfa.str("hello"), try nfa.str("world") }); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("helloworld")); try expect(!dfa.accepts("")); try expect(!dfa.accepts("hello")); try expect(!dfa.accepts("world")); } test "choice" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.choice(&.{ try nfa.str("hi"), try nfa.str("hello") }); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("hi")); try expect(dfa.accepts("hello")); try expect(!dfa.accepts("")); try expect(!dfa.accepts("h")); try expect(!dfa.accepts("helloworld")); } test "putting it all together" { var nfa = initNFA(); defer nfa.deinit(); const sub = try nfa.choice(&.{ try nfa.concat(&.{ try nfa.rep(try nfa.str("ab")), try nfa.str("cd"), }), try nfa.kleene(try nfa.str("ef")), }); var dfa = try nfa.toDFA(sub, nothing); defer dfa.deinit(); try expect(dfa.accepts("abcd")); try expect(dfa.accepts("abababcd")); try expect(dfa.accepts("efef")); try expect(dfa.accepts("")); try expect(!dfa.accepts("abcdef")); try expect(!dfa.accepts("g")); try expect(!dfa.accepts("a")); } const origRegexToDFA = @import("ex.zig").regexToDFA; fn regexToDFA(regex: []const u8) !DFA { return origRegexToDFA(allocator, regex); } test "simple regex" { var dfa = try regexToDFA("(ab)+cd|(ef)*"); defer dfa.deinit(); try expect(dfa.accepts("abcd")); try expect(dfa.accepts("abababcd")); try expect(dfa.accepts("efef")); try expect(dfa.accepts("")); try expect(!dfa.accepts("abcdef")); try expect(!dfa.accepts("g")); try expect(!dfa.accepts("a")); } test "charset" { var dfa = try regexToDFA("[a%]|b]"); defer dfa.deinit(); try expect(dfa.accepts("a")); try expect(dfa.accepts("b")); try expect(dfa.accepts("]")); try expect(dfa.accepts("|")); try expect(!dfa.accepts("c")); } test "charset range" { var dfa = try regexToDFA("[a-c]"); defer dfa.deinit(); try expect(dfa.accepts("a")); try expect(dfa.accepts("b")); try expect(!dfa.accepts("d")); } test "charset complement" { var dfa = try regexToDFA("[^ab]"); defer dfa.deinit(); try expect(!dfa.accepts("a")); try expect(!dfa.accepts("b")); try expect(dfa.accepts("c")); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | // The necessary parts of ANSI escape sequence support required for this editor to work const std = @import("std"); const fmt = std.fmt; const Color = @import("color.zig").Color; const Pos = @import("pos.zig"); pub fn parseCsiParams(res: []usize, comptime default: usize, params: []const u8, min_params: usize) ![]usize { var i: usize = 0; var si = std.mem.splitScalar(u8, params, ';'); while (i < res.len) : (i += 1) { const param = si.next(); if (param) |num| { res[i] = if (num.len == 0) default else try std.fmt.parseInt(usize, num, 10); } else { res[i] = default; break; } } if (i == res.len and si.next() != null) return error.TooManyParameters; while (i < min_params) : (i += 1) res[i] = default; return res[0..i]; } pub const AnsiCommand = union(enum) { ignore, // something we don't recognize tab, backspace, delete, newline, carriage_return, insert, // Control characters (excluding those corresponding to the above) ctrl: u8, // a - z // Regular printable ASCII key presses print: u8, cursor_movement: CursorMovement, const CursorMovement = struct { const Action = enum { left, right, up, down, pos1, end }; modifier: enum { none, shift, ctrl }, action: Action, times: usize, }; }; pub const AnsiCommandIterator = struct { buf: []const u8, i: usize, fn getch(self: *AnsiCommandIterator) ?u8 { if (self.eof()) return null; const c = self.buf[self.i]; self.i += 1; return c; } fn ungetch(self: *AnsiCommandIterator) void { self.i -= 1; } fn eof(self: *AnsiCommandIterator) bool { return self.i >= self.buf.len; } fn parseCursorMovement( kind: u8, params: []const u8, ) AnsiCommand { var movbuf: [2]usize = undefined; const movement = parseCsiParams(&movbuf, 1, params, 1) catch return .{ .ignore = {} }; const action: AnsiCommand.CursorMovement.Action = switch (kind) { 'A' => .up, 'B' => .down, 'C' => .right, 'D' => .left, 'H' => .pos1, 'F' => .end, else => return .{ .ignore = {} }, }; const times = movement[0]; return if (movement.len == 1) .{ .cursor_movement = .{ .modifier = .none, .action = action, .times = times } } else if (movement.len == 2) switch (movement[1]) { 2 => .{ .cursor_movement = .{ .modifier = .shift, .action = action, .times = times } }, 5 => .{ .cursor_movement = .{ .modifier = .ctrl, .action = action, .times = times } }, else => .{ .ignore = {} }, } else .{ .ignore = {} }; } pub fn next(self: *AnsiCommandIterator) ?AnsiCommand { const c = self.getch() orelse return null; return switch (c) { else => .{ .ignore = {} }, 0x08 => .{ .backspace = {} }, 0x7F => .{ .delete = {} }, '\n' => .{ .newline = {} }, '\r' => .{ .carriage_return = {} }, '\t' => .{ .tab = {} }, 0x01...0x07, 0x0C, 0x0E...0x1A => .{ .ctrl = c - 1 + 'a' }, // Printable ASCII ' '...'~' => .{ .print = c }, // ANSI escape sequences 0x1B => switch (self.getch() orelse return .{ .ignore = {} }) { // TODO possible ESC else => .{ .ignore = {} }, // Fe sequence 0x40...0x5A, 0x5C...0x5F => .{ .ignore = {} }, '[' => { // CSI sequence if (self.eof()) return .{ .ignore = {} }; // TODO cut off? const start = self.i; var c2 = self.getch() orelse return .{ .ignore = {} }; while (c2 >= 0x30 and c2 <= 0x3F) c2 = self.getch() orelse return .{ .ignore = {} }; while (c2 >= 0x20 and c2 <= 0x2F) c2 = self.getch() orelse return .{ .ignore = {} }; if (c2 < 0x40 or c2 > 0x7E) { self.ungetch(); return .{ .ignore = {} }; // TODO syntax error } const params = self.buf[start .. self.i - 1]; if (c2 == '~') return switch (fmt.parseInt(usize, params, 10) catch return .{ .ignore = {} }) { 2 => .{ .insert = {} }, else => .{ .ignore = {} }, }; return parseCursorMovement(c2, params); }, }, }; } }; pub fn parse(buf: []const u8) AnsiCommandIterator { return .{ .buf = buf, .i = 0 }; } pub fn writeCsi(writer: anytype, seq: []const u8) !void { try writer.writeAll("\x1B["); try writer.writeAll(seq); } pub fn fmtCsi(writer: anytype, csi_type: u8, params: anytype) !void { try writer.writeAll("\x1B["); if (params.len > 0) try fmt.format(writer, "{d}", .{params[0]}); var i: usize = 1; while (i < params.len) : (i += 1) try fmt.format(writer, ";{d}", .{params[i]}); try writer.writeByte(csi_type); } pub fn setCursor(writer: anytype, pos: Pos) !void { return fmtCsi(writer, 'H', [_]usize{ pos.row + 1, pos.col + 1 }); } pub fn setFg(writer: anytype, color: Color) !void { return fmtCsi(writer, 'm', [_]usize{ 38, 2, color.r, color.g, color.b }); } pub fn setBg(writer: anytype, color: Color) !void { return fmtCsi(writer, 'm', [_]usize{ 48, 2, color.r, color.g, color.b }); } pub fn clearScreen(writer: anytype) !void { return writeCsi(writer, "2J"); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | const hex_digit = "[0-9A-Fa-f]"; const integer = "(([1-9][0-9]*|0[0-7]*|0[xX]" ++ hex_digit ++ "+)([uU](l|L|ll|LL)|(l|L|ll|LL)[uU]))"; const dexp = "([eE][+-]?[0-9]+)"; const hexp = "([pP][+-]?[0-9]+)"; const decfloat = "([0-9]+%.[0-9]*|%.[0-9]+)" ++ dexp ++ "?|[0-9]+" ++ dexp; const hexfloat = "0[xX](" ++ hex_digit ++ "+%." ++ hex_digit ++ "*" ++ hexp ++ "?|" ++ hex_digit ++ "+" ++ hexp ++ ")"; const float = "(" ++ decfloat ++ "|" ++ hexfloat ++ ")[fF]"; // TODO fallback tainted invalid escape sequence const hex_quad = hex_digit ++ hex_digit ++ hex_digit ++ hex_digit; const escape = "(\\(['\"?\\abfnrtv]|[0-7][0-7]?[0-7]?|x" ++ hex_digit ++ "+|u" ++ hex_quad ++ "|U" ++ hex_quad ++ hex_quad ++ "))"; const tok = @import("tok.zig"); const RegexTokenizer = tok.RegexTokenizer; const Token = tok.Token; var cache: ?RegexTokenizer = null; pub fn tokenizer() !RegexTokenizer { cache = cache orelse try RegexTokenizer.init(&.{ // zig fmt: off .{.keyword, "auto|break|case|char|const|continue|default|do|double" ++ "|else|enum|extern|float|for|goto|if|inline|int|long" ++ "|register|restrict|return|short|signed|sizeof|static|struct|switch" ++ "|typedef|union|unsigned|void|volatile|while" ++ "|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local"}, .{.identifier, "[a-zA-Z_]+[a-zA-Z0-9_]*"}, .{.quoted, "(u8|[uUL])?\"([^\"\n\\]|" ++ escape ++ ")*\"|[uUL]?'([^'\n\\]|" ++ escape ++ ")*'"}, .{.number, integer ++ "|" ++ float}, .{.sym, "[(){}[%]<>.!&|+%-*/%]|%->|%+%+|%-%-|<<|>>|[!=<>]=|%^|&&|%|%||%?|:|;|%.%.%.|([*/&+%-^|]|<<|>>)?=|,|#|##" ++ "|<:|:>|<%%|%%>|%%:|%%:%%:"}, // darn digraphs .{.pp, "#include[ \t]*\"[^\n\"]*\"|<[^\n>]*>|#(pragma|define|undef|if(n?def)|else|elif|endif|line|error|warning)"}, .{.comment, "//[^\n]*|/%*(/[^*]|[^/])*%*/"}, .{.ignore, "[ \n\r\t]+"}, }); return cache.?; } const expectEq = @import("std").testing.expectEqual; const Tester = struct { t: RegexTokenizer, buf: []const u8, i: usize = 0, pub fn expect(self: *@This(), kind: tok.TokenType, s: []const u8) !void { try expectEq(Token{.kind = kind, .len = s.len}, self.t.nextToken(self.buf[self.i..])); self.i += s.len; } }; test "things" { const buf = "if (1) printf(\"blah\");"; var t = Tester{.t = try tokenizer(), .buf = buf}; try t.expect(.keyword, "if"); try t.expect(.ignore, " "); try t.expect(.sym, "("); try t.expect(.number, "2"); try t.expect(.sym, ")"); try t.expect(.ignore, " "); try t.expect(.identifier, "printf"); try t.expect(.sym, "("); try t.expect(.quoted, "\"blah\""); try t.expect(.sym, ")"); try t.expect(.sym, ";"); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | pub const Color = struct { r: u8, g: u8, b: u8 }; fn h(u: usize) Color { return .{ .r = (u >> 16) & 0xFF, .g = (u >> 8) & 0xFF, .b = u & 0xFF }; } // not doing proper enum array rn pub const FG = [_]Color{ h(0x66ff66), // keyword h(0x116611), // identifier h(0xff7611), // quoted h(0x6666ff), // number h(0x113311), // sym h(0x1d0878), // pp h(0x888888), // comment h(0x111111), // ignore }; pub const BG = Color{ .r = 255, .g = 255, .b = 255 }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | const std = @import("std"); const os = std.os; const posix = std.posix; const File = std.fs.File; const ArrayList = std.ArrayList; const ansi = @import("ansi.zig"); const AnsiCommand = ansi.AnsiCommand; const txtbuf = @import("txtbuf.zig"); const color = @import("color.zig"); const util = @import("util.zig"); const Pos = @import("pos.zig"); const TextBuffer = txtbuf.TextBuffer; const tok = @import("tok.zig"); fn asgn(u: usize) isize { return @intCast(u); } fn asun(i: isize) usize { return @intCast(i); } const Allocator = std.mem.Allocator; const Edit = struct { const Self = @This(); at: usize, old: []const u8, new: []const u8, fn init(at: usize, old: []const u8, new: []const u8, a: Allocator) !Self { const self_new = try a.alloc(u8, new.len); @memcpy(self_new, new); const self_old = try a.alloc(u8, old.len); @memcpy(self_old, old); return .{ .at = at, .new = self_new, .old = self_old }; } // Note: To play nice with arena allocators, this must be in reverse order vs. init! fn deinit(self: Self, a: Allocator) void { a.free(self.old); a.free(self.new); } fn redo(self: Self, buf: *TextBuffer) !usize { try buf.replaceRange(self.at, self.old.len, self.new); return self.at + self.new.len; } fn undo(self: Self, buf: *TextBuffer) !usize { try buf.replaceRange(self.at, self.new.len, self.old); return self.at + self.old.len; } }; const allocator = std.heap.c_allocator; // TODO cap history size const History = struct { const Self = @This(); const ArenaAllocator = std.heap.ArenaAllocator; arena: ArenaAllocator, edits: ArrayList(Edit), cursor: usize, pub fn init() Self { const arena = ArenaAllocator.init(std.heap.page_allocator); return .{ .arena = arena, .edits = ArrayList(Edit).init(allocator), .cursor = 0, }; } pub fn deinit(self: Self) void { self.arena.deinit(); self.edits.deinit(); } fn undo(self: *Self, text: *TextBuffer) !?usize { if (self.cursor == 0) return null; self.cursor -= 1; return try self.edits.items[self.cursor].undo(text); } fn redo(self: *Self, text: *TextBuffer) !?usize { if (self.cursor == self.edits.items.len) return null; const res = try self.edits.items[self.cursor].redo(text); self.cursor += 1; return res; } fn record(self: *Self, at: usize, old: []const u8, new: []const u8) !void { // TODO do better than throwing edits away // Deinitialize *in reverse order* so the arena can actually free the memory if (self.cursor < self.edits.items.len) { var i: usize = self.edits.items.len - 1; while (true) { self.edits.items[i].deinit(self.arena.allocator()); if (i == self.cursor) break; i -= 1; } self.edits.shrinkRetainingCapacity(self.cursor); } try self.edits.append(try Edit.init(at, old, new, self.arena.allocator())); self.cursor += 1; } }; const Clipboard = struct { const Self = @This(); content: []u8, pub fn init() !Self { return .{ .content = try allocator.alloc(u8, 0) }; } pub fn deinit(self: Self) void { allocator.free(self.content); } pub fn get(self: Self) []const u8 { return self.content; } pub fn set(self: *Self, content: []const u8) !void { self.content = try allocator.realloc(self.content, content.len); @memcpy(self.content, content); } }; const TextPane = struct { const Self = @This(); anchor: Pos, cursor: Pos, mark: ?Pos, text: TextBuffer, history: History, clipboard: *Clipboard, multiline: bool, pub fn init(clipboard: *Clipboard, multiline: bool) !Self { return .{ .anchor = .{ .row = 0, .col = 0 }, .cursor = .{ .row = 0, .col = 0 }, .mark = null, .text = try TextBuffer.empty(), .history = History.init(), .clipboard = clipboard, .multiline = multiline, }; } pub fn deinit(self: *Self) void { self.text.deinit(); self.history.deinit(); } fn setCursor(self: *Self, cursor: Pos) void { self.cursor = cursor; self.mark = null; } pub fn setText(self: *Self, text: TextBuffer) void { self.text = text; self.setCursor(.{ .row = 0, .col = 0 }); self.anchor = .{ .row = 0, .col = 0 }; self.history.deinit(); self.history = History.init(); } fn moveRows(self: *Self, d: isize) Pos { const row = @max(0, @min(asgn(self.text.nRows()) - 1, asgn(self.cursor.row) + d)); const col = @max(0, @min(self.text.nCols(row), self.cursor.col)); return .{ .row = row, .col = col }; } fn moveCols(self: *Self, d_cols: isize) Pos { var cursor = self.cursor; var d = d_cols; while (d < 0) { const col = asgn(cursor.col) + d; if (col >= 0) { cursor.col = asun(col); break; } if (cursor.row == 0) { cursor.col = 0; break; } cursor.row -= 1; cursor.col = self.text.nCols(cursor.row); d = col + 1; } while (d > 0) { const col = asgn(cursor.col) + d; const nCols = self.text.nCols(cursor.row); if (col <= nCols) { cursor.col = asun(col); break; } if (cursor.row == self.text.nRows() - 1) { cursor.col = nCols; break; } cursor.row += 1; cursor.col = 0; d = col - asgn(nCols) - 1; } return cursor; } fn getCursorIdx(self: Self) usize { return self.text.getIdx(self.cursor); } const Span = struct { min: usize, max: usize }; fn getSelection(self: Self) ?Span { if (self.mark) |mark| { const idx = self.getCursorIdx(); const mark_idx = self.text.getIdx(mark); return .{ .min = @min(idx, mark_idx), .max = @max(idx, mark_idx) }; } return null; } fn getCopySpan(self: Self) Span { const idx = self.text.getIdx(.{ .row = self.cursor.row, .col = 0 }); return self.getSelection() orelse Span{ .min = idx, .max = idx + self.text.nCols(self.cursor.row) + 1 }; } fn copy(self: *Self) !void { const sel = self.getCopySpan(); try self.clipboard.set(self.text.getRange(sel.min, sel.max)); } fn deleteSpan(self: *Self, sel: Span) !void { const old = self.text.getRange(sel.min, sel.max); try self.history.record(sel.min, old, &.{}); try self.text.replaceRange(sel.min, old.len, &.{}); self.setCursor(self.text.getPos(sel.min)); } fn delete(self: *Self) !void { const idx = self.getCursorIdx(); const sel = self.getSelection() orelse Span{ .min = if (idx == 0) return else idx - 1, .max = idx }; return self.deleteSpan(sel); } fn cut(self: *Self) !void { try self.copy(); try self.deleteSpan(self.getCopySpan()); } fn insert(self: *Self, new: []const u8) !void { if (!self.multiline and std.mem.indexOfScalar(u8, new, '\n') != null) return; const cur_idx = self.getCursorIdx(); const sel = self.getSelection() orelse Span{ .min = cur_idx, .max = cur_idx }; const old = self.text.getRange(sel.min, sel.max); try self.history.record(sel.min, old, new); try self.text.replaceRange(sel.min, old.len, new); self.setCursor(self.text.getPos(sel.min + new.len)); } fn insertNewline(self: *Self) !void { const start_row = if (self.mark) |pos| @min(pos.row, self.cursor.row) else self.cursor.row; const start_col = if (start_row < self.cursor.row) self.mark.?.col else @min((self.mark orelse self.cursor).col, self.cursor.col); const start_idx = self.text.getIdx(.{ .row = start_row, .col = 0 }); const line = self.text.getRange(start_idx, start_idx + self.text.nCols(start_row)); var i: usize = 0; while (i < start_col and (line[i] == ' ' or line[i] == '\t')) i += 1; const indent = line[0..i]; const indented_line = try std.mem.concat(allocator, u8, &.{ "\n", indent }); defer allocator.free(indented_line); try self.insert(indented_line); } fn paste(self: *Self) !void { try self.insert(self.clipboard.get()); } fn undo(self: *Self) !void { if (try self.history.undo(&self.text)) |idx| self.setCursor(self.text.getPos(idx)); } fn redo(self: *Self) !void { if (try self.history.redo(&self.text)) |idx| self.setCursor(self.text.getPos(idx)); } fn selectAll(self: *Self) void { self.cursor = .{ .row = 0, .col = 0 }; self.mark = .{ .row = self.text.nRows() - 1, .col = self.text.nCols(self.text.nRows() - 1) }; } fn selectToken(self: *Self) void { var hint = tok.Tokenization.Hint{}; const token = self.text.tokens.getToken(self.getCursorIdx(), &hint); // HACK don't let the trailing newline disappear self.cursor = self.text.getPos(@min(hint.sum, self.text.chars.items.len - 1)); self.mark = self.text.getPos(hint.sum - token.len); } fn gotoPrevToken(self: *Self) void { self.setCursor(self.text.getPos(self.text.tokens.getPreviousTokenStart(self.getCursorIdx()))); } fn gotoNextToken(self: *Self) void { self.setCursor(self.text.getPos(self.text.tokens.getNextTokenEnd(self.getCursorIdx()))); } pub fn processCommand(self: *Self, cmd: AnsiCommand) !void { switch (cmd) { else => {}, .backspace, .delete => try self.delete(), .newline, .carriage_return => try self.insertNewline(), .print => |c| try self.insert(&[_]u8{c}), .tab => try self.insert(" "), // HACK awful .ctrl => |c| switch (c) { 'z' => try self.undo(), 'y' => try self.redo(), 'c' => try self.copy(), 'x' => try self.cut(), 'v' => try self.paste(), 'a' => self.selectAll(), 't' => self.selectToken(), else => {}, }, .cursor_movement => |cm| switch (cm.modifier) { .none => switch (cm.action) { .up => self.setCursor(self.moveRows(-asgn(cm.times))), .down => self.setCursor(self.moveRows(asgn(cm.times))), .right => self.setCursor(self.moveCols(asgn(cm.times))), .left => self.setCursor(self.moveCols(-asgn(cm.times))), .pos1 => self.setCursor(.{ .col = 0, .row = self.cursor.row }), .end => self.setCursor(.{ .col = self.text.nCols(self.cursor.row), .row = self.cursor.row }), }, .ctrl => switch (cm.action) { .up, .down => {}, // TODO .left => self.gotoPrevToken(), .right => self.gotoNextToken(), .pos1 => self.setCursor(.{ .row = 0, .col = 0 }), .end => self.setCursor(.{ .row = self.text.nRows() - 1, .col = self.text.nCols(self.text.nRows() - 1) }), }, .shift => { if (self.mark == null) self.mark = self.cursor; switch (cm.action) { .up => self.cursor = self.moveRows(-asgn(cm.times)), .down => self.cursor = self.moveRows(asgn(cm.times)), .right => self.cursor = self.moveCols(asgn(cm.times)), .left => self.cursor = self.moveCols(-asgn(cm.times)), .pos1 => self.cursor.col = 0, .end => self.cursor.col = self.text.nCols(self.cursor.row), } }, }, } } fn scroll(self: *Self, dim: Pos) void { self.anchor = self.anchor.min(self.cursor); const bottom_right = self.anchor.add(dim); if (self.cursor.row >= bottom_right.row) self.anchor.row += self.cursor.row - bottom_right.row + 1; if (self.cursor.col >= bottom_right.col) self.anchor.col += self.cursor.col - bottom_right.col + 1; } const ColorManager = struct { const CM = @This(); fg: color.Color, bg: color.Color, pub fn init(writer: anytype) !CM { const fg = color.FG[@intFromEnum(tok.TokenType.ignore)]; try ansi.setFg(writer, fg); const bg = color.BG; try ansi.setBg(writer, bg); return .{ .fg = fg, .bg = bg, }; } pub fn set(self: *CM, writer: anytype, t: tok.TokenType, sel: bool) !void { var fg = color.FG[@intFromEnum(t)]; var bg = color.BG; if (sel) std.mem.swap(color.Color, &fg, &bg); if (!std.meta.eql(fg, self.fg)) { try ansi.setFg(writer, fg); self.fg = fg; } if (!std.meta.eql(bg, self.bg)) { try ansi.setBg(writer, bg); self.bg = bg; } } }; fn render(self: *Self, dim: Pos, writer: anytype, focus: bool) !void { self.scroll(dim); const idx = self.getCursorIdx(); const sel = self.getSelection() orelse Span{ .min = idx, .max = idx + 1 }; var row: usize = 0; var cm = try ColorManager.init(writer); var tok_hint: tok.Tokenization.Hint = .{}; while (row < dim.row) : (row += 1) { var col: usize = 0; while (col < dim.col) : (col += 1) { const pos = .{ .row = row, .col = col }; const abs = self.anchor.add(pos); const c = self.text.get(abs); var highlight = false; var tt = tok.TokenType.ignore; if (abs.row < self.text.nRows() and abs.col <= self.text.nCols(abs.row)) { const c_idx = self.text.getIdx(abs); if (focus) highlight = c_idx >= sel.min and c_idx < sel.max; tt = self.text.tokens.getToken(c_idx, &tok_hint).kind; } try cm.set(writer, tt, highlight); switch (c orelse ' ') { 0x20...0x7e => |ch| try writer.writeByte(ch), else => try writer.writeAll(" "), } } if (row + 1 < dim.row) try writer.writeAll("\r\n"); } try cm.set(writer, .ignore, false); } }; pub const Editor = struct { const Self = @This(); const BW = @TypeOf(std.io.bufferedWriter(std.io.getStdOut().writer())); tty: File, tui: *BW, path: []u8, clipboard: *Clipboard, textpane: TextPane, state: union(enum) { normal: void, confirm_quit: void, save_path: TextPane, }, pub fn init(tty: File, tui: *BW) !Self { const clipboard = try allocator.create(Clipboard); clipboard.* = try Clipboard.init(); return .{ .tty = tty, .tui = tui, .path = try allocator.alloc(u8, 0), .clipboard = clipboard, .textpane = try TextPane.init(clipboard, true), .state = .normal, }; } pub fn deinit(self: *Self) void { self.textpane.deinit(); self.clipboard.deinit(); allocator.free(self.path); allocator.destroy(self.clipboard); } fn setPath(self: *Self, path: []const u8) !void { self.path = try allocator.realloc(self.path, path.len); @memcpy(self.path, path); } pub fn open(self: *Self, path: []const u8) !void { if (TextBuffer.open(path)) |text| { self.textpane.setText(text); try self.setPath(path); } else |err| switch (err) { error.FileNotFound => { self.textpane.setText(try TextBuffer.empty()); try self.setPath(path); }, else => try self.setPath(""), } } fn isSaved(self: *Self) bool { if (self.path.len == 0) return self.textpane.text.chars.items.len == 0; const file = std.fs.cwd().openFile(self.path, .{ .mode = .read_only }) catch return false; var chars = ArrayList(u8).init(allocator); defer chars.deinit(); file.reader().readAllArrayList(&chars, 16384) catch return false; return std.mem.eql(u8, self.textpane.text.chars.items, chars.items); } fn save(self: *Self) !void { if (self.path.len > 0) { try self.textpane.text.save(self.path); // TODO error handling } else { self.state = .{ .save_path = try TextPane.init(self.clipboard, false) }; } } fn processCommand(self: *Self, cmd: AnsiCommand) !bool { switch (self.state) { .normal => switch (cmd) { .ctrl => |c| switch (c) { 'q' => { if (self.isSaved()) return true; self.state = .{ .confirm_quit = {} }; }, 's' => try self.save(), else => try self.textpane.processCommand(cmd), }, else => try self.textpane.processCommand(cmd), }, .confirm_quit => switch (cmd) { .ctrl => |c| switch (c) { 'q' => return true, else => self.state = .{ .normal = {} }, }, else => self.state = .{ .normal = {} }, }, .save_path => |prompt| switch (cmd) { .ctrl => |c| switch (c) { 'q' => { self.state.save_path.deinit(); self.state = .{ .normal = {} }; }, else => try self.state.save_path.processCommand(cmd), }, .newline, .carriage_return => { const path = prompt.text.chars.items; try self.setPath(path[0 .. path.len - 1]); // trim trailing newline (TODO refucktor) try self.textpane.text.save(self.path); // TODO error handling self.state.save_path.deinit(); self.state = .{ .normal = {} }; }, else => try self.state.save_path.processCommand(cmd), }, } return false; } fn processInput(self: *Self, buf: []const u8) !bool { var iter = ansi.parse(buf); while (iter.next()) |cmd| { switch (cmd) { .ignore => {}, .insert => @import("e/josh.zig").josh(self.tty, self.tui) catch {}, else => if (try self.processCommand(cmd)) return true, } } return false; } fn render(self: *Self) !void { const us = std.time.microTimestamp(); const writer = self.tui.writer(); const dim = try util.getTtySize(self.tty); try ansi.setCursor(writer, .{ .row = 0, .col = 0 }); try self.textpane.render(.{ .row = dim.row - 1, .col = dim.col }, writer, self.state == .normal); try writer.writeAll("\r\n"); switch (self.state) { .normal => { var buf: [1000]u8 = undefined; var fixbuf = std.io.fixedBufferStream(&buf); @memset(buf[0..dim.col], ' '); std.fmt.format(fixbuf.writer(), "{s}:{d}:{d} {d} us {d} lines", .{ if (self.path.len == 0) "?" else self.path, self.textpane.cursor.row + 1, self.textpane.cursor.col + 1, std.time.microTimestamp() - us, self.textpane.text.nRows(), }) catch {}; try writer.writeAll(buf[0..dim.col]); }, .confirm_quit => { const msg = "You have unsaved changes. Press C-q to quit, any other key to cancel."; try writer.writeAll(if (dim.col < msg.len) msg[0..dim.col] else msg); var i = msg.len; while (i < dim.col) : (i += 1) try writer.writeByte(' '); }, .save_path => { const prefix = "save as: "; try writer.writeAll(prefix); try self.state.save_path.render(.{ .row = 1, .col = dim.col - prefix.len }, writer, true); }, } try self.tui.flush(); } pub fn run(self: *Self) !void { try self.render(); var buf: [1000]u8 = undefined; while (true) { // TODO deal with full buffer (unlikely in normal usage) const len = try self.tty.read(&buf); if (try self.processInput(buf[0..len])) return; try self.render(); } } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | const std = @import("std"); const fs = std.fs; const os = std.os; const posix = std.posix; const ansi = @import("ansi.zig"); const Editor = @import("editor.zig").Editor; fn uncook(handle: anytype, tcattr: anytype) !void { var raw_attr = tcattr; raw_attr.lflag.ECHO = false; raw_attr.lflag.ICANON = false; raw_attr.lflag.ISIG = false; raw_attr.lflag.IEXTEN = false; raw_attr.iflag.IXON = false; raw_attr.iflag.ICRNL = false; raw_attr.iflag.BRKINT = false; raw_attr.iflag.INPCK = false; raw_attr.iflag.ISTRIP = false; raw_attr.oflag.OPOST = false; raw_attr.cflag.CSIZE = .CS8; // TODO think about these raw_attr.cc[@intFromEnum(std.posix.V.TIME)] = 0; raw_attr.cc[@intFromEnum(std.posix.V.MIN)] = 1; try std.posix.tcsetattr(handle, .FLUSH, raw_attr); } fn run() !void { var tty = try fs.cwd().openFile("/dev/tty", .{ .mode = .read_write }); defer tty.close(); const cooked_attr = try std.posix.tcgetattr(tty.handle); defer std.posix.tcsetattr(tty.handle, .FLUSH, cooked_attr) catch {}; try uncook(tty.handle, cooked_attr); const stdout_file = std.io.getStdOut().writer(); var bw = std.io.bufferedWriter(stdout_file); defer bw.flush() catch {}; const stdout = bw.writer(); const writeCsi = ansi.writeCsi; // Hide / unhide cursor try writeCsi(stdout, "?25l"); defer writeCsi(stdout, "?25h") catch {}; // Mouse on / off // try writeCsi(stdout, "?1000h"); // defer writeCsi(stdout, "?1000l") catch {}; // Save / restore cursor pos try writeCsi(stdout, "s"); defer writeCsi(stdout, "u") catch {}; // Save / restore screen try writeCsi(stdout, "?47h"); defer writeCsi(stdout, "?47l") catch {}; // Enable alternative buffer / switch back to original buffer try writeCsi(stdout, "?1049h"); defer writeCsi(stdout, "?1049l") catch {}; try bw.flush(); var editor = try Editor.init(tty, &bw); defer editor.deinit(); var args = std.process.args(); if (args.next()) |_| { if (args.next()) |path| { if (args.next() == null) try editor.open(path); } } try editor.run(); } pub fn main() !void { return run() catch |e| switch (e) { error.OutOfMemory => std.io.getStdOut().writer().writeAll(@import("e/oom.zig").oom), else => e, }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | const tok = @import("tok.zig"); const RegexTokenizer = tok.RegexTokenizer; const Token = tok.Token; var cache: ?RegexTokenizer = null; pub fn tokenizer() !RegexTokenizer { cache = cache orelse try RegexTokenizer.init(&.{ // zig fmt: off .{.identifier, "[^ \n\r\t]+"}, .{.ignore, "[ \n\r\t]+"}, }); return cache.?; } |
1 2 3 4 5 6 7 8 9 10 11 12 | const Pos = @This(); row: usize, col: usize, pub fn add(p: Pos, q: Pos) Pos { return Pos{ .row = p.row + q.row, .col = p.col + q.col }; } pub fn sub(p: Pos, q: Pos) Pos { return Pos{ .row = p.row - q.row, .col = p.col - q.col }; } pub fn min(p: Pos, q: Pos) Pos { return Pos{ .row = @min(p.row, q.row), .col = @min(p.col, q.col) }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | const std = @import("std"); const NFA = @import("reg/nfa.zig").NFA(StateInfo); const DFA = @import("reg/dfa.zig").DFA(StateInfo); const RegexReader = @import("reg/ex.zig").RegexReader(StateInfo); const allocator = std.heap.c_allocator; pub const TokenType = enum(u8) { keyword, identifier, quoted, number, sym, pp, comment, ignore, }; pub const Token = struct { kind: TokenType, len: usize, }; const StateInfo = struct { tt: TokenType, acc: bool, }; fn mergeTokens(a: StateInfo, b: StateInfo) StateInfo { if (a.acc != b.acc) { return if (a.acc) a else b; } return .{ .tt = @enumFromInt(@min(@intFromEnum(a.tt), @intFromEnum(b.tt))), .acc = a.acc, }; } pub const RegexTokenizer = struct { const Self = @This(); dfa: DFA, pub fn init(comptime rules: []const struct { TokenType, []const u8 }) !Self { var nfa = NFA.init(allocator, .{ .tt = .ignore, .acc = false }); defer nfa.deinit(); var subs: [rules.len]NFA.Sub = undefined; var i: usize = 0; while (i < rules.len) : (i += 1) { nfa.value = .{ .tt = rules[i][0], .acc = false }; var rr = RegexReader.init(&nfa, rules[i][1]); subs[i] = try rr.read(); nfa.states.items[subs[i].end].value.acc = true; // HACK } const sub = try nfa.choice(&subs); return .{ .dfa = try nfa.toDFA(sub, mergeTokens), }; } // no need to deinit pub fn nextToken(self: Self, buf: []const u8) Token { var state: usize = 0; var len: usize = 0; while (len < buf.len) : (len += 1) { const c = buf[len]; if (self.dfa.getTransition(state, c)) |next_state| { state = next_state; } else { return .{ .kind = self.dfa.states.items[state].value.tt, .len = @max(len, 1), // HACK }; } } return .{ .kind = self.dfa.states.items[state].value.tt, .len = @max(len, 1), }; } }; // Two interesting optimizations are possible here: // - We could retokenize only the affected range. // - We could use a clever data structure (e.g. B-trees augmented with sums of token lengths) // All in all this would in theory allow updates in O(edit size) time. // But we don't have working B-trees so we don't and this is O(text size) on every edit. Urgh. pub const Tokenization = struct { const Self = @This(); tokens: std.ArrayList(Token), pub fn init(text: []const u8, tokenizer: RegexTokenizer) !Self { var i: usize = 0; var tokens = std.ArrayList(Token).init(allocator); while (i < text.len) { const t = tokenizer.nextToken(text[i..]); try tokens.append(t); i += t.len; } return .{ .tokens = tokens }; } pub fn deinit(self: *Self) void { self.tokens.deinit(); } pub const Hint = struct { ti: usize = 0, sum: usize = 0, }; pub fn getPreviousTokenStart(self: Self, i: usize) usize { var sum: usize = 0; var res: usize = 0; var j: usize = 0; while (sum < i and j < self.tokens.items.len) : (j += 1) { const token = self.tokens.items[j]; if (token.kind != .ignore) res = sum; sum += token.len; } return res; } pub fn getNextTokenEnd(self: Self, i: usize) usize { var sum: usize = 0; var j: usize = 0; while (sum < i and j < self.tokens.items.len) { sum += self.tokens.items[j].len; j += 1; } while (j < self.tokens.items.len) : (j += 1) { sum += self.tokens.items[j].len; if (self.tokens.items[j].kind != .ignore) break; } return sum; } pub fn getToken(self: Self, i: usize, hint: *Hint) Token { while (hint.sum <= i and hint.ti < self.tokens.items.len) { hint.sum += self.tokens.items[hint.ti].len; hint.ti += 1; } return self.tokens.items[hint.ti - 1]; } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | const std = @import("std"); const fs = std.fs; const Path = []const u8; const stdio = @cImport({ @cInclude("stdio.h"); }); const Pos = @import("pos.zig"); const char = u8; const allocator = std.heap.c_allocator; const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const Tokenization = @import("tok.zig").Tokenization; pub const FileType = enum { plain, c, fn init(path: Path) FileType { return if (std.mem.endsWith(u8, path, ".c")) .c else .plain; } }; fn tokenize(t: FileType, text: []const u8) !Tokenization { return Tokenization.init(text, switch (t) { .plain => try @import("plain.zig").tokenizer(), .c => try @import("c.zig").tokenizer(), }); } pub const TextBuffer = struct { const Self = @This(); chars: ArrayList(char), lineOffsets: ArrayList(usize), // where does the respective line end? fileType: FileType, tokens: Tokenization, pub fn empty() !Self { var chars = try ArrayList(char).initCapacity(allocator, 1); try chars.append('\n'); return Self{ .chars = chars, .lineOffsets = try calculateLineOffsets(chars.items), .tokens = try tokenize(.plain, chars.items), .fileType = .plain, }; } pub fn open(path: Path) !Self { const file = try fs.cwd().openFile(path, .{ .mode = .read_only }); const reader = file.reader(); var chars = ArrayList(char).init(allocator); { defer file.close(); try reader.readAllArrayList(&chars, 16384); } const ft = FileType.init(path); return .{ .chars = chars, .lineOffsets = try Self.calculateLineOffsets(chars.items), .tokens = try tokenize(ft, chars.items), .fileType = ft, }; } pub fn save(self: *TextBuffer, path: Path) !void { const old_ft = self.fileType; self.fileType = FileType.init(path); if (old_ft != self.fileType) { self.tokens.deinit(); self.tokens = try tokenize(self.fileType, self.chars.items); } const dirname = fs.path.dirname(path); const basename = fs.path.basename(path); const tmpname = try std.mem.concat(allocator, u8, &.{ ".~sped-tmp-", basename }); defer allocator.free(tmpname); const tmpath = try fs.path.join(allocator, if (dirname) |name| &.{ name, basename } else &.{basename}); defer allocator.free(tmpath); const file = try fs.cwd().createFile(tmpath, .{}); { defer file.close(); try file.writeAll(self.chars.items); } try fs.cwd().rename(tmpath, path); } pub fn deinit(self: *Self) void { self.chars.deinit(); self.lineOffsets.deinit(); self.tokens.deinit(); } /// Number of rows, always >= 1. pub fn nRows(self: Self) usize { return self.lineOffsets.items.len; } pub fn nCols(self: Self, row: usize) usize { return if (row == 0) self.lineOffsets.items[0] else self.lineOffsets.items[row] - self.lineOffsets.items[row - 1] - 1; } // TODO LFs (<=) pub fn inBounds(self: Self, pos: Pos) bool { return pos.row < self.nRows() and pos.col < self.nCols(pos.row); } fn rowStart(self: Self, row: usize) usize { return if (row == 0) 0 else self.lineOffsets.items[row - 1] + 1; } pub fn getIdx(self: Self, pos: Pos) usize { return self.rowStart(pos.row) + pos.col; } fn loLt(_: void, lhs: usize, rhs: usize) bool { return lhs < rhs; } /// O(log n) pub fn getPos(self: Self, idx: usize) Pos { const row = std.sort.lowerBound(usize, idx, self.lineOffsets.items, void{}, loLt); return .{ .row = row, .col = idx - self.rowStart(row) }; } pub fn get(self: Self, pos: Pos) ?char { return if (self.inBounds(pos)) self.chars.items[self.getIdx(pos)] else null; } pub fn getRange(self: Self, from: usize, to: usize) []const u8 { return self.chars.items[from..to]; } fn calculateLineOffsets(chars: []const u8) !ArrayList(usize) { var lineOffsets = ArrayList(usize).init(allocator); var i: usize = 0; while (std.mem.indexOfScalar(char, chars[i..], '\n')) |offset| { try lineOffsets.append(i + offset); i += offset + 1; } if (chars.len == 0 or i < chars.len) // no trailing newline try lineOffsets.append(chars.len); // note: no newline! return lineOffsets; } pub fn replaceRange(self: *Self, from: usize, len: usize, replacement: []const u8) !void { try self.chars.replaceRange(from, len, replacement); self.lineOffsets.deinit(); self.lineOffsets = try calculateLineOffsets(self.chars.items); self.tokens.deinit(); self.tokens = try tokenize(self.fileType, self.chars.items); } }; |
1 2 3 4 5 6 7 8 9 10 11 12 | const std = @import("std"); const Pos = @import("pos.zig"); pub fn getTtySize(tty: std.fs.File) !Pos { var size: std.c.winsize = undefined; size.ws_row = 60; size.ws_col = 80; const err = std.c.ioctl(tty.handle, std.c.T.IOCGWINSZ, &size); if (err != 0) return error.TerminalSizeUnknown; return .{ .row = size.ws_row, .col = size.ws_col }; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "sped", .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .link_libc = true, }); b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); } const run_step = b.step("run", "Run editor"); run_step.dependOn(&run_cmd.step); const exe_unit_tests = b.addTest(.{ .root_source_file = b.path("src/c.zig"), .target = target, .optimize = optimize, .link_libc = true, }); const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_exe_unit_tests.step); } |
1 2 3 4 5 6 7 8 9 10 11 12 | .{ .name = "sped", .version = "0.0.0", .minimum_zig_version = "0.13.0", .dependencies = .{}, .paths = .{ "build.zig", "build.zig.zon", "src", // TODO license }, } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | sped is a lightweight, primitive text editor if first command line argument is a file that is opened stuff marked with [ ] is not yet implemented features: - syntax highlighting (C only) - [ ] good performance even for massive files keybindings: notation: - Control: C - Shift: S - Arrow Keys: L, R, U, D cursor movement: - L / R / U / D: move cursor - begin / end: move to begin / end of line - C-begin / C-end: move to begin / end of file - [ ] page up / page down: move cursor up / down one page - C-L / C-R: move to previous / next token - [ ] C-U / C-D: * if parentheses (tokens) are unmatched at cursor position: move to previous opening / subsequent closing parenthesis * otherwise: move to previous / subsequent smaller indentation level selection: - S-L / S-R / S-U / S-D: start or continue selection - C-c / C-x / C-v: copy / cut / paste * operate on the given line if nothing is selected - C-a / C-t: select all / token editing: - character keys: insert character - backspace: delete - [ ] tab: * if preceding characters are whitespace (incl. newline): indent * otherwise: autocomplete token - [ ] S-tab: dedent - enter: insert newline (with indentation) - C-z / C-y: undo / redo meta: - C-q: quit - C-s: save file - [ ] C-f: find - [ ] C-r: replace - [ ] C-g: goto - [ ] C-i: help |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | -- y'all will guess me anyway but who cares, -- scissors is winning rock paper scissors royale! -- (i hope) getmetatable"".__index = function(str, key) if type(key) == "number" then return (key >= 1 and key <= #str) and str:sub(key, key) or nil end return string[key] end local readline = io.lines() while 1 do local grid = {} repeat local line = readline() if not line then break end -- being nice or something grid[#grid+1] = line until line == "" local x = assert(tonumber(readline())) local y = assert(tonumber(readline())) local dirs = { L = {-1, 0}, R = {1, 0}, U = {0, -1}, D = {0, 1}, } local function get_tile(tx, ty) return (grid[ty] or {})[tx] or "#" end local function murder(K, V) local function dist(mx, my) local res = 0 local level = {{mx, my}} local visited = {[my] = {[mx] = true}} repeat local next_level = {} for _, pos in ipairs(level) do local px, py = table.unpack(pos) for dn, dp in pairs(dirs) do local dx, dy = table.unpack(dp) local nx, ny = px + dx, py + dy if ({[K..V]=1,[V..K]=1})[get_tile(px,py)..get_tile(nx,ny)] then return res end if get_tile(nx, ny) ~= "#" and not (visited[ny] or {})[nx] then visited[ny] = visited[ny] or {} visited[ny][nx] = true next_level[#next_level+1] = {nx, ny} end end end level = next_level res = res + 1 until not level[1] return math.huge end local best_move, min_dist = nil, math.huge for dn, dp in pairs(dirs) do local dx, dy = table.unpack(dp) if ({[K..V]=1,[V..K]=1})[get_tile(x,y)..get_tile(x+dx,y+dy)] then print"I" print(dn) return end local can_dist = dist(x + dx, y + dy) if can_dist < min_dist then best_move, min_dist = dn, can_dist end end if best_move then print"M" print(best_move) return end print"P" -- there is nothing we can do end if table.concat(grid):find"R" then murder("P", "R") else murder("S", "P") end end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | const std=@import("std");const ArrayList =std.ArrayList;const Doer=struct{ const State=enum{Normal,JustTainted ,Tainted,TaintedGroup,Ignore,};const SyntaxError=error .InvalidSyntax;buf:ArrayList(u8),stk:ArrayList(usize ),stateStk:ArrayList(State),state:State,concatBegin :usize,pub fn init(alloc:anytype)Doer {return Doer {.buf=ArrayList(u8).init (alloc),. stk=ArrayList(usize).init (alloc),. stateStk=ArrayList(State).init(alloc),.state =.Normal, .concatBegin=0,};}pub fn startConcat(self: *Doer)void {self.eraseConcat();self.state=.Normal;}pub fn eraseConcat (self:*Doer)void {self.buf.shrinkRetainingCapacity (self.concatBegin);}pub fn pushState (self:*Doer)!void {try self .stk.append(self .concatBegin);try self.stateStk.append( self.state);self .concatBegin =self.buf.items.len;} pub fn popState (self: *Doer)!void{self.concatBegin =self.stk.popOrNull () orelse return SyntaxError;self. state=self.stateStk.popOrNull() orelse unreachable;} pub fn taint(self:*Doer) void{self.eraseConcat();self.state=.Tainted;}pub fn bufChar(self:*Doer,c:u8) !void{try self.buf.append(c);}pub fn do(self:*Doer, in:anytype )![]const u8{while(in.readByte())|c|{switch(self.state){. Normal=>switch (c){'\\'=> try self.bufChar(try in.readByte()),'|'=>self.state =.Ignore, '*'=>{},'[' =>{if(try in.readByte()!=']')return SyntaxError; self.state =.JustTainted ;},']'=>return SyntaxError,'('=>try self.pushState (),')'=>try self.popState (),else=>try self.bufChar(c),},.JustTainted =>switch( c){'\\'=> {try in.skipBytes(1,.{});self.taint();},'*' =>self.state =.Normal, '|'=>self .startConcat (),'('=>{ self.taint ();try self .pushState ();},')'=> {self. eraseConcat ();self.state =.TaintedGroup ;},else=> self.taint (),},. Tainted=> switch(c) {'\\'=> try in.skipBytes (1,.{}),'|' =>self .startConcat (),'('=>try self.pushState (),')'=>{ self.eraseConcat ();self.state =.TaintedGroup ;},else=> {},},.TaintedGroup=>switch (c){'*'=> try self. popState( ),'|'=>{try self.popState ();self.startConcat ();},'('=> {try self.popState();self .taint(); try self.pushState();},')' =>{try self .popState();self.state =.TaintedGroup;},'\\'=>{try in.skipBytes (1,.{});try self.popState ();self.taint();},else=>{try self.popState ();self.taint();}},.Ignore =>switch(c){'\\','['=>try in .skipBytes (1,.{} ),']'=>return SyntaxError ,'('=>try self.pushState (),')'=>try self.popState (),else=> {},},} }else|err |{if(err!=error .EndOfStream )return err;}switch(self.state ){.Normal ,.Ignore =>return self.buf.toOwnedSlice(),else=> return SyntaxError,}}};pub fn main()!void {const stdout=std.io.getStdOut ().writer();var bufout=std .io.bufferedWriter(stdout);const stdin=std.io.getStdIn() ;var bufin=std.io.bufferedReader (stdin.reader());var arena =std.heap.ArenaAllocator.init (std.heap.page_allocator);defer arena.deinit();var doer=Doer .init(arena.allocator());try bufout.writer().writeAll(try doer.do(bufin.reader()));try bufout.flush();} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | from sys import stdin M = { '+' : ((1, 0), (0, 1)), '/' : ((0,-1), (-1,0)), '\\': ((0, 1), (1, 0)), } L = tuple(map(str.rstrip, stdin.readlines())) W, H = S = max(map(len, L)), len(L) def I(p): x, y = p return y in range(H) and x in range(len(L[y])) and L[y][x] in M def D(v, w): return sum(x * y for x, y in zip(v, w)) def F(p, v): x, y = p m = M[L[y][x]] w = tuple(map(lambda r: D(r, v), m)) return (x + w[0], y + w[1]), w def P(p, v): o = p while I(p): p, v = F(p, v) if abs(D(o, v) - D(p, v)) >= abs(D(S, v)) >= 8: exit(1) for x in range(W): P((x, 0), (0, 1)) P((x, H-1), (0, -1)) for y in range(H): P((0, y), (1, 0)) P((W-1, y), (-1, 0)) def C(p): for v in ((0, 1), (0, -1), (1, 0), (-1, 0)): q = set() while I(p): q.add(p) p, v = F(p, v) if p in q: exit(1) for y, l in enumerate(L): for x in range(len(l)): C((x, y)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | #!/c/Program\ Files/PHP/php.exe <?php ini_set('evil_bit', 1); $a=[]; while ($b=rtrim(fgets(STDIN), "\n\r")) { $cs=array(); preg_match_all('/./u',$b,$cs); $a[]=$cs[0]; } function d() { global $a; foreach ($a as $r) { foreach ($r as $c) echo $c; echo "\n"; } } function ass($c) { if ($c) { return; } echo "invalid!!!"; exit(69); } class RectAngle { public readonly int $x1, $x2, $y1, $y2; public function __construct($x1, $x2, $y1, $y2) { $this->x1 = $x1; $this->x2 = $x2; $this->y1 = $y1; $this->y2 = $y2; } public function loop($f) { for ($x = $this->x1; $x <= $this->x2; $x++) for ($y = $this->y1; $y <= $this->y2; $y++) $f($x,$y); } public function cr() { global $a; $a[$this->y1][$this->x1]=$a[$this->y1][$this->x2]=$a[$this->y2][$this->x1]=$a[$this->y2][$this->x2]=' '; } public function inp($x,$y) { return $x >= $this->x1 && $x <= $this->x2 && $y >= $this->y1 && $y <= $this->y2; } } if (!($h=count($a))) { exit; } $w=count($a[0]); $rn=0; $ls=[ '│' => "UD", '─' => "LR", '┴' => "LRU", '┬' => "LRD", '┤' => "LUD", '├' => "RUD", '┌' => "DR", '┐' => "LD", '└' => "UR", '┘' => "LU", ]; $ds=[ "L" => [-1,0], "R" => [1,0], "U" => [0,-1], "D" => [0,1], ]; $br=[]; foreach ($a as $y=>$r) { foreach ($r as $x=>$c) { switch ($c) { case '┌': $xn = $x; while (++$xn < $w && $r[$xn] != '┐'); if ($xn==$w) continue 2; $yn = $y; while (++$yn < $h && $a[$yn][$x] != '└'); if ($yn==$h) continue 2; if ($a[$yn][$xn] != '┘') continue 2; $re=new RectAngle($x,$xn,$y,$yn); $re->cr(); $con=[++$rn=>true]; $fl = function($x,$y) use ($re,&$br,$rn,$ds,$ls,$w,$h,&$con) { global $a; $br[$y][$x] = $rn; $in=0; $dv=null; ass(array_key_exists($a[$y][$x],$ls)); foreach (str_split($ls[$a[$y][$x]]) as $dc) { $dw=$ds[$dc];$xm=$x+$dw[0];$ym=$y+$dw[1]; if ($re->inp($xm,$ym)) $in++; else $dv = $dw; } ass($in==2); $a[$y][$x]=' '; if ($dv==null) return; $kill=[]; while (1) { $x+=$dv[0];$y+=$dv[1]; $kill[]=[$x,$y]; ass((new RectAngle(0,$w-1,0,$h-1))->inp($x,$y)); $re2 = null; if (array_key_exists($y,$br) && array_key_exists($x,$br[$y])) $re2 = $br[$y][$x]; if ($re2!=null) { ass(!array_key_exists($re2,$con)); $con[$re2]=true; foreach ($kill as $k) $a[$k[1]][$k[0]]=' '; break; } ass(array_key_exists($a[$y][$x],$ls)); $sl = strlen($ls[$a[$y][$x]]); if ($sl==3) break; ass($sl==2); $dv2=null; foreach (str_split($ls[$a[$y][$x]]) as $dc) { $dvc=$ds[$dc]; if ($dvc[0]!=-$dv[0] || $dvc[1]!=-$dv[1]) $dv2=$dvc; #there is no going back } $dv=$dv2; } }; (new RectAngle($x+1, $xn-1, $y+1, $yn-1))->loop(function($x,$y) { global $a; ass($a[$y][$x] == ' '); }); foreach ([ new RectAngle($x+1, $xn-1, $y, $y), new RectAngle($x+1, $xn-1, $yn, $yn), new RectAngle($x, $x, $y+1, $yn-1), new RectAngle($xn, $xn, $y+1, $yn-1) ] as $rl) $rl->loop($fl); break; case '│': case '─': case '┴': case '┬': case '┤': case '├': case '┐': case '└': case '┘': case ' ': break; # a ok default: ass(0); } } } foreach ($a as $r) foreach ($r as $c) ass($c==' '); ?> |
1 2 3 4 5 6 | import Data.Bits (popCount, (.&.)) import Data.Function (on) naive = [0] ++ go [0] where go seq = let inv = map (1-) seq in inv ++ go (seq ++ inv) parity = go (0 :: Integer) where go i = popCount i .&. 1 : go (succ i) main = if ((==) `on` take 1000) naive parity then putStrLn "Test passed" else error "Test failed" -- 🥱 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <stdlib.h> #include <stdio.h> #include <assert.h> #define mapass(v,f,...) v=f(v,##__VA_ARGS__) enum C {Z,O,E}; const char L=-1,R=1; typedef struct {char m;enum C w;int n;} T; const T sts[7][3]={{ {L,E,1}, {L,E,1}, {L,E,5}, },{ {L,O,4}, {L,Z,1}, {R,E,2}, },{ {R,O,3}, {R,O,2}, {R,O,0}, },{ {R,Z,3}, {R,Z,2}, {R,Z,0}, },{ {L,Z,4}, {L,O,4}, {R,E,6}, },{ {L,Z,5}, {L,O,5}, {R,E,-1}, },{ {R,E,2}, {R,E,2}, {R,E,2}, }}; char *dostuff(char *t) { int s=0; ++t; do { T tr=sts[s][*t]; *t=tr.w; t+=tr.m; s=tr.n; } while (s!=-1); return t; } main() { char c,*t=malloc(1); t[0]=E; int nt=1,ct=1; while (EOF!=(c=getchar())) { if (nt==ct) assert(mapass(t,realloc,ct<<=1)); t[nt++]=Z; } if (nt+2>ct) assert(mapass(t,realloc,ct+2)); t[nt++]=E; t[nt++]=E; assert(feof(stdin)); mapass(t,dostuff); for(char *e=t+nt;t!=e&&*t!=E;++t) assert(EOF!=putchar('0'+*t)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import java.util.*;import java.util.regex.Pattern;import java.util.stream.*;import java.io.*; // da spek sed "Your complete function may produce any amount of output, although the result should depend on text_so_far given some corpus." // dis meks a infinte strem o'. do smth liek java thing.java "I like fish" <bible.txt | head -c 1000 o jst ctrl^C idk class Thing{ public static void main(String... args){ final var corpus=new BufferedReader(new InputStreamReader(System.in)).lines().collect(Collectors.joining("\n")); final var text_so_far=args[0]; final var n=3; var next=new HashMap<String,ArrayList<String>>(); var p=Pattern.compile("\\w+"); var m=p.matcher(corpus); var prevs=new ArrayList<String>(); prevs.add(""); while(m.find()){ var tok=m.group(); var ctx=prevs.get(prevs.size()-1); for(var i=1;i<=Math.min(prevs.size()-1,n);i++){ var nexts=next.getOrDefault(ctx,new ArrayList<>()); nexts.add(tok); next.put(ctx,nexts); ctx=" "+prevs.get(prevs.size()-1-i)+" "+ctx; } prevs.add(tok); } var r=new Random(); m=p.matcher(text_so_far); var ks=prevs; prevs=new ArrayList<String>(); for (var i=0;i<n;i++) prevs.add(ks.get(r.nextInt(ks.size()))); while (m.find()) prevs.add(m.group()); while(true){ var ctx = prevs.get(prevs.size()-1); var choisez = new ArrayList<String>(); for(var j=1;j<=Math.min(prevs.size()-1,n);j++) { choisez.addAll(next.getOrDefault(ctx, new ArrayList<>())); ctx = prevs.get(prevs.size()-1-j)+" "+ctx; } if(choisez.isEmpty()){ for(var i=0;i<n;i++) prevs.add(ks.get(r.nextInt(ks.size()))); } var w = choisez.get(r.nextInt(choisez.size())); System.out.print(" "+w); prevs.add(w); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #lang racket (define (proceed-parse in) (read-char in) (parse in)) (define (assert cond) (when (not cond) (raise "assertion failed"))) (define (expect in c) (assert (eqv? c (read-char in)))) (define (read-atom in) (let [(c (peek-char in))] (if (or (char-whitespace? c) (char=? #\) c)) '() (begin (read-char in) (cons c (read-atom in)))))) (define (skip-line in) (if (eqv? #\newline (read-char in)) (void) (skip-line in))) (define (parse in) (let [(c (peek-char in))] (cond [(or (eof-object? c) (char=? #\) c)) '()] [(char=? #\# c) (begin (skip-line in) (parse in))] [(char-whitespace? c) (proceed-parse in)] [(char=? #\( c) (let [(r (proceed-parse in))] (begin (expect in #\)) (cons r (parse in))))] [else (cons (let [(s (list->string (read-atom in)))] (or (string->number s) (list 'name s))) (parse in))]))) (define (fnify f) (lambda (args ctx) (f (eval-args args ctx)))) (define (thunk args ctx) (fnify (lambda (_) (last (eval-args args ctx))))) (define (my-lambda args ctx) (letrec [(param (begin (assert (eqv? 'name (caar args))) (cadar args))) (body (cdr args)) (f (lambda (xs) (if (null? xs) f (let* [(new-ctx (hash-set ctx param (car xs))) (res (last (eval-args body new-ctx)))] (if (null? (cdr xs)) res (res (cdr xs) ctx))))))] (fnify f))) (define (my-quote args _) args) (define (fnify-n n f) (letrec [(l (lambda (args ctx) (if (null? args) l (let [(arg (eval (car args) ctx))] (if (= n 1) (if (null? (cdr args)) (f arg) ((f arg) (eval-args (cdr args) ctx))) ((fnify-n (- n 1) (curry f arg)) (cdr args) ctx))) )))] l)) (define my-t (fnify-n 2 (lambda (x y) x))) (define my-f (fnify-n 2 (lambda (x y) y))) (define (my-<= n m) (cond [(eq? n m) my-t] [(and (number? n) (number? m)) (if (<= n m) my-t my-f)] [(null? n) (if (pair? m) my-t my-f)] [(and (pair? n) (pair? m)) (cond [(not (my-<= (car n) (car m))) my-f] [(not (my-<= (car m) (car n))) my-t] [else (my-<= (cdr n) (cdr m))])] [else my-f])) (define (d args) (display args) (newline)) (define (my-macro margs mctx) (lambda (args ctx) (eval (last (eval-args margs (hash-set ctx "..." args))) ctx))) (define predefs (hash ;; builtins (mostly inherited from racket) "d" (fnify d) "ib" (fnify (lambda (_) (char->integer (read-char)))) "ob" (fnify-n 1 (lambda (c) (write-char (integer->char c)))) "do" (fnify last) "car" (fnify-n 1 car) "cdr" (fnify-n 1 cdr) "cons" (fnify-n 2 cons) "list" (fnify identity) "-" (fnify-n 1 -) "+" (fnify-n 2 +) "*" (fnify-n 2 *) "<=" (fnify-n 2 my-<=) "t" my-t "f" my-f ;; special forms "\\\\" thunk "\\" my-lambda "'" my-quote "$" my-macro)) (define (eval-args args ctx) (map (lambda (arg) (eval arg ctx)) args)) (define (eval expr ctx) (if (pair? expr) (let [(f (car expr)) (args (cdr expr))] (if (eqv? f 'name) (hash-ref ctx (car args)) ((eval f ctx) args ctx))) expr)) (define (get-file-name) (command-line #:program "crisp" #:args (filename) filename)) (define (maybe-display v) (when (not (eq? v (void))) (display v))) (maybe-display (eval (cons (list 'name "do") (call-with-input-file (get-file-name) parse)) predefs)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # she bangs # (all lines starting with # actually) are ignored # run this using "racket crisp.rkt stuff.crisp" # d is a debug print for a list of arguments (d 1 2 3) # (ib) reads a byte, (ob b) writes a byte (ob 65) # (d (ib)) # basic math works; - is unary; +, * are strictly binary, fold them yourself (d (+ (+ (* 4 5) (* 2 3)) (- 1))) # lambdas (single parameter only) (d ((\ x (\ y (+ x y))) 1 2)) # you can quote stuff, albeit unusually (d (' + 1 2)) # automatic currying (d (+ 1)) (d 42) (d ((+ 1) 2)) (d 69) # "thunks" (paramless lambdas) (d ((\\ (+ 1 2)))) # we've got cons, car, cdr, list (d (cons 1 2)) (d (car (cons 1 2))) (d (cdr (cons 1 2))) (d (')) # empty list (d (cons 1 ('))) # list with one elem (d (list 1 2 3)) # bools are just functions (d (t 1 0)) (d (f 1 0)) (d (<= 1 2)) (d ((<= 1 2) 1 0)) # <= is special: it compares lexicographically and can be used to test for nil (d ((<= (') (')) 1 0)) (d ((<= (') (' 1 2)) 1 0)) (d ((<= (' 1 2) (')) 1 0)) (d ((<= (' 1 2) (' 1 2)) 1 0)) # this is enough for a simple recursive fibonacci already (d ((\ f (f f 10)) (\ f (\ n (((<= n 1) (\\ n) (\\ (+ (f f (+ n (- 1))) (f f (+ n (- 2))))))))))) # multiple things are awkward here: # - nesting of lambdas # - no let(rec) # - thunks # it's time to introduce "macros". macros are like functions, # except they operate on the raw sexprs rather than the evaluated sexprs. # $ is like \, but the parameter is always called ... and is implicit. # "macro" "expansion" happens at runtime. (d (($ (car ...)) 1 2 3)) (($ (d (list (car (' d)) ...)) (cons (car (' d)) ...)) 1 2 3) (($ ... (list (list (car ...) (list (car (' \\)) (car (cdr ...))) (list (car (' \\)) (car (cdr (cdr ...))))))) t (d 1) (d 0)) # macros to solve the other problems are left as exercises to the reader |
1 | export function entry(h:string,n:string):[number,number]|null{for(let g=1;n.length*g<=h.length;++g){const m=RegExp(n.split('').map(c=>(/[.*+?^${}()|[\]\\]/.test(c)?'\\':'')+c).join(`.{${g-1}}`)).exec(h);if(m)return[m.index,--g]}return null}// dis onli wroks on WIDE CHARS because YES |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | /* Efficient longest increasing subsequence finding. Written for Code Guessing Round 47 (https://cg.esolangs.gay/47/). Input: Sequence of integers delimited by spacing, ex.: 4 5 2 6 3 5 Output: Subsequence in the same format, ex.: 4 5 6 Code may contain minor inconsistencies; the author was initially trying to conceal their style (this was for code guessing, after all) but then effectively backpedaled on that too. The author recommends using at least a gigabyte of IDE bloat to have a half-decent Groovy experience. */ class BigIntTree implements Iterable<Iterable<Integer>> { class Node { List<Integer> is Node left, right } Node root void set(BigInteger k, int i) { Node node = root ?= new Node() for (int j = k.bitLength() - 1; j > -1; --j) node = k.testBit(j) ? (node.right ?= new Node()) : (node.left ?= new Node()) (node.is ?= []).add(i) } // Breadth-first traversal of the tree gives lets us traverse the keys in sorted order // in linear time in the total number of digits in the input @Override Iterator<Iterable<Integer>> iterator() { List<Node> lvl = root == null ? [] : [root] int i = 0 return new Iterator<Iterable<Integer>>() { @Override boolean hasNext() { return !lvl.isEmpty() } @Override Iterable<Integer> next() { List<Integer> vs do { vs = lvl.get(i).is if (++i >= lvl.size()) { List<Node> nlvl = [] for (nd in lvl) { if (nd.left != null) nlvl.add(nd.left) if (nd.right != null) nlvl.add(nd.right) } lvl = nlvl i = 0 } } while (vs == null) return vs } } } } class Subseq { class Node { int i Node prev Node(int i, Node prev) { this.i = i this.prev = prev } } int len Node root static Subseq EMPTY = new Subseq() Subseq() {} Subseq(Subseq p, int i) { len = (p == null ? 0 : p.len) + 1 root = new Node(i, p.root) } BigInteger[] apply(BigInteger[] seq) { def res = new BigInteger[len] def node = this.root for (def i = len - 1; i > -1; i--) { res[i] = seq[node.i] node = node.prev } return res } } class SegmentTree { class Node { Subseq subseq = Subseq.EMPTY Node left, right Node(int n) { assert (n > 0) if (n == 1) return def mid = n >> 1 left = new Node(mid) right = new Node(n - mid) } // Get best subseq s with max(s) <= n Subseq get(int w, int n) { assert n <= w if (w == n) return subseq def mid = w >> 1 if (n <= mid) return left.get(mid, n) def ssl = left.subseq def ssr = right.get(w - mid, n - mid) return (ssr.len > ssl.len) ? ssr : ssl } // Set new best subseq s for max(s) <= n void set(int w, int n, Subseq ss) { assert n <= w if (w == n) { if (ss.len > subseq.len) subseq = ss return } if (ss.len > subseq.len) subseq = ss def mid = w >> 1 if (n <= mid) { left.set(mid, n, ss) return } // Note: We can't install this for left, since left has a stricter bound right.set(w - mid, n - mid, ss) } } Node root int n SegmentTree(int n) { root = new Node(this.n = n) } Subseq get(int n) { return root.get(this.n, n) } Subseq set(int n, Subseq ss) { return root.set(this.n, n, ss) } } static BigInteger[] solve(BigInteger[] seq) { if (seq.length == 0) return new BigInteger[0] def t = new BigIntTree() for (int i = 0; i < seq.length; ++i) t.set(seq[i], i) // Remove gaps in the ordering. // This is important for achieving good time complexity. int o = 0 def ordinals = new int[seq.length] for (is in t) { ++o for (i in is) ordinals[i] = o } // Do the "greedy" / "dynamic programming" solving // using a segment tree of best subsequences for upper bounds of the last element. def st = new SegmentTree(o) for (int i = 0; i < ordinals.length; ++i) { def n = ordinals[i] def ss = n == 1 ? Subseq.EMPTY : st.get(n - 1) st.set(n, new Subseq(ss, i)) } return st.get(o).apply(seq) } static BigInteger[] read() { def sc = new Scanner(System.in) List<BigInteger> s = [] while (sc.hasNext()) s << new BigInteger(sc.next()) return s.toArray(new BigInteger[s.size()]) } static void write(BigInteger[] subseq) { print(subseq[0]) for (int i = 1; i < subseq.length; i++) { print(" ") print(subseq[i]) } println() } static void main(String[] args) { write(solve(read())) } /* Runtime analysis: Let the input be a sequence of n numbers encoded in some base (say, binary, or decimal, with at least one digit per number), delimited by some delimiter. Then the length of the input is O(m), where m is the total count of digits in the input (in any fixed base). Constructing the prefix tree to sort the numbers is O(m) then, as is traversing the prefix tree in level-order (breadth-first, left to right); replacing numbers with their ordinals is O(m) as well (incrementing the ordinal o would be amortized constant time even if o were a bigint). For each distinct ordinal, there needs to be a distinct number in the input. To encode k distinct numbers, you need Θ(log(k)) bits (on average) for each number. This implies an input length of Θ(n log(k)) (in bits, bytes, characters, whatever, as long as it's fixed size). (This also imposes an upper bound of O(log n) on the length of each ordinal in bits, which is why this implementation elects to represent ordinals as "just integers": larger sequences couldn't be represented using Java data structures anyways.) The next step maintains a "segment tree" which maps maxima to longest subsequences using only elements encountered so far (a prefix of the sequence). Since the largest value is the largest ordinal, this segment tree has depth log(k). For each element in the sequence, one get and set operation are issued. Since these operations can both easily be seen (*) to be O(log(k)), we obtain O(n log(k)), which is true linear time in the input size (in bits, not in integer registers). (*) For a simplified analysis, assume a perfect binary segment tree (that is, k is a power of two). We presume big integers (which this implementation does not use for aforementioned reasons, but which are nevertheless relevant for runtime analysis). Then the comparison `w == n` would not be constant time, but for each bit it has to compare, it saves having to dive a layer deeper, so it is fine. Since we split perfectly in the middle, `n <= mid` would only have to look at the most significant bit. `w - mid` / `n - mid` effectively just removes that most significant bit, thus is also constant time. A proof of correctness will be supplied when the author finds the time and motivation. For now, you will have to take the author's "trust me bro" for it. Exercises left to the reader: * Test this thoroughly to convince yourself of the correctness. * Constant-factor optimization of the binary tree / prefix tree: "Compress" long paths of multiple bits (trie -> patricia tree) * Constant-factor optimization of the segment tree: Store it in an array, avoids many heap allocations, improves cache locality. * Rewrite this in a "better" programming language. */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ========================== CG 46: Find Candidate Keys ========================== Input ===== **Tab-Separated Values** (TSV) on standard input as Olive intended. The escape sequences ``\t``, ``\n``, ``\r`` and ``\\`` are supported. Example ------- Here is the example table in TSV format:: contest date held winner winner's second name dog fight oct 17 2000 discarding sabot sabot cat-off jul 01 2001 palm tree oil tree rat duel oct 05 2001 cart of iron of rat duel mar 21 2006 cart of iron of shark race mar 21 2006 linguist NULL Output ====== For consistency, the output is also **pseudo-TSV** that is written to standard output. Edge cases: * The empty set of columns is represented by an empty line. * The empty set of candidate keys is represented by no lines being printed. Example ------- Here is the output for the example table:: date held winner's second name date held winner contest date held |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ;; © 2042 Kim Apr (ns find_candidate_keys (:require [clojure.string :as str] [clojure.set :as set])) (def escs {"\\t" "\t" "\\n" "\n" "\\r" "\r" "\\\\" "\\"}) (defn rd-row [line] (map (fn [s] (str/replace s #"\\." (fn [c] (escs c c)))) (str/split line #"\t"))) (defn rd-tsv [] (let [ln (read-line)] (if (nil? ln) nil (cons (rd-row ln) (rd-tsv))))) (defn transp [rws] (let [rst-rws (rest rws)] (if (empty? rst-rws) (map list (first rws)) (map cons (first rws) (transp rst-rws))))) (defn ntrvl [col] (filter ;; clj-kondo WILL lie to you!!! (fn [cl] (not (empty? (rest cl)))) col)) (defn cl-add [cl i el] (assoc cl el (conj (cl el #{}) i))) (defn eq-cls [col] (vals (reduce (fn [cl pair] (let [[i el] pair] (cl-add cl i el))) {} (map-indexed vector col)))) (defn mapify-eq-cls [cls] (reduce (fn [map cl] (reduce (fn [map i] (assoc map i cl)) map cl)) {} cls)) (defn merge-eq-cls [cls1 cls2] (let [m2 (mapify-eq-cls cls2)] (reduce (fn [cls cl1] (reduce (fn [cls cl2] (cons (set/intersection cl1 cl2) cls)) cls (set (remove nil? (map m2 cl1))))) '() cls1))) (defn map-subseq [f seq] (if (empty? seq) '() (cons (f seq) (map-subseq f (rest seq))))) (defn cands [keys cnds] (if (empty? cnds) keys (reduce (fn [keys cnd] (if (empty? (cnd :eq)) (cons (rest (reverse (map (comp first first) (cnd :cols)))) keys) (cands keys (remove nil? (map-subseq (fn [col] (let [mrgd (ntrvl (merge-eq-cls (cnd :eq) (ntrvl (eq-cls (rest (first col))))))] (if (= (cnd :eq) mrgd) nil {:cols (cons col (cnd :cols)) :eq mrgd}))) (rest (first (cnd :cols)))))))) keys cnds))) (defn cnd-empty [cols] (list {:cols (list (cons '() cols)) :eq (ntrvl (list (set (range (count (rest (first cols)))))))})) (def unescs (set/map-invert escs)) (defn wr-row [cnd] (println (str/join "\t" (map ;; It is with great disgust that I have to inform you that `.` in Java ;; matches "any character (may or may not match line terminators)" (fn [s] (str/replace s #".|\r|\n" (fn [c] (unescs c c)))) cnd)))) (defn wr-tsv [cnds] (run! wr-row cnds)) (wr-tsv (cands '() (cnd-empty (transp (rd-tsv))))) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | import std/bitops import std/strutils import std/options type X = range[0'u8..6'u8] Y = range[0'u8..5'u8] Stack = set[Y] Mask = array[X, Stack] Board = tuple[ours: Mask, theirs: Mask] type RowBitset = range[0'u8..127'u8] proc winRowUtil (row: RowBitset): bool = (row and 0b0001111) == 0b0001111 or (row and 0b0011110) == 0b0011110 or (row and 0b0111100) == 0b0111100 or (row and 0b1111000) == 0b1111000 var winRows: set[RowBitset] for i in RowBitset(0)..127'u8: if winRowUtil(i): winRows.incl i proc winRow (row: RowBitset): bool = row in winRows proc row (m: Mask, y: Y): RowBitset = for x in X(0)..6: if y in m[x]: result = result or (1'u8 shl x) proc ascDiag (m: Mask, x: X, y: Y): RowBitset = var j = 0'u8 for i in -int8(x.min(y))..int8((6-x).min(5-y)): if Y(int8(y) + i) in m[X(int8(x) + i)]: result = result or (1'u8 shl j) j += 1 proc descDiag (m: Mask, x: X, y: Y): RowBitset = var j = 0'u8 for i in -int8((6-x).min(y))..int8(x.min(5-y)): if Y(int8(y) + i) in m[X(int8(x) - i)]: result = result or (1'u8 shl j) j += 1 proc winMove (m: Mask, x: X, y: Y): bool = winRow(cast[RowBitset](m[x])) or winRow(m.row(y)) or winRow(m.descDiag(x, y)) or winRow(m.ascDiag(x, y)) proc top (board: Board, x: X): Option[Y] = let used = cast[uint8](board.ours[x] + board.theirs[x]) if used == 0: return Y(0).some let y = 8 - used.countLeadingZeroBits if y > 5: return Y.none return Y(y).some #[ import std/unittest suite "bot": test "winRow": check(winRow 0b1111000) check(winRow 0b0111100) check(winRow 0b0011110) check(winRow 0b0001111) check(not winRow 0b0001101) let m: Mask = [ {1, 2, 3}, {0, 3}, {1, 2}, {0, 1}, {0, 4}, {3, 4, 5}, {1, 2, 3}, ] test "row": check(m.row(0) == 0b0011010) check(m.row(1) == 0b1001101) test "ascDiag": check(m.ascDiag(1, 1) == 0b110100) test "descDiag": check(m.descDiag(1, 1) == 0b100) test "winMove": let m: Mask = [{1, 2, 3, 4}, {}, {}, {}, {}, {}, {}] check(m.winMove(0, 4)) test "top": check((ours: m, theirs: m).top(5) == none(Y)) check((ours: m, theirs: m).top(1) == some(Y(4))) ]# proc applyMove (board: var Board, x: X, ours: bool) = let y = board.top(x).get if ours: board.ours[x].incl y else: board.theirs[x].incl y proc maximize (board: Board, depth: uint8): tuple[score: float, move: X] = if depth > 7: return result.score = -1 var foundValidMove = false for x in X(0)..6: let top = board.top(x) if top.isNone: continue let y = top.unsafeGet foundValidMove = true # Pick a valid move, even if it may seem futile. if result.score == -1: result.move = x var ours = board.ours ours[x].incl y if ours.winMove(x, y): return (score: 1, move: x) let min = -(ours: board.theirs, theirs: ours).maximize(depth + 1).score # Indirect win forcable? if min == 1: return (score: 1, move: x) if min > result.score: result.score = min result.move = x # Returns an invalid move value (0) but meh if not foundValidMove: result.score = 0 var board: Board proc makeMove () = let move = board.maximize(0).move board.applyMove(move, true) echo $(move + 1) let line = stdin.readLine if line == "f": makeMove() else: assert line == "s" while true: let move = stdin.readLine.parseUInt() assert move >= 1 and move <= 7 board.applyMove(X(move - 1), false) makeMove() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import os import osproc import std/strutils import std/streams type Spot = enum Free, Ours, Theirs Stack = array[6, Spot] Board = array[7, Stack] var board: Board var winner: Spot = Free proc printBoard = for row in countdown(5, 0): for col in 0..6: const spotChar: array[Spot, char] = ['.', 'O', 'X'] stdout.write spotChar[board[col][row]] stdout.write '\n' stdout.flushFile() proc invalidMove (move: uint): bool = move < 1 or move > 7 or board[move - 1][^1] != Free proc inBounds (x, y: int): bool = x >= 0 and x < 7 and y >= 0 and y < 6 proc countDir(x, y: uint, dx, dy: int): uint = var count: uint = 0 var x = int(x) var y = int(y) let expected = board[x][y] while true: x += dx y += dy if not inBounds(x, y) or board[x][y] != expected: break count += 1 return count proc checkWinDir (x, y: uint, dx, dy: int): bool = return countDir(x, y, -dx, -dy) + 1 + countDir(x, y, dx, dy) >= 4 proc checkWin (x, y: uint): bool = checkWinDir(x, y, 0, 1) or checkWinDir(x, y, 1, 0) or checkWinDir(x, y, 1, 1) var moves = 0 proc makeMove (move: uint, player: Spot) = assert player != Free for y, spot in board[move]: if spot == Free: board[move][y] = player if checkWin(move, uint(y)): winner = player moves += 1 break var bot = startProcess(paramStr(1), options = {}) var botIn = bot.inputStream var botOut = bot.outputStream proc sendCommand (command: string) = botIn.writeLine command botIn.flush sendCommand "s" # hoomans go first! while true: printBoard() if winner != Free or moves == 6*7: break block: echo "Make a move:" let move = stdin.readLine.parseUInt if invalidMove(move): echo "Invalid move" continue makeMove(move - 1, Ours) sendCommand $move if winner == Free: var line: string assert botOut.readLine line let move = line.parseUInt if invalidMove(move): echo "Invalid move from bot" break # can't resume with a broken bot makeMove(move - 1, Theirs) bot.terminate bot.close const outcome: array[Spot, string] = ["Draw", "You win!", "They win!"] echo outcome[winner] |
1 2 | Compile bot (or client): nim compile -d:release bot Use client: ./client bot |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #programmer time (MY TIME) is worth MOAR than cpu time!!!!!! import argparse from collections import Counter from itertools import permutations,product class Param: n=1 def eval(it): return next(it) class Expr: def __init__(self,l,op,r): self.l,self.op,self.r,self.n=l,op,r,l.n+r.n def eval(self,it): l,r=self.l.eval(it),self.r.eval(it) match self.op: case '+': return l+r case '*': return l*r case '-': return float('nan') if l<r else l-r case '/': return float('nan') if not r or l%r else l/r class Bag: def __init__(self,s): self.ops=Counter() self.digits=Counter() for c in s: if c in '+-*/': self.ops.update((c,)) elif (d:=ord(c)-ord('0')) in range(10): self.digits.update((d,)) else: raise ValueError('invalid string') def _exprs(ops): yield Param if not any(ops.values()): return nz=[o for o in ops if ops[o]] if sum(1 for _ in nz)==1 and (op:=nz[0]) in '+*': e=Param for _ in range(ops[op]): yield (e:=Expr(e,op,Param)) return for op in ops: ops[op]-=1 for splt in product(*(range(ops[o]+1) for o in ops)): for l,r in product(Bag._exprs({o:n for n,o in zip(splt,ops)}),Bag._exprs({o:ops[o]-n for n,o in zip(splt,ops)})): yield Expr(l,op,r) ops[op]+=1 def exprs(self): return Bag._exprs(self.ops) def params(self,n): return permutations(self.digits,r=n) def solve(self,num): return min((expr.eval(iter(params)) for expr in self.exprs() for params in self.params(expr.n)),key=lambda x:abs(num-x)) if __name__=='__main__': parser=argparse.ArgumentParser() parser.add_argument('bag') parser.add_argument('num') args=parser.parse_args() print(Bag(args.bag).solve(int(args.num))) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | -- (c) 2021 🥺🥺🥺 -- this code was manualy cursed to meet the lowest standards ✅✅✅ -- "Inter-token spacing is the root of all evil." - Mahatma Gandhi local splurped={} do local ts={_G} local s={} repeat local ns={} local fr={} for _,t in pairs(ts) do s[t]=1 for k,v in pairs(t) do if fr[k]==nil then fr[k]=v else fr[k]=fr end if type(v)=="table" and not s[v] then ns[#ns+1]=v end end end for k,v in pairs(fr) do if splurped[k]==nil and v~=fr then splurped[k]=v end end ts=ns until#ts==0 end setfenv(1,setmetatable({},{__index=splurped})) local function mapva(f,...) if select("#",...)==0 then return end return f((...)),mapva(f,select(2,...)) end p,x,pts,stp=400,0,{},{} -- 400² is the HOLY RESOLUTION - DO NOT TOUCH! function love.load(args) R,r,d=mapva(tonumber,unpack(args)) m=p/(R-r+abs(d))*0.5*0.75 R,r,d=R*m,r*m,d*m mdt = min(abs(1/(R-r)),abs(r/(R-r)/d))/10 setTitle(((r<0)and"epi"or"hypo").."trochoid") setMode(p,p) end function love.update(fdt) n=ceil(fdt/mdt) dt=fdt/n for i=1,n do x=x-dt y=-x*(R-r)/r cx,cy=p/2,p/2 rx,ry=cx+(R-r)*cos(x),cy+(R-r)*sin(x) px,py=floor(rx-d*cos(y)),floor(ry-d*sin(y)) h=py*p+px if not stp[h] then stp[h]=1 insert(pts,{px,py}) end end end function love.draw() setColor(0,1,0,1) ellipse("line",cx,cy,R,R) ellipse("line",rx,ry,abs(r),abs(r)) line(rx,ry,px,py) setColor(1,0,0,1) points(pts) end |
1 2 3 | so uh i maded some sussy hax but they shoud work on LOVE 11.3 (Mysterious Mysteries) oh uh also run is "love . R r d" in foldr |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | // Simple 2048 game for the terminal use crossterm::{ self, cursor, event::{read, Event, KeyCode}, execute, queue, terminal, }; use rand::Rng; use std::{ fmt, io::{self, Stdout, Write}, }; #[derive(Copy, Clone, PartialEq)] enum Move { Left, Right, Up, Down, } impl TryFrom<KeyCode> for Move { type Error = (); fn try_from(value: KeyCode) -> Result<Self, Self::Error> { match value { KeyCode::Left | KeyCode::Char('a') => Ok(Move::Left), KeyCode::Right | KeyCode::Char('d') => Ok(Move::Right), KeyCode::Up | KeyCode::Char('w') => Ok(Move::Up), KeyCode::Down | KeyCode::Char('s') => Ok(Move::Down), _ => Err(()), } } } #[derive(PartialEq, Clone)] struct Board { tiles: [[u8; 4]; 4], } impl Board { fn random_tile() -> u8 { if rand::thread_rng().gen_range(1..=10) == 10 { 2 } else { 1 } } fn place_random_tile(&mut self) { loop { let y = rand::thread_rng().gen_range(0..4); let x = rand::thread_rng().gen_range(0..4); if self.tiles[y][x] == 0 { self.tiles[y][x] = Self::random_tile(); break; } } } fn init() -> Self { let mut this = Self { tiles: [[0; 4]; 4] }; this.place_random_tile(); this.place_random_tile(); this } fn transpose(&mut self) { let tiles = &mut self.tiles; for y in 0..tiles.len() { for x in 0..y { (tiles[y][x], tiles[x][y]) = (tiles[x][y], tiles[y][x]); } } } fn reverse_rows(&mut self) { for row in self.tiles.as_mut() { row.reverse() } } fn move_left(&mut self) { for row in self.tiles.as_mut() { for x in 1..4 { let mut nx = x; while nx > 0 && row[nx - 1] == 0 { nx -= 1; } if nx > 0 && row[nx - 1] == row[x] { row[nx - 1] += 1; row[x] = 0; } else if nx < x { row[nx] = row[x]; row[x] = 0; } } } } fn make_move(&mut self, mov: Move) { match mov { Move::Left => self.move_left(), Move::Right => { self.reverse_rows(); self.move_left(); self.reverse_rows(); } Move::Up => { self.transpose(); self.move_left(); self.transpose(); } Move::Down => { self.transpose(); self.reverse_rows(); self.move_left(); self.reverse_rows(); self.transpose(); } } } fn valid_moves(&self) -> impl Iterator<Item = &Move> { [Move::Left, Move::Right, Move::Up, Move::Down] .iter() .filter(|&&mov| { let mut clone = self.clone(); clone.make_move(mov); clone != *self }) } fn won(&self) -> bool { const TILE_2048: u8 = 11; self.tiles.iter().flatten().any(|&t| t == TILE_2048) } } // TODO (...) the hardcoded carriage returns for raw terminal mode feel dirty. impl fmt::Display for Board { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let sep: String = "+----".repeat(4) + "+\r\n"; for row in self.tiles { f.write_str(&sep)?; f.write_str( &(String::from("|") + &row .map(|tile| { if tile == 0 { " ".into() } else { format!("{:^4}", 1 << tile) } }) .join("|") + "|\r\n"), )?; } f.write_str(&sep)?; Ok(()) } } struct RawTerminal { stdout: Stdout, } impl RawTerminal { fn init() -> Result<Self, io::Error> { terminal::enable_raw_mode()?; let mut stdout = io::stdout(); execute!( stdout, terminal::EnterAlternateScreen, crossterm::cursor::Hide )?; Ok(Self { stdout }) } fn queue_reset(&mut self) -> Result<(), io::Error> { queue!( self.stdout, terminal::Clear(terminal::ClearType::FromCursorUp), cursor::MoveTo(0, 0) ) } fn flush(&mut self) -> Result<(), io::Error> { self.stdout.flush() } } impl Drop for RawTerminal { fn drop(&mut self) { execute!( self.stdout, crossterm::cursor::Show, terminal::LeaveAlternateScreen ) .unwrap(); terminal::disable_raw_mode().unwrap(); } } enum GameOutcome { Win, Loss, Quit, } fn play() -> Result<GameOutcome, io::Error> { let mut terminal = RawTerminal::init()?; let mut board = Board::init(); 'game: loop { terminal.queue_reset()?; print!("{board}"); print!("arrow keys or WASD to play, q to quit"); terminal.flush()?; if board.won() { return Ok(GameOutcome::Win); } let valid_moves: Vec<&Move> = board.valid_moves().collect(); if valid_moves.is_empty() { return Ok(GameOutcome::Loss); } let mov = loop { match read()? { Event::Key(event) => { if event.code == KeyCode::Char('q') { return Ok(GameOutcome::Quit); } if let Ok(mov) = Move::try_from(event.code) { if valid_moves.contains(&&mov) { break mov; } } } Event::Resize(_, _) => { continue 'game; } _ => (), } }; board.make_move(mov); board.place_random_tile(); } } fn main() { let outcome = play().unwrap(); println!( "{}", match outcome { GameOutcome::Win => "You win!", GameOutcome::Loss => "You lose!", GameOutcome::Quit => "quit", } ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "_2048" version = "0.1.0" dependencies = [ "crossterm", "rand", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossterm" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ "bitflags 2.4.0", "crossterm_winapi", "libc", "mio", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "getrandom" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "lock_api" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "mio" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", "wasi", "windows-sys", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", "mio", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "smallvec" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" |
1 2 3 4 5 6 7 8 | [package] name = "_2048" version = "0.1.0" edition = "2021" [dependencies] rand = "0.8.5" crossterm = "0.27.0" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | // FALSE bytecode compiler & VM for round 41 of code guessing (https://cg.esolangs.gay/41/). // Written by Lars Müller. Licensed under the MIT license. // Compile using `zig build-exe 41.zig -O ReleaseFast -fstrip -fsingle-threaded`. const std = @import("std"); const Allocator = std.mem.Allocator; const Op = enum(u32) { // 🥺 Push, GetReg, SetReg, // Stack reordering Dup, Drop, Swap, Rot, Index, // Binops Add, Sub, Mul, Div, And, Or, Eq, Gt, // Unops Inv, Neg, // Control flow Jmp, Call, CallIf, Ret, LoopSetup, LoopTest, LoopBody, // I/O ReadByte, WriteByte, WriteInt, // technically redundant (like plenty of other instructions too) but I'm too laziggy and performance or something Flush, }; // teknikhally this is a bytecode builder - 🤓 const Bytecode = struct { allocator: Allocator, words: std.ArrayList(u32), pub fn init(allocator: Allocator) Bytecode { return Bytecode{.allocator = allocator, .words = std.ArrayList(u32).init(allocator)}; } pub fn deinit(self: *Bytecode) void { self.words.deinit(); } pub fn getWords(self: *Bytecode) []u32 { return self.words.items; } fn emit(self: *Bytecode, op: Op) !void { try self.words.append(@intFromEnum(op)); } fn emitToPatch(self: *Bytecode) !usize { try self.words.append(0xDEADBEEF); return self.words.items.len - 1; } fn patch(self: *Bytecode, i: usize, u: u32) void { self.words.items[i] = u; } fn emitPush(self: *Bytecode, u: u32) !void { try self.emit(.Push); try self.words.append(u); } fn append(self: *Bytecode, other: Bytecode) !u32 { const nextPos: u32 = @intCast(self.words.items.len); try self.words.appendSlice(other.words.items); return nextPos; } }; // shot🔫 parser & bytecode emitter fn Compiler(comptime R: type) type { return struct { const Self = @This(); allocator: Allocator, in: R, b: ?u8 = null, bytecode: Bytecode, pub fn init(allocator: Allocator, in: R) Self { return Self{.allocator = allocator, .in = in, .bytecode = Bytecode.init(allocator)}; } pub fn reset(self: *Self) void { self.b = null; self.bytecode = Bytecode.init(self.allocator); } pub fn deinit(self: *Self) void { self.bytecode.deinit(); } fn readByte(self: *Self) !u8 { const b = self.b; if (b == null) return self.in.readByte(); self.b = null; return b.?; } fn unreadByte(self: *Self, b: u8) void { self.b = b; } pub fn compileFn(self: *Self) !u32 { var bytecode = Bytecode.init(self.allocator); defer bytecode.deinit(); while (true) { const b = self.readByte() catch |err| { if (err == error.EndOfStream) break; return err; }; try switch (b) { '\t', ' ', '\n' => {}, '{' => while (try self.readByte() != '}') {}, '"' => while (true) { const quotedB = try self.readByte(); if (quotedB == '"') break; try bytecode.emitPush(@as(u32, quotedB)); try bytecode.emit(.WriteByte); }, '\'' => { const quotedB = try self.readByte(); try bytecode.emitPush(@as(u32, quotedB)); }, '0' ... '9' => { var u: u32 = b - '0'; var nb: u8 = undefined; while (true) { nb = self.readByte() catch |err| { if (err == error.EndOfStream) break; return err; }; if (nb < '0' or nb > '9') break; u = 10 * u + nb - '0'; } self.unreadByte(nb); try bytecode.emitPush(u); }, 'a' ... 'z' => try bytecode.emitPush(@as(u32, b - 'a')), '[' => { try bytecode.emit(.Push); const i = try bytecode.emitToPatch(); bytecode.patch(i, try self.compileFn()); if (try self.readByte() != ']') return error.UnclosedQuote; }, ']' => { self.unreadByte(']'); break; }, '!' => bytecode.emit(.Call), '?' => bytecode.emit(.CallIf), '#' => { // too laziggy to relocate addresses for jumps so here you go, loops get three instructions for ([_]Op{.LoopSetup, .LoopTest, .LoopBody}) |op| try bytecode.emit(op); }, else => try bytecode.emit(switch (b) { ';' => .GetReg, ':' => .SetReg, '$' => .Dup, '%' => .Drop, '\\' => .Swap, '@' => .Rot, 'O' => .Index, '+' => .Add, '-' => .Sub, '/' => .Div, '*' => .Mul, '|' => .Or, '&' => .And, '=' => .Eq, '>' => .Gt, '~' => .Inv, '_' => .Neg, '^' => .ReadByte, ',' => .WriteByte, '.' => .WriteInt, 'B' => .Flush, else => return error.InvalidInstruction, // includes '`' }), }; } try bytecode.emit(.Ret); return try self.bytecode.append(bytecode); } pub fn compile(self: *Self) !Bytecode { try self.bytecode.emit(.Push); const i = try self.bytecode.emitToPatch(); try self.bytecode.emit(.Jmp); self.bytecode.patch(i, try self.compileFn()); const bytecode = self.bytecode; self.reset(); return bytecode; } }; } // we skimp on error checking here (gotta go fast); // FALSE programmers can be trusted to not ever make oopsies // thus there is no typechecking (num/quote/char/reg etc.) here, // no bounds checking, no stack overflow or underflow checking // (Zig will trap the "unreachable" code though) fn VM(comptime R: type, comptime W: type) type { return struct { const Self = @This(); stack: std.ArrayList(u32), retstack: std.ArrayList(u32), regs: [32]u32 = undefined, // did you want zeroes? no zeroes for you. // i already gifted you a few registers, be grateful! in: R, out: W, pub fn init(allocator: Allocator, in: R, out: W) Self { return Self{ .stack = std.ArrayList(u32).init(allocator), .retstack = std.ArrayList(u32).init(allocator), .in = in, .out = out, }; } pub fn deinit(vm: *Self) void { vm.flush(); vm.stack.deinit(); vm.retstack.deinit(); } fn pop(vm: *Self) u32 { return vm.stack.pop(); // what is an error? } fn push(vm: *Self, u: u32) void { vm.stack.append(u) catch unreachable; // gotta go fast } fn drop(vm: *Self) void { _ = vm.pop(); } fn dup(vm: *Self) void { vm.push(vm.stack.getLast()); } fn swap(vm: *Self) void { const top = vm.pop(); const bot = vm.pop(); vm.push(top); vm.push(bot); } fn rot(vm: *Self) void { const top = vm.pop(); const mid = vm.pop(); const bot = vm.pop(); vm.push(mid); vm.push(top); vm.push(bot); } fn index(vm: *Self) void { const j = vm.pop(); const i = vm.stack.items.len - j - 1; vm.push(vm.stack.items[i]); // what is an OOB } fn binop(vm: *Self, comptime op: fn(lhs: u32, rhs: u32) u32) void { const rhs = vm.pop(); const lhs = vm.pop(); vm.push(op(lhs, rhs)); } // u32, i32, it's all the same (modular arithmetic says hi) fn add(lhs: u32, rhs: u32) u32 { return lhs +% rhs; } fn sub(lhs: u32, rhs: u32) u32 { return lhs -% rhs; } fn mul(lhs: u32, rhs: u32) u32 { return lhs *% rhs; } fn div(lhs: u32, rhs: u32) u32 { return @divTrunc(lhs, rhs); } fn band(lhs: u32, rhs: u32) u32 { return lhs & rhs; } fn bor(lhs: u32, rhs: u32) u32 { return lhs | rhs; } fn eq(lhs: u32, rhs: u32) u32 { return if (lhs == rhs) ~@as(u32, 0) else 0; } // okay *maybe* i lied and it's not quite as shrimple fn gt(lhs: u32, rhs: u32) u32 { // *portability* rules so let's write some inefficient branching code const sl = lhs >> 31; const sr = rhs >> 31; return if (if (sl == sr) lhs > rhs else sl < sr) ~@as(u32, 0) else 0; } fn unop(vm: *Self, comptime op: fn(i: u32) u32) void { vm.push(op(vm.pop())); } fn negate(i: u32) u32 { return 1 +% ~i; } // you should have recognized this! fn invert(i: u32) u32 { return ~i; } fn getReg(vm: *Self) void { const i = vm.pop(); vm.push(vm.regs[@intCast(i)]); // OOBs don't happen, do they? } fn setReg(vm: *Self) void { const i = vm.pop(); const v = vm.pop(); vm.regs[@intCast(i)] = v; } fn readByte(vm: *Self) void { // no distinguishing EOF and other "errors" because yes vm.push(vm.in.readByte() catch ~@as(u32, 0)); } fn _writeByte(vm: *Self, b: u8) void { const bs = [_]u8{b}; // should we assert that it wrote exactly one character? _ = vm.out.write(bs[0..]) catch unreachable; // nah, nothing will go wrong. } fn writeByte(vm: *Self) void { vm._writeByte(@truncate(vm.pop())); } fn writeInt(vm: *Self) void { var i = vm.pop(); const negative = i >> 31 == 1; if (negative) { vm._writeByte('-'); i = 1 + ~i; } // maybe i should look up the library function for this var buf: [16]u8 = undefined; var j: u8 = 0; while (true) { buf[j] = @truncate(i % 10); j += 1; i = @divTrunc(i, 10); if (i == 0) break; } while (true) { j -= 1; vm._writeByte(buf[j] + '0'); if (j == 0) break; } } fn flush(vm: *Self) void { vm.out.flush() catch unreachable; } pub fn run(vm: *Self, bytecode: []const u32) void { vm.retstack.append(@intCast(bytecode.len)) catch unreachable; // main func returning should end the program not pop an empty stack var ip: u32 = 0; while (ip < bytecode.len) { const op: Op = @enumFromInt(bytecode[ip]); switch (op) { // Control flow .Push => { vm.push(bytecode[ip + 1]); // surely this won't OOB ip += 2; continue; }, .Jmp => { ip = vm.pop(); continue; }, .Call => { vm.retstack.append(ip + 1) catch unreachable; ip = vm.pop(); continue; }, .Ret => { ip = vm.retstack.pop(); continue; }, .CallIf => { const q = vm.pop(); const v = vm.pop(); if (v != 0) { vm.retstack.append(ip + 1) catch unreachable; // gotta go fast ip = q; continue; } }, .LoopSetup => { const body = vm.pop(); const cond = vm.pop(); vm.retstack.append(body) catch unreachable; vm.retstack.append(cond) catch unreachable; }, .LoopTest => { const cond = vm.retstack.getLast(); vm.retstack.append(ip + 1) catch unreachable; // gotta go fast ip = cond; continue; }, .LoopBody => { if (vm.pop() != 0) { const body = vm.retstack.items[vm.retstack.items.len - 2]; vm.retstack.append(ip - 1) catch unreachable; // this is a sneaky one ip = body; continue; } // pop cond & body _ = vm.retstack.pop(); _ = vm.retstack.pop(); }, // everything else .Dup => vm.dup(), .Drop => vm.drop(), .Swap => vm.swap(), .Rot => vm.rot(), .Index => vm.index(), .Add => vm.binop(add), .Sub => vm.binop(sub), .Mul => vm.binop(mul), .Div => vm.binop(div), .And => vm.binop(band), .Or => vm.binop(bor), .Eq => vm.binop(eq), .Gt => vm.binop(gt), .Neg => vm.unop(negate), .Inv => vm.unop(invert), .GetReg => vm.getReg(), .SetReg => vm.setReg(), .ReadByte => vm.readByte(), .WriteByte => vm.writeByte(), .WriteInt => vm.writeInt(), .Flush => vm.flush(), } ip += 1; } } }; } pub fn main() !void { var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(general_purpose_allocator.deinit() == .ok); const gpa = general_purpose_allocator.allocator(); var args = try std.process.argsWithAllocator(gpa); defer args.deinit(); if (!args.skip()) return error.InvalidUsage; const path = args.next(); if (path == null) return error.InvalidUsage; var file = try std.fs.cwd().openFile(path.?, .{}); defer file.close(); var buf = std.io.bufferedReader(file.reader()); var in = buf.reader(); var compiler = Compiler(@TypeOf(in)).init(gpa, in); defer compiler.deinit(); var bytecode = try compiler.compile(); defer bytecode.deinit(); var bufStdin = std.io.bufferedReader(std.io.getStdIn().reader()); var stdinReader = bufStdin.reader(); var bufStdout = std.io.bufferedWriter(std.io.getStdOut().writer()); var vm = VM(@TypeOf(stdinReader), @TypeOf(bufStdout)).init(gpa, stdinReader, bufStdout); defer vm.deinit(); vm.run(bytecode.getWords()); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | { FALSE self-interpreter. Takes a FALSE program as input, followed by `<` as a delimiter, followed by program input. If there is no program input, the `<` delimiter can be omitted. Expects ASCII: B rather than ß and O rather than ø. Written by Lars Müller (https://github.com/appgurueu) for round 41 of code guessing (https://cg.esolangs.gay/41/). Licensed under the MIT license. Heavily uses variables as to not interfere with what it's doing on the stack (splicing the stack, emitting bytecode on the stack or using the stack as the interpreter stack). Some FALSE operations will have linear time complexity in the size of the stack in this interpreter. That is, polynomial vs. superpolynomial time is preserved, but programs may get a linear time complexity factor. } { shove/splice (s): pop n elements, then call f to mutate the stack, then restore the popped elements invocation: [...]f: 42n: 32m: s;! } [ n;0= $[% f;! 0~]? ~[ m;0= $[ % {kill cond} % {kill a zero on stack} n; 1- n: 32 m: s;! 0 {this is to be left on the stack} 0~ {this will be killed (cond)} ]? ~[ m; 1- m: $ 1& {extract lowest bit} \ 2/ \ {>> 1 thing on stack} $[ % s;! 2* 1| 0~ ]? ~[ s;! 2* ]? ]? ]? ]s: { Compiler. Leaves bytecode on stack. Uses`<` to delimit program and input. } 0l: {bytecode length} 0t: 0n: {state t: 0 = default, 1 = number; n holds the numerical value of the number} [^c: c;'<= c;1_= | ~] {loop until `<` or EOF is encountered} [ 1h: {to handle? set to 0 if handled} '0c;> c;'9> | ~[ c; '0- n; 10* + n: {add digit to numerical value} 1t: {we have a number now} 0h: ]? h;[ t;['P n; l;2+l:]? {emit a num push if necessary} 0t: 0n: {reset state to "not a number, numerical value 0"} ]? {variables} 'ac;> c;'z> | ~[ 'P c;'a- l;2+l: 0h: ]? {character literals} c;''=[ 'P ^ {pls don't EOF here oki?} l;2+l: 0h: ]? {whitespace} c;32{space}= c;9{tab}= c;10{newline}= ||[ 0h: {ignore whitespace; don't push it} ]? {comments} c;'{=[ [^'}=~][]# 0h: ]? {string literals} c;'"=[ [^$'"=~][ {push char, then write char} 'P \ ', l;3+l: ]# % {murder the closing "} 0h: ]? {lambdas} c;'[=[ 'J 55555 {jump, address is to be replaced} l;2+l: {NOTE: we can reuse n here since it was already emitted} [l;]f: l;n: 32m: s;! {push start address of function on stack} 0h: ]? c;']=[ {TODO (...) check balance} [q:]f: l;n: 32m: s;! {this should pop the top of the funcinfo stack, which starts right under the bytecode} 'R l;1+l: {emit return} l;q; - n: {this is the length of the function - how many things to skip until we can edit the jump address before the function} [% l;]f: 32m: s;! {replace jump address} 'P q; {return, push lambda} l;2+l: 0h: ]? c;'#=[ 'S 'T 'L l;3+l: 0h: ]? {TODO (...) reject invalid characters} h;[ c; l;1+l: ]? ]# t;['P n; l;2+l:]? {deal with a trailing number (not that it would matter)} 'E {mark end of bytecode} { Interpreter. Does everything on the stack. Stack layout: Bytecode, call stack, variables, working stack. } l; b: {base of the stack (start of bytecode) relative to the top} l; c: {top of the call stack, relative to base} {variables come after the call stack (c+x); push 26 var slots} 0 i: [i;26=~][ 123456 {for easier debugging} i;1+i: ]# b;26+b: 0 i: {program counter relative to b} [b;i;-O 'E =~] {loop until sentinel is reached} [ b;i;-O {fetch instruction} $'P=[% i;1+i: b;i;-O b;1+b: 'E]? {push 'P <value>} {variables} $';=[% {take something from the stack as offset to add to c, then use as index} b;c;-\- 2-{1- for what we just popped, another 1- because it is in ':} O {-1+1=0} 'E]? $':=[% {stack: val regno} \ v: {save val} b;2-b: b;c;- \ - 1- n: {n = b - c - regno - 1} [% v;]f: 32m: s;! {replace variable on stack} 'E]? {control flow} {jump 'J <address>} $'J=[% i;1+i: b;i;-O 1-{to undo later 1+}i: {set PC} 'E]? {pop and call} $'!=[% g: {pop & remember function to call} [i;1+]f: b;c;- n: 32m: s;! {push next pc to call stack} c;1+c: g;1-{to undo later 1+}i: {set PC} {-1+1=0} 'E]? {conditional call} $'?=[% b;2-b: {will pop two things} g: {remember func addr.} [ {push to call stack} [i;1+]f: b;1+{pretend it was one larger (cmp with '! to see why)}c;- n: 32m: s;! c;1+c: g;1-{to undo later 1+}i: {set pc} b;1+b: {pushed one thing on call stack} ]? {this pops!} 'E]? {loop setup} $'S=[% g: o: {remember func addr.} {push condition & body lambdas on the call stack} [g;o;]f: b;2-c;- n: 32m: s;! c;2+c: {no need to adjust base; all we did was move two things from stack to call stack} 'E]? {loop test} $'T=[% b;c;- O {this is just the code for a call of `g`} g: [i;1+]f: b;1+c;- n: 32m: s;! c;1+c: g;1-i: b;1+b: {pushed addr to call stack, popped nothing (cond remains on call stack)} 'E]? {loop looping} $'L=[% b;1-b: w: w;[ b;c;-1+{body lies one deeper than cond} O {this is just the code for a call of `g`} g: [i;1-{sneaky one: go back to T instr}]f: b;1+c;- n: 32m: s;! c;1+c: g;1-i: b;1+b: ]? w;0=[ {clean up call stack: drop cond and body} [%%]f: b;c;- n: 32m: s;! c;2-c: b;2-b: ]? 'E]? {return} $'R=[% c;1-c: {pop from call stack} [ 1-{to undo later 1+}i: ]f: b;c;-n: 32m: s;! b;1-b: 'E]? {binops} $'+=[% + b;1-b: 'E]? $'-=[% - b;1-b: 'E]? $'*=[% * b;1-b: 'E]? $'/=[% / b;1-b: 'E]? $'&=[% & b;1-b: 'E]? $'|=[% | b;1-b: 'E]? $'>=[% > b;1-b: 'E]? $'==[% = b;1-b: 'E]? {unops} $'~=[% ~ 'E]? $'_=[% _ 'E]? {stack ops; these are funky} $'\=[% \ 'E]? $'@=[% @ 'E]? $'%=[% % b;1-b: 'E]? $'$=[% $ b;1+b: 'E]? $'O=[% O {+1-1} 'E]? {I/O; compiler needs to handle "..."} $'B=[% B 'E]? $'^=[% ^ b;1+b: 'E]? $',=[% , b;1-b: 'E]? '.=[. B b;1-b:]? i;1+i: ]# |
1 2 3 4 5 6 7 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <!-- The INTERNET permission is required for development. Specifically, the Flutter tool needs it to communicate with the running application to allow setting breakpoints, to provide hot reload, etc. --> <uses-permission android:name="android.permission.INTERNET"/> </manifest> |
1 2 3 4 5 6 | package com.example.fifteen import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { } |
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="utf-8"?> <!-- Modify this file to customize your launch splash screen --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@android:color/white" /> <!-- You can insert your own image assets here --> <!-- <item> <bitmap android:gravity="center" android:src="@mipmap/launch_image" /> </item> --> </layer-list> |
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="utf-8"?> <!-- Modify this file to customize your launch splash screen --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="?android:colorBackground" /> <!-- You can insert your own image assets here --> <!-- <item> <bitmap android:gravity="center" android:src="@mipmap/launch_image" /> </item> --> </layer-list> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="utf-8"?> <resources> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> <!-- Show a splash screen on the activity. Automatically removed when the Flutter engine draws its first frame --> <item name="android:windowBackground">@drawable/launch_background</item> </style> <!-- Theme applied to the Android Window as soon as the process has started. This theme determines the color of the Android Window while your Flutter UI initializes, as well as behind your Flutter UI while its running. This Theme is only used starting with V2 of Flutter's Android embedding. --> <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> <item name="android:windowBackground">?android:colorBackground</item> </style> </resources> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="utf-8"?> <resources> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> <!-- Show a splash screen on the activity. Automatically removed when the Flutter engine draws its first frame --> <item name="android:windowBackground">@drawable/launch_background</item> </style> <!-- Theme applied to the Android Window as soon as the process has started. This theme determines the color of the Android Window while your Flutter UI initializes, as well as behind your Flutter UI while its running. This Theme is only used starting with V2 of Flutter's Android embedding. --> <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> <item name="android:windowBackground">?android:colorBackground</item> </style> </resources> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:label="15" android:name="${applicationName}" android:icon="@mipmap/launcher_icon"> <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- Specifies an Android theme to apply to this Activity as soon as the Android process has started. This theme is visible to the user while the Flutter UI initializes. After that, this theme continues to determine the Window background behind the Flutter UI. --> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!-- Don't delete the meta-data below. This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> <meta-data android:name="flutterEmbedding" android:value="2" /> </application> <queries> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent> </queries> </manifest> |
1 2 3 4 5 6 7 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <!-- The INTERNET permission is required for development. Specifically, the Flutter tool needs it to communicate with the running application to allow setting breakpoints, to provide hot reload, etc. --> <uses-permission android:name="android.permission.INTERNET"/> </manifest> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { namespace "com.example.fifteen" compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.fifteen" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug } } } flutter { source '../..' } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } |
1 2 3 4 5 | distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | buildscript { ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { google() mavenCentral() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { project.evaluationDependsOn(':app') } tasks.register("clean", Delete) { delete rootProject.buildDir } |
1 2 3 | org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true |
1 2 3 4 5 6 7 8 9 10 11 | include ':app' def localPropertiesFile = new File(rootProject.projectDir, "local.properties") def properties = new Properties() assert localPropertiesFile.exists() localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } def flutterSdkPath = properties.getProperty("flutter.sdk") assert flutterSdkPath != null, "flutter.sdk not set in local.properties" apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg width="16" height="16" viewBox="0 0 4.2333332 4.2333333" version="1.1" id="svg5" inkscape:version="1.2.2 (732a01da63, 2022-12-09, custom)" sodipodi:docname="icon.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="px" showgrid="false" inkscape:zoom="1.4039843" inkscape:cx="14.601303" inkscape:cy="8.1909749" inkscape:window-width="1850" inkscape:window-height="1016" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="layer1" /> <defs id="defs2" /> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <rect style="fill:#ffffff;stroke:#000000;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" id="rect2269" width="3.96875" height="3.96875" x="0.14086828" y="0.14379625" ry="0.46099386" /> <path style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 2.1166666,0.13229166 V 4.1010416" id="path3328" sodipodi:nodetypes="cc" /> <path style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 4.1010417,2.1166665 H 0.13229166" id="path3328-3" sodipodi:nodetypes="cc" /> <text xml:space="preserve" style="font-size:1.41111px;line-height:1.25;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583" x="0.85640651" y="1.7070621" id="text3507"><tspan sodipodi:role="line" id="tspan3505" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Comfortaa;-inkscape-font-specification:'Comfortaa Bold';stroke-width:0.264583" x="0.85640651" y="1.7070621">1</tspan></text> <text xml:space="preserve" style="font-size:1.41111px;line-height:1.25;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583" x="2.7050855" y="1.7001066" id="text3507-6"><tspan sodipodi:role="line" id="tspan3505-7" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Comfortaa;-inkscape-font-specification:'Comfortaa Bold';stroke-width:0.264583" x="2.7050855" y="1.7001066">2</tspan></text> <text xml:space="preserve" style="font-size:1.41111px;line-height:1.25;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583" x="0.72468543" y="3.7001522" id="text3507-6-5"><tspan sodipodi:role="line" id="tspan3505-7-3" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Comfortaa;-inkscape-font-specification:'Comfortaa Bold';stroke-width:0.264583" x="0.72468543" y="3.7001522">3</tspan></text> </g> </svg> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleExecutable</key> <string>App</string> <key>CFBundleIdentifier</key> <string>io.flutter.flutter.app</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>App</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>1.0</string> <key>MinimumOSVersion</key> <string>11.0</string> </dict> </plist> |
1 | #include "Generated.xcconfig" |
1 | #include "Generated.xcconfig" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | { "images" : [ { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@3x.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@3x.png", "scale" : "3x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@1x.png", "scale" : "1x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@1x.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@1x.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" }, { "size" : "1024x1024", "idiom" : "ios-marketing", "filename" : "Icon-App-1024x1024@1x.png", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { "images" : [ { "idiom" : "universal", "filename" : "LaunchImage.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "LaunchImage@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "LaunchImage@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } |
1 2 3 4 5 | # Launch Screen Assets You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> </dependencies> <scenes> <!--View Controller--> <scene sceneID="EHf-IW-A2E"> <objects> <viewController id="01J-lp-oVM" sceneMemberID="viewController"> <layoutGuides> <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/> <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/> </layoutGuides> <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> </imageView> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> </constraints> </view> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="53" y="375"/> </scene> </scenes> <resources> <image name="LaunchImage" width="168" height="185"/> </resources> </document> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> </dependencies> <scenes> <!--Flutter View Controller--> <scene sceneID="tne-QT-ifu"> <objects> <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> <layoutGuides> <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> </layoutGuides> <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> </view> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> </objects> </scene> </scenes> </document> |
1 2 3 4 5 6 7 8 9 10 11 12 13 | import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleDisplayName</key> <string>15</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>15</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>$(FLUTTER_BUILD_NAME)</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>$(FLUTTER_BUILD_NUMBER)</string> <key>LSRequiresIPhoneOS</key> <true/> <key>UILaunchStoryboardName</key> <string>LaunchScreen</string> <key>UIMainStoryboardFile</key> <string>Main</string> <key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UISupportedInterfaceOrientations~ipad</key> <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UIViewControllerBasedStatusBarAppearance</key> <false/> <key>CADisableMinimumFrameDurationOnPhone</key> <true/> <key>UIApplicationSupportsIndirectInputEvents</key> <true/> </dict> </plist> |
1 | #import "GeneratedPluginRegistrant.h"
|
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>IDEDidComputeMac32BitWarning</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PreviewsEnabled</key> <false/> </dict> </plist> |
1 2 3 4 5 6 7 | <?xml version="1.0" encoding="UTF-8"?> <Workspace version = "1.0"> <FileRef location = "self:"> </FileRef> </Workspace> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?xml version="1.0" encoding="UTF-8"?> <Scheme LastUpgradeVersion = "1300" version = "1.3"> <BuildAction parallelizeBuildables = "YES" buildImplicitDependencies = "YES"> <BuildActionEntries> <BuildActionEntry buildForTesting = "YES" buildForRunning = "YES" buildForProfiling = "YES" buildForArchiving = "YES" buildForAnalyzing = "YES"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "97C146ED1CF9000F007C117D" BuildableName = "Runner.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildActionEntry> </BuildActionEntries> </BuildAction> <TestAction buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> <MacroExpansion> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "97C146ED1CF9000F007C117D" BuildableName = "Runner.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </MacroExpansion> <Testables> <TestableReference skipped = "NO" parallelizable = "YES"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "331C8080294A63A400263BE5" BuildableName = "RunnerTests.xctest" BlueprintName = "RunnerTests" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </TestableReference> </Testables> </TestAction> <LaunchAction buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> <BuildableProductRunnable runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "97C146ED1CF9000F007C117D" BuildableName = "Runner.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildableProductRunnable> </LaunchAction> <ProfileAction buildConfiguration = "Profile" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> <BuildableProductRunnable runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "97C146ED1CF9000F007C117D" BuildableName = "Runner.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildableProductRunnable> </ProfileAction> <AnalyzeAction buildConfiguration = "Debug"> </AnalyzeAction> <ArchiveAction buildConfiguration = "Release" revealArchiveInOrganizer = "YES"> </ArchiveAction> </Scheme> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 97C146E61CF9000F007C117D /* Project object */; proxyType = 1; remoteGlobalIDString = 97C146ED1CF9000F007C117D; remoteInfo = Runner; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, ); name = Flutter; sourceTree = "<group>"; }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( 331C807B294A618700263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = "<group>"; }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = "<group>"; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = "<group>"; }; 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = "<group>"; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 331C8080294A63A400263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 331C807D294A63A400263BE5 /* Sources */, 331C807E294A63A400263BE5 /* Frameworks */, 331C807F294A63A400263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( 331C8086294A63A400263BE5 /* PBXTargetDependency */, ); name = RunnerTests; productName = RunnerTests; productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( ); dependencies = ( ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { CreatedOnToolsVersion = 14.0; TestTargetID = 97C146ED1CF9000F007C117D; }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 97C146E51CF9000F007C117D; productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 331C807F294A63A400263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 331C807D294A63A400263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 97C146ED1CF9000F007C117D /* Runner */; targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 97C146FB1CF9000F007C117D /* Base */, ); name = Main.storyboard; sourceTree = "<group>"; }; 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 97C147001CF9000F007C117D /* Base */, ); name = LaunchScreen.storyboard; sourceTree = "<group>"; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Profile; }; 249021D4217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Debug; }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Release; }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 97C147071CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 331C8088294A63A400263BE5 /* Debug */, 331C8089294A63A400263BE5 /* Release */, 331C808A294A63A400263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>IDEDidComputeMac32BitWarning</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PreviewsEnabled</key> <false/> </dict> </plist> |
1 2 3 4 5 6 7 | <?xml version="1.0" encoding="UTF-8"?> <Workspace version = "1.0"> <FileRef location = "group:Runner.xcodeproj"> </FileRef> </Workspace> |
1 2 3 4 5 6 7 8 9 10 11 12 | import Flutter import UIKit import XCTest class RunnerTests: XCTestCase { func testExample() { // If you add code to the Runner application, consider adding tests here. // See https://developer.apple.com/documentation/xctest for more information about using XCTest. } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | library; import "dart:math"; typedef Board = int; typedef Tile = int; const Board winningBoard = 0x0FEDCBA987654321; Tile getTile(Board board, int i) { return (board >> (i << 2)) & 0xF; } Board setTile(Board board, int i, Tile tile) { final bitIdx = i << 2; return (board & ~(0xF << bitIdx)) | (tile << bitIdx); } Board swapTiles(Board board, int i, int j) { int a = getTile(board, i); int b = getTile(board, j); return setTile(setTile(board, i, b), j, a); } Board moveHoleTo(Board board, int newHolePos) { int bitPos = (flip(board) & 0xF) << 2; int newBitPos = newHolePos << 2; int val = (board >> newBitPos) & 0xF; return board ^ (val << bitPos) ^ (val << newBitPos); } /// Invert ("flip") the permutation of 0 - 15. Board flip(Board board) { Board res = 0; for (int i = 0; i < 0x10; i++) { final tile = board & 0xF; res |= i << (tile << 2); board >>= 4; } return res; } bool isSolvable(Board board) { int inversions = 0; for (int i = 0; i < 0x10; i++) { for (int j = i + 1; j < 0x10; j++) { final a = getTile(board, i); final b = getTile(board, j); if (a != 0 && b != 0 && a > b) inversions++; } } final (_, hy) = idxToPos(getTile(flip(board), 0)); return (inversions + hy).isOdd; } String toHex(Board board, [String rowsep = ""]) { return Iterable.generate( 4, (y) => Iterable.generate( 4, (x) => getTile(board, posToIdx(x, y)).toRadixString(0x10)) .join()).join(rowsep); } Board _pack(Iterable<int> nums) { assert(nums.length == 0x10); return nums.fold(0, (board, tile) => (board << 4) | tile); } Board? fromHex(String hex) { if (!RegExp(r"^[\da-fA-F]{16}$").hasMatch(hex)) return null; return _pack(hex.codeUnits .map((c) => int.parse(String.fromCharCode(c), radix: 16)) .toList() .reversed); } Board shuffle(Board board, int minMoves, int maxMoves) { var holePos = flip(board) & 0xF; final rand = Random(); final moves = rand.nextInt(maxMoves) + minMoves; for (int i = 0; i <= moves; i++) { List<int> options = []; if (holePos > 3) options.add(-4); if (holePos < 12) options.add(4); int x = holePos & 3; if (x > 0) options.add(-1); if (x < 3) options.add(1); int delta = options[rand.nextInt(options.length)]; int bitPos = holePos << 2; holePos += delta; int newBitPos = holePos << 2; int val = (board >> newBitPos) & 0xF; board ^= (val << bitPos) ^ (val << newBitPos); } return board; } Board randomSolvable() { return shuffle(winningBoard, 100, 1000); } int posToIdx(int x, int y) { return (y << 2) + x; } (int, int) idxToPos(int idx) { return (idx & 3, idx >> 2); } Iterable<Board> solveBFS(int solved, int toSolve, Board start) { int flippedMask = (toSolve << 4) | 0xF; // holes matter! bool predicate(Board board) => board & toSolve == winningBoard & toSolve; if (predicate(start)) return const Iterable.empty(); List<(Board, Board)> level = [(start, flip(start))]; Map<Board, Board> predecessor = {flip(start) & flippedMask: 0}; while (level.isNotEmpty) { List<(Board, Board)> nextLevel = []; for (final tup in level) { final (board, flipped) = tup; final holePos = flipped & 0xF; Iterable<Board>? move(int dx, int dy) { int bitPos = holePos << 2; int newHolePos = holePos + posToIdx(dx, dy); int newBitPos = newHolePos << 2; if ((0xF << newBitPos) & solved != 0) return null; int val = (board >> newBitPos) & 0xF; final newBoard = board ^ (val << bitPos) ^ (val << newBitPos); int valPos = val << 2; final newFlipped = (((flipped & ~0xF) | newHolePos) & ~(0xF << valPos)) | (holePos << valPos); if (!predecessor.containsKey(newFlipped & flippedMask)) { predecessor[newFlipped & flippedMask] = board; if (predicate(newBoard)) { List<Board> solution = [newBoard]; Board preBoard = board; while (preBoard != start) { solution.add(preBoard); preBoard = predecessor[flip(preBoard) & flippedMask]!; } return solution.reversed; } nextLevel.add((newBoard, newFlipped)); } return null; } // Hot loop + no macros = ugly boilerplate (or error abuse or the like) final (hx, hy) = idxToPos(holePos); if (hx > 0) { final res = move(-1, 0); if (res != null) return res; } if (hx < 3) { final res = move(1, 0); if (res != null) return res; } if (hy > 0) { final res = move(0, -1); if (res != null) return res; } if (hy < 3) { final res = move(0, 1); if (res != null) return res; } } level = nextLevel; } throw "unsolvable"; } Iterable<Board> solve(Board start) { const row1 = 0xFFFF; const row2 = row1 << 16; const upperHalf = row2 | row1; final row1Sol = solveBFS(0, row1, start); final row2Sol = solveBFS(row1, upperHalf, row1Sol.lastOrNull ?? start); final lowerSolution = solveBFS( upperHalf, ~0, row2Sol.lastOrNull ?? row1Sol.lastOrNull ?? start); return row1Sol.followedBy(row2Sol).followedBy(lowerSolution); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; import 'board.dart' as brd; typedef Board = brd.Board; typedef Tile = brd.Tile; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '15', theme: ThemeData( // Define the default brightness and colors. brightness: Brightness.light, colorSchemeSeed: Colors.lightBlueAccent, useMaterial3: true, ), home: const MyHomePage(), ); } } class _TileWidget extends StatelessWidget { final Tile tile; final Function()? onPressed; final Color? disabledBackgroundColor; final bool showBlank; const _TileWidget(this.tile, this.onPressed, {this.disabledBackgroundColor = const Color.fromARGB(255, 134, 198, 238), this.showBlank = false}); @override Widget build(BuildContext context) { if (tile == 0 && !showBlank) return Container(); return Container( padding: const EdgeInsets.all(2), child: FilledButton( key: ValueKey<int>(tile), onPressed: onPressed, style: FilledButton.styleFrom( backgroundColor: const Color.fromARGB(255, 67, 170, 230), disabledBackgroundColor: disabledBackgroundColor), child: Text(tile == 0 ? "" : tile.toString(), style: DefaultTextStyle.of(context) .style .apply(fontSizeFactor: 2.0)), )); } } class _DraggableTileWidget extends StatelessWidget { final Tile tile; final int idx; final Function(Tile) onAccept; const _DraggableTileWidget(this.tile, this.idx, this.onAccept); @override Widget build(BuildContext context) { final Widget child = _TileWidget(tile, null, showBlank: true); return DragTarget<int>( builder: (context, candidateData, rejectedData) => LayoutBuilder( builder: (context, constraints) => Draggable<int>( data: idx, dragAnchorStrategy: pointerDragAnchorStrategy, feedback: SizedBox( width: constraints.maxWidth, height: constraints.maxHeight, child: DefaultTextStyle.of(context).wrap(context, child)), childWhenDragging: _TileWidget( tile, null, disabledBackgroundColor: const Color.fromARGB(255, 190, 217, 233), showBlank: true, ), child: child, )), onAccept: onAccept, ); } } class _GameWidget extends StatefulWidget { final SharedPreferences? prefs; const _GameWidget(this.prefs); @override State<_GameWidget> createState() => _GameWidgetState(); } class _GameWidgetState extends State<_GameWidget> { Board _board; Board get board => _board; bool get won => board == brd.winningBoard; set board(Board board) { _board = board; _persist(); } bool _editing = false; bool get editing => _editing; set editing(bool editing) { _editing = editing; _persist(); } // These two are deliberately not persisted Future<List<Board>>? _solving; Timer? _solutionStepper; _GameWidgetState() : _board = brd.randomSolvable(); @override initState() { super.initState(); if (widget.prefs == null) return; final SharedPreferences prefs = widget.prefs!; _editing = prefs.getBool('editing') ?? false; final boardHex = prefs.getString('board'); if (boardHex != null) _board = brd.fromHex(boardHex) ?? _board; _persist(); } _persist() { if (widget.prefs == null) return; final SharedPreferences prefs = widget.prefs!; prefs.setBool('editing', editing).then((success) { if (success) prefs.setString('board', brd.toHex(board)); // TODO (...) log failure or notify user }); } _move(int toIdx) { setState(() { board = brd.moveHoleTo(board, toIdx); }); } _slide(int dx, int dy) { if (_solutionStepper != null || _solving != null || editing) return; var (hx, hy) = brd.idxToPos(brd.getTile(brd.flip(board), 0)); // It is more intuitive to slide in the opposite direction of hole movement. hx -= dx; hy -= dy; if (hx < 0 || hx > 3 || hy < 0 || hy > 3) return; _move(brd.posToIdx(hx, hy)); } _solve() { setState(() { _solving = compute((board) => brd.solve(board).toList(), board); }); } _stop() { if (_solutionStepper == null) return; setState(() { _solutionStepper!.cancel(); _solutionStepper = null; }); } _shuffle() { setState(() { board = brd.randomSolvable(); _solving = null; if (_solutionStepper != null) { _solutionStepper!.cancel(); _solutionStepper = null; } }); } _edit() { _stop(); setState(() { editing = true; }); } _done() { setState(() { editing = false; }); } _copy() { Clipboard.setData(ClipboardData(text: brd.toHex(board))); } _paste() { Clipboard.getData(Clipboard.kTextPlain).then((value) { final text = value?.text; if (text == null) return; setState(() { final clippedboard = brd.fromHex(text); if (clippedboard != null) board = clippedboard; }); }); } _reset() { setState(() { board = brd.winningBoard; }); } _swap(int i, j) { setState(() { board = brd.swapTiles(board, i, j); }); } Widget _build() { final (hx, hy) = brd.idxToPos(brd.flip(board) & 0xF); final buttons = Iterable.generate( 4, (y) => Iterable.generate(4, (x) { final idx = brd.posToIdx(x, y); Tile tile = brd.getTile(board, idx); if (editing) { return _DraggableTileWidget( tile, idx, (int j) => _swap(idx, j), ); } final neighbor = (x - hx).abs() + (y - hy).abs() == 1; return _TileWidget( tile, neighbor && _solutionStepper == null ? () { _move(idx); } : null, ); }).toList()).toList(); final grid = GridView.count( crossAxisCount: 4, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), children: buttons.expand((x) => x).toList(), ); return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: editing ? [ TextButton(onPressed: _shuffle, child: const Text("Shuffle")), TextButton(onPressed: _reset, child: const Text("Reset")), TextButton( // TODO (...?) disable if clipboard content is invalid onPressed: _paste, child: const Text("Paste")), FilledButton( onPressed: brd.isSolvable(board) ? _done : null, child: const Text("Done")), ] : [ TextButton(onPressed: _shuffle, child: const Text("Shuffle")), TextButton(onPressed: _edit, child: const Text("Edit")), TextButton( onPressed: brd.isSolvable(board) ? _copy : null, child: const Text("Copy")), _solutionStepper == null ? FilledButton( onPressed: won ? null : _solve, child: const Text("Solve")) : FilledButton( onPressed: won ? null : _stop, child: const Text("Stop")), ], ), Expanded( child: Center( child: Focus( autofocus: true, onKeyEvent: (_, keyEvent) { if (keyEvent is! KeyUpEvent) return KeyEventResult.ignored; switch (keyEvent.logicalKey) { case LogicalKeyboardKey.keyW: _slide(0, -1); case LogicalKeyboardKey.keyA: _slide(-1, 0); case LogicalKeyboardKey.keyS: _slide(0, 1); case LogicalKeyboardKey.keyD: _slide(1, 0); default: return KeyEventResult.ignored; } return KeyEventResult.handled; }, child: GestureDetector( // TODO make sure that this fires only for the primary axis onHorizontalDragEnd: (DragEndDetails details) { if (details.primaryVelocity == null) return; _slide(details.primaryVelocity!.sign.toInt(), 0); }, onVerticalDragEnd: (DragEndDetails details) { if (details.primaryVelocity == null) return; _slide(0, details.primaryVelocity!.sign.toInt()); }, child: grid), ))), TextButton( onPressed: () { launchUrl(Uri.parse("https://en.wikipedia.org/wiki/15_puzzle"), mode: LaunchMode.externalApplication); }, child: const Text("About")), ], ); } @override Widget build(BuildContext context) { if (_solving != null) { return FutureBuilder<List<Board>>( future: _solving, builder: (context, snapshot) { assert(!snapshot.hasError); if (snapshot.hasData) { _solving = null; final data = snapshot.data!; assert(data.isNotEmpty); int i = 0; _solutionStepper = Timer.periodic( const Duration(seconds: 1), (Timer t) => setState(() { board = data[i]; i++; if (i >= data.length) { _solutionStepper!.cancel(); _solutionStepper = null; } })); return _build(); } return const Center(child: CircularProgressIndicator()); }, ); } return _build(); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { _MyHomePageState(); @override Widget build(BuildContext context) { return Scaffold( body: Container( padding: EdgeInsets.fromLTRB(0, MediaQuery.of(context).viewPadding.top, 0, 0), child: FutureBuilder<SharedPreferences>( future: SharedPreferences.getInstance(), builder: (context, snapshot) { // Behave gracefully if we don't have persistent storage. // TODO (...) log this or notify user about the issue if (snapshot.hasError) return const _GameWidget(null); if (snapshot.hasData) return _GameWidget(snapshot.data!); return const Center(child: CircularProgressIndicator()); }, ), )); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.10) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. # Serves the same purpose as list(TRANSFORM ... PREPEND ...), # which isn't available in 3.10. function(list_prepend LIST_NAME PREFIX) set(NEW_LIST "") foreach(element ${${LIST_NAME}}) list(APPEND NEW_LIST "${PREFIX}${element}") endforeach(element) set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) endfunction() # === Flutter Library === # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "fl_basic_message_channel.h" "fl_binary_codec.h" "fl_binary_messenger.h" "fl_dart_project.h" "fl_engine.h" "fl_json_message_codec.h" "fl_json_method_codec.h" "fl_message_codec.h" "fl_method_call.h" "fl_method_channel.h" "fl_method_codec.h" "fl_method_response.h" "fl_plugin_registrar.h" "fl_plugin_registry.h" "fl_standard_message_codec.h" "fl_standard_method_codec.h" "fl_string_codec.h" "fl_value.h" "fl_view.h" "flutter_linux.h" ) list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") target_link_libraries(flutter INTERFACE PkgConfig::GTK PkgConfig::GLIB PkgConfig::GIO ) add_dependencies(flutter flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/_phony_ COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include <url_launcher_linux/url_launcher_plugin.h> void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include <flutter_linux/flutter_linux.h> // Registers Flutter plugins. void fl_register_plugins(FlPluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | # Project-level configuration. cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "fifteen") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.example.fifteen") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() # Define build configuration options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") # Define the application target. To change its name, change BINARY_NAME above, # not the value here, or `flutter run` will no longer work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} "main.cc" "my_application.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of # the default top-level location. set_target_properties(${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() |
1 2 3 4 5 6 | #include "my_application.h" int main(int argc, char** argv) { g_autoptr(MyApplication) app = my_application_new(); return g_application_run(G_APPLICATION(app), argc, argv); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #include "my_application.h" #include <flutter_linux/flutter_linux.h> #ifdef GDK_WINDOWING_X11 #include <gdk/gdkx.h> #endif #include "flutter/generated_plugin_registrant.h" struct _MyApplication { GtkApplication parent_instance; char** dart_entrypoint_arguments; }; G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); // Use a header bar when running in GNOME as this is the common style used // by applications and is the setup most users will be using (e.g. Ubuntu // desktop). // If running on X and not using GNOME then just use a traditional title bar // in case the window manager does more exotic layout, e.g. tiling. // If running on Wayland assume the header bar will work (may need changing // if future cases occur). gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) { const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); if (g_strcmp0(wm_name, "GNOME Shell") != 0) { use_header_bar = FALSE; } } #endif if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); gtk_header_bar_set_title(header_bar, "15"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { gtk_window_set_title(window, "15"); } gtk_window_set_default_size(window, 405, 720); gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { g_warning("Failed to register: %s", error->message); *exit_status = 1; return TRUE; } g_application_activate(application); *exit_status = 0; return TRUE; } // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); G_OBJECT_CLASS(my_application_parent_class)->dispose(object); } static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, nullptr)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ #include <gtk/gtk.h> G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication) /** * my_application_new: * * Creates a new Flutter-based application. * * Returns: a new #MyApplication. */ MyApplication* my_application_new(); #endif // FLUTTER_MY_APPLICATION_H_ |
1 | #include "ephemeral/Flutter-Generated.xcconfig" |
1 | #include "ephemeral/Flutter-Generated.xcconfig" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // // Generated file. Do not edit. // import FlutterMacOS import Foundation import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | { "info": { "version": 1, "author": "xcode" }, "images": [ { "size": "16x16", "idiom": "mac", "filename": "app_icon_16.png", "scale": "1x" }, { "size": "16x16", "idiom": "mac", "filename": "app_icon_32.png", "scale": "2x" }, { "size": "32x32", "idiom": "mac", "filename": "app_icon_32.png", "scale": "1x" }, { "size": "32x32", "idiom": "mac", "filename": "app_icon_64.png", "scale": "2x" }, { "size": "128x128", "idiom": "mac", "filename": "app_icon_128.png", "scale": "1x" }, { "size": "128x128", "idiom": "mac", "filename": "app_icon_256.png", "scale": "2x" }, { "size": "256x256", "idiom": "mac", "filename": "app_icon_256.png", "scale": "1x" }, { "size": "256x256", "idiom": "mac", "filename": "app_icon_512.png", "scale": "2x" }, { "size": "512x512", "idiom": "mac", "filename": "app_icon_512.png", "scale": "1x" }, { "size": "512x512", "idiom": "mac", "filename": "app_icon_1024.png", "scale": "2x" } ] } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | <?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <dependencies> <deployment identifier="macosx"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> <connections> <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/> </connections> </customObject> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target"> <connections> <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/> <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/> </connections> </customObject> <customObject id="YLy-65-1bz" customClass="NSFontManager"/> <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> <items> <menuItem title="APP_NAME" id="1Xt-HY-uBw"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr"> <items> <menuItem title="About APP_NAME" id="5kV-Vb-QxS"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/> <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> <menuItem title="Services" id="NMo-om-nkz"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> </menuItem> <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN"> <connections> <action selector="hide:" target="-1" id="PnN-Uc-m68"/> </connections> </menuItem> <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <connections> <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/> </connections> </menuItem> <menuItem title="Show All" id="Kd2-mp-pUS"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi"> <connections> <action selector="terminate:" target="-1" id="Te7-pn-YzF"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Edit" id="5QF-Oa-p0T"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Edit" id="W48-6f-4Dl"> <items> <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> <connections> <action selector="undo:" target="-1" id="M6e-cu-g7V"/> </connections> </menuItem> <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> <connections> <action selector="redo:" target="-1" id="oIA-Rs-6OD"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> <connections> <action selector="cut:" target="-1" id="YJe-68-I9s"/> </connections> </menuItem> <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> <connections> <action selector="copy:" target="-1" id="G1f-GL-Joy"/> </connections> </menuItem> <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> <connections> <action selector="paste:" target="-1" id="UvS-8e-Qdg"/> </connections> </menuItem> <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <connections> <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/> </connections> </menuItem> <menuItem title="Delete" id="pa3-QI-u2k"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/> </connections> </menuItem> <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> <connections> <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> <menuItem title="Find" id="4EN-yA-p0u"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Find" id="1b7-l0-nxx"> <items> <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> <connections> <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/> </connections> </menuItem> <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <connections> <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/> </connections> </menuItem> <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> <connections> <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/> </connections> </menuItem> <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> <connections> <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/> </connections> </menuItem> <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> <connections> <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/> </connections> </menuItem> <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> <connections> <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> <items> <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> <connections> <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/> </connections> </menuItem> <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> <connections> <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/> </connections> </menuItem> <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/> </connections> </menuItem> <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Substitutions" id="9ic-FL-obx"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> <items> <menuItem title="Show Substitutions" id="z6F-FW-3nz"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/> </connections> </menuItem> <menuItem title="Smart Quotes" id="hQb-2v-fYv"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/> </connections> </menuItem> <menuItem title="Smart Dashes" id="rgM-f4-ycn"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/> </connections> </menuItem> <menuItem title="Smart Links" id="cwL-P1-jid"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/> </connections> </menuItem> <menuItem title="Data Detectors" id="tRr-pd-1PS"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/> </connections> </menuItem> <menuItem title="Text Replacement" id="HFQ-gK-NFA"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Transformations" id="2oI-Rn-ZJC"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Transformations" id="c8a-y6-VQd"> <items> <menuItem title="Make Upper Case" id="vmV-6d-7jI"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/> </connections> </menuItem> <menuItem title="Make Lower Case" id="d9M-CD-aMd"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/> </connections> </menuItem> <menuItem title="Capitalize" id="UEZ-Bs-lqG"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Speech" id="xrE-MZ-jX0"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Speech" id="3rS-ZA-NoH"> <items> <menuItem title="Start Speaking" id="Ynk-f8-cLZ"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/> </connections> </menuItem> <menuItem title="Stop Speaking" id="Oyz-dy-DGm"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/> </connections> </menuItem> </items> </menu> </menuItem> </items> </menu> </menuItem> <menuItem title="View" id="H8h-7b-M4v"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="View" id="HyV-fh-RgO"> <items> <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> <connections> <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Window" id="aUF-d1-5bR"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> <items> <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> <connections> <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/> </connections> </menuItem> <menuItem title="Zoom" id="R4o-n2-Eq4"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/> </connections> </menuItem> <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> <menuItem title="Bring All to Front" id="LE2-aR-0XJ"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/> </connections> </menuItem> </items> </menu> </menuItem> <menuItem title="Help" id="EPT-qC-fAb"> <modifierMask key="keyEquivalentModifierMask"/> <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/> </menuItem> </items> <point key="canvasLocation" x="142" y="-258"/> </menu> <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <rect key="contentRect" x="335" y="390" width="405" height="720"/> <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/> <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ"> <rect key="frame" x="0.0" y="0.0" width="405" height="720"/> <autoresizingMask key="autoresizingMask"/> </view> </window> </objects> </document> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // Application-level settings for the Runner target. // // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the // future. If not, the values below would default to using the project name when this becomes a // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. PRODUCT_NAME = 15 // The application's bundle identifier PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen // The copyright displayed in application information // TODO update this PRODUCT_COPYRIGHT = Copyright © 2023 |
1 2 | #include "../../Flutter/Flutter-Debug.xcconfig" #include "Warnings.xcconfig" |
1 2 | #include "../../Flutter/Flutter-Release.xcconfig" #include "Warnings.xcconfig" |
1 2 3 4 5 6 7 8 9 10 11 12 13 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings GCC_WARN_UNDECLARED_SELECTOR = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN_PRAGMA_PACK = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_COMMA = YES GCC_WARN_STRICT_SELECTOR_MATCH = YES CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES GCC_WARN_SHADOW = YES CLANG_WARN_UNREACHABLE_CODE = YES |
1 2 3 4 5 6 7 8 9 | import Cocoa import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } } |
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.cs.allow-jit</key> <true/> <key>com.apple.security.network.server</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIconFile</key> <string></string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>$(FLUTTER_BUILD_NAME)</string> <key>CFBundleVersion</key> <string>$(FLUTTER_BUILD_NUMBER)</string> <key>LSMinimumSystemVersion</key> <string>$(MACOSX_DEPLOYMENT_TARGET)</string> <key>NSHumanReadableCopyright</key> <string>$(PRODUCT_COPYRIGHT)</string> <key>NSMainNibFile</key> <string>MainMenu</string> <key>NSPrincipalClass</key> <string>NSApplication</string> </dict> </plist> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import Cocoa import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) RegisterGeneratedPlugins(registry: flutterViewController) super.awakeFromNib() } } |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>IDEDidComputeMac32BitWarning</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <?xml version="1.0" encoding="UTF-8"?> <Scheme LastUpgradeVersion = "1300" version = "1.3"> <BuildAction parallelizeBuildables = "YES" buildImplicitDependencies = "YES"> <BuildActionEntries> <BuildActionEntry buildForTesting = "YES" buildForRunning = "YES" buildForProfiling = "YES" buildForArchiving = "YES" buildForAnalyzing = "YES"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "33CC10EC2044A3C60003C045" BuildableName = "fifteen.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildActionEntry> </BuildActionEntries> </BuildAction> <TestAction buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> <MacroExpansion> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "33CC10EC2044A3C60003C045" BuildableName = "fifteen.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </MacroExpansion> <Testables> <TestableReference skipped = "NO" parallelizable = "YES"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "331C80D4294CF70F00263BE5" BuildableName = "RunnerTests.xctest" BlueprintName = "RunnerTests" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </TestableReference> </Testables> </TestAction> <LaunchAction buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> <BuildableProductRunnable runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "33CC10EC2044A3C60003C045" BuildableName = "fifteen.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildableProductRunnable> </LaunchAction> <ProfileAction buildConfiguration = "Profile" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> <BuildableProductRunnable runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "33CC10EC2044A3C60003C045" BuildableName = "fifteen.app" BlueprintName = "Runner" ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildableProductRunnable> </ProfileAction> <AnalyzeAction buildConfiguration = "Debug"> </AnalyzeAction> <ArchiveAction buildConfiguration = "Release" revealArchiveInOrganizer = "YES"> </ArchiveAction> </Scheme> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { isa = PBXAggregateTarget; buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; buildPhases = ( 33CC111E2044C6BF0003C045 /* ShellScript */, ); dependencies = ( ); name = "Flutter Assemble"; productName = FLX; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC10EC2044A3C60003C045; remoteInfo = Runner; }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 33CC110E2044A8840003C045 /* Bundle Framework */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; }; 33CC10ED2044A3C60003C045 /* fifteen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "fifteen.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; }; 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; }; 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; }; 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 331C80D2294CF70F00263BE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( 331C80D7294CF71000263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = "<group>"; }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, ); path = Configs; sourceTree = "<group>"; }; 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, ); sourceTree = "<group>"; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* fifteen.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = "<group>"; }; 33CC11242044D66E0003C045 /* Resources */ = { isa = PBXGroup; children = ( 33CC10F22044A3C60003C045 /* Assets.xcassets */, 33CC10F42044A3C60003C045 /* MainMenu.xib */, 33CC10F72044A3C60003C045 /* Info.plist */, ); name = Resources; path = ..; sourceTree = "<group>"; }; 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, ); path = Flutter; sourceTree = "<group>"; }; 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 33E51914231749380026EE4D /* Release.entitlements */, 33CC11242044D66E0003C045 /* Resources */, 33BA886A226E78AF003329D5 /* Configs */, ); path = Runner; sourceTree = "<group>"; }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = "<group>"; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 331C80D4294CF70F00263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( 331C80DA294CF71000263BE5 /* PBXTargetDependency */, ); name = RunnerTests; productName = RunnerTests; productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, ); buildRules = ( ); dependencies = ( 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; productName = Runner; productReference = 33CC10ED2044A3C60003C045 /* fifteen.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { CreatedOnToolsVersion = 14.0; TestTargetID = 33CC10EC2044A3C60003C045; }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; }; }; }; 33CC111A2044C6BA0003C045 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 331C80D3294CF70F00263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( Flutter/ephemeral/tripwire, ); outputFileListPaths = ( Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 331C80D1294CF70F00263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC10EC2044A3C60003C045 /* Runner */; targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 33CC10F52044A3C60003C045 /* Base */, ); name = MainMenu.xib; path = Runner; sourceTree = "<group>"; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fifteen.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fifteen"; }; name = Debug; }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fifteen.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fifteen"; }; name = Release; }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.fifteen.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fifteen.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fifteen"; }; name = Profile; }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Profile; }; 338D0CEA231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Profile; }; 338D0CEB231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; }; 33CC10F92044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 33CC10FA2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 33CC10FC2044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 33CC10FD2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Release; }; 33CC111C2044C6BA0003C045 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 33CC111D2044C6BA0003C045 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 331C80DB294CF71000263BE5 /* Debug */, 331C80DC294CF71000263BE5 /* Release */, 331C80DD294CF71000263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10F92044A3C60003C045 /* Debug */, 33CC10FA2044A3C60003C045 /* Release */, 338D0CE9231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10FC2044A3C60003C045 /* Debug */, 33CC10FD2044A3C60003C045 /* Release */, 338D0CEA231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC111C2044C6BA0003C045 /* Debug */, 33CC111D2044C6BA0003C045 /* Release */, 338D0CEB231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } |
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>IDEDidComputeMac32BitWarning</key> <true/> </dict> </plist> |
1 2 3 4 5 6 7 | <?xml version="1.0" encoding="UTF-8"?> <Workspace version = "1.0"> <FileRef location = "group:Runner.xcodeproj"> </FileRef> </Workspace> |
1 2 3 4 5 6 7 8 9 10 11 12 | import FlutterMacOS import Cocoa import XCTest class RunnerTests: XCTestCase { func testExample() { // If you add code to the Runner application, consider adding tests here. // See https://developer.apple.com/documentation/xctest for more information about using XCTest. } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <!DOCTYPE html> <html> <head> <!-- If you are serving your web app in a path other than the root, change the href value below to reflect the base path you are serving from. The path provided below has to start and end with a slash "/" in order for it to work correctly. For more details: * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base This is a placeholder for base href that will be replaced by the value of the `--base-href` argument provided to `flutter build`. --> <base href="$FLUTTER_BASE_HREF"> <meta charset="UTF-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="description" content="A new Flutter project."> <!-- iOS meta tags & icons --> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-title" content="15"> <link rel="apple-touch-icon" href="icons/Icon-192.png"> <!-- Favicon --> <link rel="icon" type="image/png" href="favicon.png"/> <title>15</title> <link rel="manifest" href="manifest.json"> <script> // The value below is injected by flutter build, do not touch. var serviceWorkerVersion = null; </script> <!-- This script adds the flutter initialization JS code --> <script src="flutter.js" defer></script> </head> <body> <script> window.addEventListener('load', function(ev) { // Download main.dart.js _flutter.loader.loadEntrypoint({ serviceWorker: { serviceWorkerVersion: serviceWorkerVersion, }, onEntrypointLoaded: function(engineInitializer) { engineInitializer.initializeEngine().then(function(appRunner) { appRunner.runApp(); }); } }); }); </script> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | { "name": "15", "short_name": "15", "start_url": ".", "display": "standalone", "background_color": "#ffffff", "theme_color": "#000000", "description": "A new Flutter project.", "orientation": "portrait-primary", "prefer_related_applications": false, "icons": [ { "src": "icons/Icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "icons/Icon-512.png", "sizes": "512x512", "type": "image/png" }, { "src": "icons/Icon-maskable-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { "src": "icons/Icon-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ] } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_include_directories(flutter_wrapper_app PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_app flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" windows-x64 $<CONFIG> VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include <url_launcher_windows/url_launcher_windows.h> void RegisterPlugins(flutter::PluginRegistry* registry) { UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include <flutter/plugin_registry.h> // Registers Flutter plugins. void RegisterPlugins(flutter::PluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) |
1 | cg: couldn't decode file contents |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | // Microsoft Visual C++ generated resource script. // #pragma code_page(65001) #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else #define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.example" "\0" VALUE "FileDescription", "15" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "15" "\0" VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "fifteen.exe" "\0" VALUE "ProductName", "15" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #include "flutter_window.h" #include <optional> #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique<flutter::FlutterViewController>( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional<LRESULT> result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ #include <flutter/dart_project.h> #include <flutter/flutter_view_controller.h> #include <memory> #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: // Creates a new FlutterWindow hosting a Flutter view running |project|. explicit FlutterWindow(const flutter::DartProject& project); virtual ~FlutterWindow(); protected: // Win32Window: bool OnCreate() override; void OnDestroy() override; LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override; private: // The project to run. flutter::DartProject project_; // The Flutter instance hosted by this window. std::unique_ptr<flutter::FlutterViewController> flutter_controller_; }; #endif // RUNNER_FLUTTER_WINDOW_H_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <flutter/dart_project.h> #include <flutter/flutter_view_controller.h> #include <windows.h> #include "flutter_window.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } // Initialize COM, so that it is available for use in the library and/or // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); flutter::DartProject project(L"data"); std::vector<std::string> command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(405, 720); if (!window.Create(L"15", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // #define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> </windowsSettings> </application> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- Windows 10 and Windows 11 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> <!-- Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!-- Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!-- Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> </application> </compatibility> </assembly> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #include "utils.h" #include <flutter_windows.h> #include <io.h> #include <stdio.h> #include <windows.h> #include <iostream> void CreateAndAttachConsole() { if (::AllocConsole()) { FILE *unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { _dup2(_fileno(stdout), 1); } if (freopen_s(&unused, "CONOUT$", "w", stderr)) { _dup2(_fileno(stdout), 2); } std::ios::sync_with_stdio(); FlutterDesktopResyncOutputStreams(); } } std::vector<std::string> GetCommandLineArguments() { // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. int argc; wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); if (argv == nullptr) { return std::vector<std::string>(); } std::vector<std::string> command_line_arguments; // Skip the first argument as it's the binary name. for (int i = 1; i < argc; i++) { command_line_arguments.push_back(Utf8FromUtf16(argv[i])); } ::LocalFree(argv); return command_line_arguments; } std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; if (target_length <= 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); int converted_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, input_length, utf8_string.data(), target_length, nullptr, nullptr); if (converted_length == 0) { return std::string(); } return utf8_string; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ #include <string> #include <vector> // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string // encoded in UTF-8. Returns an empty std::string on failure. std::string Utf8FromUtf16(const wchar_t* utf16_string); // Gets the command line arguments passed in as a std::vector<std::string>, // encoded in UTF-8. Returns an empty std::vector<std::string> on failure. std::vector<std::string> GetCommandLineArguments(); #endif // RUNNER_UTILS_H_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | #include "win32_window.h" #include <dwmapi.h> #include <flutter_windows.h> #include "resource.h" namespace { /// Window attribute that enables dark mode window decorations. /// /// Redefined in case the developer's machine has a Windows SDK older than /// version 10.0.22000.0. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; /// Registry key for app theme preference. /// /// A value of 0 indicates apps should use dark mode. A non-zero or missing /// value indicates apps should use light mode. constexpr const wchar_t kGetPreferredBrightnessRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast<int>(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast<EnableNonClientDpiScaling*>( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); } FreeLibrary(user32_module); } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registrar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::Create(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast<LONG>(origin.x), static_cast<LONG>(origin.y)}; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } UpdateTheme(window); return OnCreate(); } bool Win32Window::Show() { return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams)); auto that = static_cast<Win32Window*>(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_DESTROY: window_handle_ = nullptr; Destroy(); if (quit_on_close_) { PostQuitMessage(0); } return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast<RECT*>(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; case WM_DWMCOLORIZATIONCOLORCHANGED: UpdateTheme(hwnd); return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast<Win32Window*>( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. } void Win32Window::UpdateTheme(HWND const window) { DWORD light_mode; DWORD light_mode_size = sizeof(light_mode); LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr, &light_mode, &light_mode_size); if (result == ERROR_SUCCESS) { BOOL enable_dark_mode = light_mode == 0; DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, &enable_dark_mode, sizeof(enable_dark_mode)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ #include <windows.h> #include <functional> #include <memory> #include <string> // A class abstraction for a high DPI-aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling class Win32Window { public: struct Point { unsigned int x; unsigned int y; Point(unsigned int x, unsigned int y) : x(x), y(y) {} }; struct Size { unsigned int width; unsigned int height; Size(unsigned int width, unsigned int height) : width(width), height(height) {} }; Win32Window(); virtual ~Win32Window(); // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a // consistent size this function will scale the inputted width and height as // as appropriate for the default monitor. The window is invisible until // |Show| is called. Returns true if the window was created successfully. bool Create(const std::wstring& title, const Point& origin, const Size& size); // Show the current window. Returns true if the window was successfully shown. bool Show(); // Release OS resources associated with window. void Destroy(); // Inserts |content| into the window tree. void SetChildContent(HWND content); // Returns the backing Window handle to enable clients to set icon and other // window properties. Returns nullptr if the window has been destroyed. HWND GetHandle(); // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); // Return a RECT representing the bounds of the current client area. RECT GetClientArea(); protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that // inheriting classes can handle. virtual LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related // setup. Subclasses should return false if setup fails. virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); private: friend class WindowClassRegistrar; // OS callback called by message pump. Handles the WM_NCCREATE message which // is passed when the non-client area is being created and enables automatic // non-client DPI scaling so that the non-client area automatically // responds to changes in DPI. All other messages are handled by // MessageHandler. static LRESULT CALLBACK WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; // Update the window frame's theme to match the system theme. static void UpdateTheme(HWND const window); bool quit_on_close_ = false; // window handle for top level window. HWND window_handle_ = nullptr; // window handle for hosted content. HWND child_content_ = nullptr; }; #endif // RUNNER_WIN32_WINDOW_H_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | # Project-level configuration. cmake_minimum_required(VERSION 3.14) project(fifteen LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "fifteen") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() # Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | MIT License Copyright (c) 2023 Lars Müller Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # 15 The [15](https://en.wikipedia.org/wiki/15_puzzle) puzzle. ## App Allows creating, playing & editing puzzles. Includes a solver. Puzzles can be copied to and pasted from clipboard in hex format. You can click on the neighboring buttons of the blank spots or use WASD or slide gestures to play. Web (JS) build won't work since the board representation requires 64-bit ints; might work with the experimental WASM build mode. ## CLI A simple CLI for the solver is at `cli_solve.dart`. Run using `dart run cli_solve.dart <hex board>`, compile using `dart compile exe cli_solve.dart -o solve` (and then run using `./solve <hex board>`). The output is a sequence of puzzle states, from the given problem to the winning board, as hex, with newlines inserted for better readability. The hex format is simply a hex string of the hex digits of the 16 tiles; the blank tile is assigned 0. The winning board is stored as `123456789abcdef0` using this format. Whitespace is not allowed. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # This file configures the analyzer, which statically analyzes Dart code to # check for errors, warnings, and lints. # # The issues identified by the analyzer are surfaced in the UI of Dart-enabled # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be # invoked from the command line by running `flutter analyze`. # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints # and their documentation is published at # https://dart-lang.github.io/linter/lints/index.html. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code # or a specific dart file by using the `// ignore: name_of_lint` and # `// ignore_for_file: name_of_lint` syntax on the line or in the file # producing the lint. rules: # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import 'dart:io'; import 'lib/board.dart' as brd; typedef Board = brd.Board; // ignore_for_file: avoid_print usage() { print("arg: <hex board>"); exit(1); } void main(List<String> args) { if (args.length != 1) usage(); Board? board = brd.fromHex(args[0]); if (board == null) usage(); if (!brd.isSolvable(board!)) { print("unsolvable"); exit(1); } final linefeed = Platform.isWindows ? "\r\n" : "\n"; print([board] .followedBy(brd.solve(board)) .map((b) => brd.toHex(b, linefeed)) .join(linefeed + linefeed)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: archive: dependency: transitive description: name: archive sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted version: "3.3.7" args: dependency: transitive description: name: args sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted version: "2.4.2" async: dependency: transitive description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted version: "2.1.1" characters: dependency: transitive description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted version: "1.3.0" checked_yaml: dependency: transitive description: name: checked_yaml sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted version: "2.0.3" cli_util: dependency: transitive description: name: cli_util sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 url: "https://pub.dev" source: hosted version: "0.4.0" clock: dependency: transitive description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted version: "1.17.1" convert: dependency: transitive description: name: convert sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" url: "https://pub.dev" source: hosted version: "3.1.1" crypto: dependency: transitive description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted version: "3.0.3" fake_async: dependency: transitive description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted version: "2.0.2" file: dependency: transitive description: name: file sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted version: "6.1.4" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" url: "https://pub.dev" source: hosted version: "0.13.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" url: "https://pub.dev" source: hosted version: "2.0.2" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" image: dependency: transitive description: name: image sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf url: "https://pub.dev" source: hosted version: "4.0.17" js: dependency: transitive description: name: js sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted version: "4.8.1" lints: dependency: transitive description: name: lints sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted version: "2.1.1" matcher: dependency: transitive description: name: matcher sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted version: "0.2.0" meta: dependency: transitive description: name: meta sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted version: "1.9.1" path: dependency: transitive description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted version: "1.8.3" path_provider_linux: dependency: transitive description: name: path_provider_linux sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 url: "https://pub.dev" source: hosted version: "2.2.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 url: "https://pub.dev" source: hosted version: "2.1.0" path_provider_windows: dependency: transitive description: name: path_provider_windows sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da url: "https://pub.dev" source: hosted version: "2.2.0" petitparser: dependency: transitive description: name: petitparser sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted version: "5.4.0" platform: dependency: transitive description: name: platform sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" url: "https://pub.dev" source: hosted version: "2.1.5" pointycastle: dependency: transitive description: name: pointycastle sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted version: "3.7.3" shared_preferences: dependency: "direct main" description: name: shared_preferences sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 url: "https://pub.dev" source: hosted version: "2.3.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" url: "https://pub.dev" source: hosted version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" url: "https://pub.dev" source: hosted version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" url: "https://pub.dev" source: hosted version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d url: "https://pub.dev" source: hosted version: "2.3.0" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" source_span: dependency: transitive description: name: source_span sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted version: "0.5.1" typed_data: dependency: transitive description: name: typed_data sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" url: "https://pub.dev" source: hosted version: "6.0.37" url_launcher_ios: dependency: transitive description: name: url_launcher_ios sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" url: "https://pub.dev" source: hosted version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" url: "https://pub.dev" source: hosted version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted version: "3.0.7" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted version: "2.1.4" win32: dependency: transitive description: name: win32 sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 url: "https://pub.dev" source: hosted version: "5.0.6" xdg_directories: dependency: transitive description: name: xdg_directories sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff url: "https://pub.dev" source: hosted version: "1.0.1" xml: dependency: transitive description: name: xml sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted version: "6.3.0" yaml: dependency: transitive description: name: yaml sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted version: "3.1.2" sdks: dart: ">=3.0.6 <4.0.0" flutter: ">=3.10.0" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | name: "fifteen" description: The 15 puzzle game. publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: sdk: '>=3.0.6 <4.0.0' dependencies: flutter: sdk: flutter shared_preferences: ^2.2.0 url_launcher: ^6.1.12 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 flutter_launcher_icons: "^0.13.1" flutter_launcher_icons: android: "launcher_icon" ios: true image_path: "assets/icon.png" min_sdk_android: 16 web: generate: true image_path: "assets/icon.png" background_color: "#ffffff" theme_color: "#000000" windows: generate: true image_path: "assets/icon.png" icon_size: 128 macos: generate: true image_path: "assets/icon.png" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ; Brain-Flak implementation in Chicken Scheme for Code Guessing Round 39 ; Supports line comments using `#`, ignores invalid characters ; Compilation & invocation: `csc cg39.scm && ./cg39 FILE [ARGS ...]` (import (chicken process-context)) (define (parse port) (define (paren closing) (read-char port) (let ((sub (parse port))) (assert (eqv? (read-char port) closing)) (cons (cons closing sub) (parse port)))) (let ((c (peek-char port))) (case c ((#\) #\] #\} #\> #!eof) '()) ((#\() (paren #\))) ((#\[) (paren #\])) ((#\{) (paren #\})) ((#\<) (paren #\>)) (else (if (eqv? (read-char port) #\#) (do () ((memv (read-char port) '(#\newline #!eof))))) (parse port))))) (define (exec exp active) (let ((inactive '())) (define (pop) (if (null? active) 0 (let ((top (car active))) (set! active (cdr active)) top))) (define (push x) (set! active (cons x active))) (define (toggle) (let ((a active)) (set! active inactive) (set! inactive a))) (define (ctx-eval exp) (if (null? exp) 0 (let ((sub (cdr exp)) (nilad (null? (cdr exp)))) (if (list? (car exp)) (apply + (map ctx-eval exp)) (case (car exp) ((#\)) (if nilad 1 (let ((k (ctx-eval sub))) (push k) k))) ((#\]) (if nilad (length active) (- (ctx-eval sub)))) ((#\}) (if nilad (pop) (do ((sum 0)) ((or (null? active) (= (car active) 0)) sum) (set! sum (+ sum (ctx-eval sub)))))) ((#\>) (begin (if nilad (toggle) (ctx-eval sub)) 0))))))) (ctx-eval exp)) (for-each (lambda (x) (display x) (newline)) active)) (let ((args (command-line-arguments))) (call-with-input-file (car args) (lambda (port) (let ((exp (parse port))) (assert (eof-object? (read-char port))) (exec exp (map string->number (reverse (cdr args)))))))) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | package main import ( "os" "fmt" "bufio" ) func pop[T any](slice []T) ([]T, T) { return slice[:len(slice)-1], slice[len(slice) - 1] } func apply(op byte, a, b int32) int32 { switch op { case '+': return a + b case '-': return a - b case '*': return a * b case '/': return a / b } panic("invalid op") } // 1*1 + 2*2 // 1*1 + 2 * 3 // 3 - 2 - 1-1 func main() { var operands []int32 var ops []byte var precedences []uint // higher is lower var eval func() int32 eval = func() int32 { if len(operands) == 0 { panic("no operands") } if len(ops) == len(operands) { panic("too few operands") } for { if len(ops) == 0 { res := operands[0] operands = nil return res } var topOp byte var topPrec uint var lhs, rhs int32 ops, topOp = pop(ops) precedences, topPrec = pop(precedences) operands, rhs = pop(operands) if len(ops) > 0 { botPrec := precedences[len(precedences) - 1] if botPrec <= topPrec { return apply(topOp, eval(), rhs) } } operands, lhs = pop(operands) operands = append(operands, apply(topOp, lhs, rhs)) } } stdin := bufio.NewReader(os.Stdin) countSpaces := func() (spaces uint) { for { c, _ := stdin.ReadByte() if c != ' ' { break } spaces++ } stdin.UnreadByte() return } for { leadingSpaces := countSpaces() c, err := stdin.ReadByte() if c == '\n' || err != nil { fmt.Println(eval()) } if err != nil { return } if c >= '0' && c <= '9' { if len(operands) > len(ops) { panic("too many operands") } operand := int32(c - '0') for { c, _ := stdin.ReadByte() if c < '0' || c > '9' { break } operand = 10 * operand + int32(c - '0') } stdin.UnreadByte() operands = append(operands, operand) } else if c == '+' || c == '-' || c == '*' || c == '/' { if len(operands) < len(ops) { panic("no operand") } trailingSpaces := countSpaces() var precedence uint if trailingSpaces > leadingSpaces { precedence = trailingSpaces } else { precedence = leadingSpaces } precedences = append(precedences, precedence) ops = append(ops, c) } } } |
post a comment