100 lines
2.7 kB
1
defmodule BlogWeb.GridLive do
2
use BlogWeb, :live_view
3
require Logger
4
import Bitwise
5
6
@grid_size 100
7
@total_cells @grid_size * @grid_size
8
@topic "grid_state"
9
10
def mount(_params, _session, socket) do
11
if connected?(socket) do
12
Phoenix.PubSub.subscribe(Blog.PubSub, @topic)
13
end
14
15
# Get or create grid state from ETS
16
grid_state = get_or_create_grid_state()
17
18
{:ok, assign(socket,
19
grid_state: grid_state,
20
grid_size: @grid_size
21
)}
22
end
23
24
def handle_event("toggle", %{"index" => index}, socket) do
25
index = String.to_integer(index)
26
new_state = toggle_bit(socket.assigns.grid_state, index)
27
:ets.insert(:grid_state, {:state, new_state})
28
29
# Broadcast the change
30
Phoenix.PubSub.broadcast(Blog.PubSub, @topic, {:grid_update, new_state})
31
32
{:noreply, assign(socket, grid_state: new_state)}
33
end
34
35
def handle_info({:grid_update, new_state}, socket) do
36
{:noreply, assign(socket, grid_state: new_state)}
37
end
38
39
defp get_or_create_grid_state do
40
try do
41
:ets.new(:grid_state, [:set, :public, :named_table])
42
initial_state = :binary.copy(<<0>>, div(@total_cells, 8) + 1)
43
:ets.insert(:grid_state, {:state, initial_state})
44
initial_state
45
rescue
46
ArgumentError ->
47
# Table exists, get current state
48
[{:state, state}] = :ets.lookup(:grid_state, :state)
49
state
50
end
51
end
52
53
defp toggle_bit(binary, index) do
54
byte_index = div(index, 8)
55
bit_index = rem(index, 8)
56
57
<<prefix::binary-size(byte_index),
58
byte::integer,
59
rest::binary>> = binary
60
61
new_byte = bxor(byte, 1 <<< bit_index)
62
63
<<prefix::binary, new_byte::integer, rest::binary>>
64
end
65
66
defp bit_set?(binary, index) do
67
byte_index = div(index, 8)
68
bit_index = rem(index, 8)
69
70
<<_prefix::binary-size(byte_index),
71
byte::integer,
72
_rest::binary>> = binary
73
74
(byte &&& (1 <<< bit_index)) != 0
75
end
76
77
def render(assigns) do
78
~H"""
79
<div class="p-4">
80
<h1 class="text-2xl font-bold mb-4">Shared Grid</h1>
81
<div class="grid" style="grid-template-columns: repeat(100, 20px); gap: 1px; background-color: #eee; padding: 1px; width: fit-content;">
82
<%= for y <- 0..(@grid_size-1) do %>
83
<%= for x <- 0..(@grid_size-1) do %>
84
<% index = y * @grid_size + x %>
85
<div class="bg-white">
86
<input
87
type="checkbox"
88
class="w-5 h-5 m-0 cursor-pointer"
89
checked={bit_set?(@grid_state, index)}
90
phx-click="toggle"
91
phx-value-index={index}
92
/>
93
</div>
94
<% end %>
95
<% end %>
96
</div>
97
</div>
98
"""
99
end
100
end
101