今日已更新 233 条资讯 | 累计 20205 条内容
关于我们

标签:#tco

找到 34 篇相关文章

AI 资讯

Building a Bitcoin Education Platform, Contributing to Open Source, and Surviving a Hackathon

A few months ago, I didn't expect that I'd be spending my days debugging authentication flows, opening pull requests, analyzing backend architectures, and building a Bitcoin education platform during a hackathon. Yet here we are. What started as curiosity about Bitcoin turned into one of the most intense learning experiences I've had as a builder, and honestly, I wouldn't trade it for anything. This is the story of how I joined Hack4Freedom Lagos 2026, helped build BitPath, contributed to open source, discovered OpenCode, and learned that software engineering is often just solving one problem after another until things somehow start working. How I Ended Up Building in Bitcoin My interest in Bitcoin didn't start from price charts or trading. What attracted me was the builder ecosystem around it. I've contributed to open source before, so I already appreciated the value of collaborative software development. But what stood out about Bitcoin was how deeply open source is woven into the culture. In many ecosystems, open source feels like an option. In Bitcoin, it feels like a foundation. Everywhere I looked, people were building in public, contributing to projects, improving documentation, reviewing code, and helping newcomers find their footing. That environment made me want to participate more deeply. When the opportunity came to join the Hack4Freedom Lagos 2026 hackathon, I said yes. The Project: BitPath Our team worked on BitPath, an AI-powered learn-and-earn platform designed to make Bitcoin education more accessible. The idea was simple: Instead of overwhelming learners with technical concepts, BitPath uses conversational learning experiences, AI tutoring, quizzes, progress tracking, and rewards to help users learn Bitcoin and financial literacy in a more engaging way. Our stack looked something like this: Frontend Next.js TypeScript Tailwind CSS Zustand Backend NestJS PostgreSQL Redis Queue processing Additional Services Google OAuth OpenAI APIs Lightning Network

2026-06-14 原文 →
开发者

AtCoder Beginner Contest 462 参加記録と解答例 (A E問題)

本記事は、AtCoder Beginner Contest 462 (ABC462) に参加した際の、A〜E問題の復習と解答の備忘録です。コンテスト中に考えた解法の方針や、提出したPythonのコードについて整理しています。 A - Secret Numbers / 実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: None 配点 : 100 点 問題文 英小文字と数字のみからなる文字列 $S$ が与えられます。 $S$ から数字である文字だけを取り出し、元の順序のまま並べた文字列を求めてください。 制約 $S$ は英小文字と数字のみからなる長さ 1 以上 50 以下の文字列 自分の解答の方針 一文字づつ数字かどうかを判定し、数字のみを配列に入れて出力する。 提出の時には数字かどうかの判定は0-9のどれかに含まれているかを調べたが、解説ではPythonは isdigit() で数値かどうかを調べられるらしい。 提出したコード S = list ( input ()) T = [] for i in range ( len ( S )): if S [ i ] in [ " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " , " 8 " , " 9 " , " 0 " ]: T . append ( S [ i ]) print ( "" . join ( T )) B - Gift / 実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: None 配点 : 200 点 問題文 人 1 から人 $N$ の $N$ 人がギフトを送り合いました。 人 $i$ は人 $A_{i,1}, A_{i,2}, \dots, A_{i,K_i}$ の $K_i$ 人にギフトを送りました。 $i=1,2,\dots,N$ に対し、人 $i$ にギフトを送った人を全て求めてください。 制約 $2 \le N \le 100$ $1 \le K_i \le N-1$ $1 \le A_{i,1} < A_{i,2} < \dots < A_{i,K_i} \le N$ $A_{i,j} \neq i$ 入力される値は全て整数 自分の解答の方針 辞書に人 $i$ と、その人にギフトを送った人の番号をリストとして持つことを考える。 入力で受け取った、ギフトを送った人と送られた人すべてに対して辞書に登録し、結果を出力する。 提出したコード N = int ( input ()) dct = dict () for i in range ( N ): dct [ i + 1 ] = [] for i in range ( N ): A = list ( map ( int , input (). split ())) for j in range ( 1 , A [ 0 ] + 1 ): dct [ A [ j ]]. append ( i + 1 ) for i in range ( N ): print ( " " . join ([ str ( len ( dct [ i + 1 ]))] + list ( map ( str , dct [ i + 1 ])))) C - Not Covered Points / 実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: None 配点 : 300 点 問題文 2 次元平面上に点 1 から点 $N$ の $N$ 個の点があります。点 $i$ $(1 \le i \le N)$ の座標は $(X_i, Y_i)$ です。ここで、 $X, Y$ はそれぞれ $(1,2,\dots,N)$ の順列であることが保証されます。 左下の頂点を $(0,0)$ 、右上の頂点を $(X_i, Y_i)$ とする $x$ 軸に平行な辺と $y$ 軸に平行な辺のみからなる長方形の内部(辺上を含まない)に点 1 から点 $N$ までの $N$ 個の点をどれも含まないような $i$ の個数を求めてください。 制約 $1 \le N \le 3 \times 10^5$ $1 \le X_i, Y_i \le N$ $X, Y$ はそれぞれ $(1,2,\dots,N)$ の順列 入力される値は全て整数 自分の解答の方針 端から考えたいので、初めに $X$ についてソートする。 $X$ が小さい順に見ていっ​​たとき、現在の点が作る長方形の内部にほかの点が含まれるかどうかは、、これまでに走査した($X$座標が自身より小さい)点の中に、自身より $Y$ 座標

2026-06-13 原文 →
AI 资讯

Frameworks Rot. The Platform Doesn't.

A decision memo for anyone staring at their package.json and wondering. Most arguments for leaving your SPA framework center on the upgrade treadmill — the endless cycle of major-version migrations, dependency churn, and build-tool turnover. That argument is real but incomplete, and on its own it has never been decisive: every framework shop has learned to live with the treadmill. There's a stronger case, built on four pillars that compound with each other. First, total cost of ownership : vanilla JavaScript on the web platform has unusual TCO properties, dominated by a depreciation curve that is nearly flat. Code written against the platform does not rot, because its substrate does not change. Over long horizons, this single property outweighs almost every per-feature productivity argument in a framework's favor. Second, the labor market : the pool of people who can work on vanilla JavaScript is not a niche within the frontend market — it is the entire frontend market, plus most of the backend market. Every framework developer is, underneath, a JavaScript developer. The reverse is not true. If you hire for a specific framework, you're hiring from a subset while telling yourself you're hiring from the mainstream. Third, AI leverage : engineers now produce a growing share of code with AI assistance, and the economics of that assistance differ sharply by target. The web platform is a small, stable, exhaustively documented body of knowledge; a framework ecosystem is a large, fast-mutating one whose training data is perpetually stale. AI coding tools are measurably more reliable on the former. As AI-assisted development becomes the dominant mode of production, the substrate that AI handles best becomes the cheaper substrate — and the gap widens every year the platform stays still while frameworks move. Fourth, architecture : porting to Web Components is not a transliteration of the same design into different syntax. The platform pushes toward a genuinely different archi

2026-06-13 原文 →
AI 资讯

Blazor SSR Gets Client-Side Validation in .NET 11 Preview 5 — No More Round-Trips Just to Show a Red Border

Blazor SSR Gets Client-Side Validation in .NET 11 Preview 5 If you've built Blazor Server-Side Rendering (SSR) forms, you know the pain: a user fills out a form, hits submit, the form posts to the server, the server runs validation, and only then does the user see the "This field is required" message next to the empty email field. That round-trip latency adds up. It breaks the immediacy users expect from modern web apps. .NET 11 Preview 5 fixes this. Blazor SSR forms now get instant, in-browser validation feedback — no server required. The server renders your validation rules as metadata, and Blazor's JavaScript enforces them client-side. Same DataAnnotationsValidator component you already use. Zero code changes needed. Let's break down how it works. Before .NET 11: The SSR Validation Gap In .NET 8 and 9, Blazor SSR rendered HTML on the server and sent it down. Validation only ran server-side — on form submission. If a field was invalid, the whole form posted to the server, came back with validation messages, and re-rendered. Interactive Blazor modes (Server, WebAssembly, Auto) had instant client-side validation because an active SignalR circuit or WASM runtime ran the validation logic locally. But SSR mode — the simplest, most performant option — was left out. The result? Developers who chose SSR Blazor for its simplicity had to choose between: Accepting the laggy validation UX Adding a second JavaScript validation library (and maintaining two validation rulesets) Re-architecting to use an interactive render mode None of these are great options. What Changed in .NET 11 Preview 5 The .NET team shipped two PRs ( #66441 and #66420 ) that bring unobtrusive client-side validation to Blazor SSR forms. The key insight: The .NET model stays the single source of truth. On form render, the server serializes your DataAnnotations validation rules into HTML metadata attributes. Blazor's JavaScript reads those attributes and applies them client-side — the same approach ASP.NET M

2026-06-13 原文 →
AI 资讯

I Got Bored of LeetCode, so I Built a Coding RPG

https://dsa-life-simulator-frontend.vercel.app"I made a free tool to make DSA practice feel like an RPG — would like feedback from this community"Been grinding DSA for months and it never felt fun. So I built something. What it does: 🏟️ Real-time 1v1 Arena battles against other devs 🧪 Lab to create and publish your own challenges 🏘️ Community Hub to attempt others' challenges 📖 AI writes your weekly coding journey as a life story 🎮 XP, credits, levels, leaderboards Stack: React + Tailwind + Firebase + Node.js + Socket.IO + Groq AI Still early — would genuinely love feedback from people who've felt the pain of traditional DSA prep.

2026-06-11 原文 →
AI 资讯

Delete Node in a Linked List

Problem Link - https://leetcode.com/problems/delete-node-in-a-linked-list/ This is one of those interview questions that looks impossible at first. Normally, to delete a node from a Linked List, we need access to the previous node. But in this problem, we're only given the node that needs to be deleted. No head. No previous pointer. So how do we remove it? Let's understand the trick. Problem Statement Write a function to delete a node in a singly linked list. You are not given the head of the list. Instead, you are given only the node that needs to be deleted. Example Input: 4 -> 5 -> 1 -> 9 node = 5 Output: 4 -> 1 -> 9 Initial Thought Normally we delete a node like this: prev.next = node.next But here: We don't have prev We don't have head So the usual deletion approach is impossible. Key Observation Although we cannot delete the current node directly, we can make it look like it never existed. Consider: 4 -> 5 -> 1 -> 9 We need to delete: 5 Instead of removing node 5 , copy the value of the next node into it. 4 -> 1 -> 1 -> 9 Now remove the next node. 4 -> 1 -> 9 The original value 5 has disappeared. Mission accomplished. Intuition Copy the next node's value into the current node. Skip the next node. The current node now behaves as if it was deleted. Since the problem guarantees that the given node is not the tail node, a next node will always exist. Dry Run Input 4 -> 5 -> 1 -> 9 node = 5 Current node: 5 Next node: 1 Step 1 Copy next node value. node.val = node.next.val List becomes: 4 -> 1 -> 1 -> 9 Step 2 Skip next node. node.next = node.next.next List becomes: 4 -> 1 -> 9 Done. Optimal Java Solution class Solution { public void deleteNode ( ListNode node ) { ListNode cur = node . next ; node . val = cur . val ; node . next = cur . next ; } } Even Shorter Version class Solution { public void deleteNode ( ListNode node ) { node . val = node . next . val ; node . next = node . next . next ; } } Complexity Analysis Metric Complexity Time Complexity O(1) Space Comp

2026-06-10 原文 →
AI 资讯

Learn Leetcode daily with Claude code mentor

This is a submission for the GitHub Finish-Up-A-Thon Challenge What I Built After being abandoned for several months, I have come back to build and complete Claude with LeetCode, which is a DSA learning system that automates daily algorithm education with Claude code directly inside GitHub repo. Every time I submit an accepted solution on Leetcode, the Github workflow fetches my Leetcode account data and commit the problem with the solution to the repo. Claude will then run on a fixed schedule and automatically generates a full structured lecture, covering the DSA topic, brute force through optimal solutions in Python, complexity analysis, and a YouTube video packaged in a GitHub Issue. This project means a lot to me because it merges two things I care about daily: now not only can I solve Leetcode problem, my solution is automatically analyzed by a powerful AI agent mentor. Demo Link to my project: https://github.com/Stewie-pixel/claude-with-leetcode.git Link to my application walkthrough: https://youtu.be/ClWdW3v9JJ0 The Comeback Story At first this was only a project to store the Leetcode questions I have solved. The process required manual pushing the problem to the repo and nothing special. Later I have added the automation workflow to fetch data from my Leetcode account, Claude will be prompted like an experienced dsa mentor from Claude and skill.md file to give a thorough analysis on that problem. And at the end of the day, Github Copilot workflow will give a daily summary report to cover my daily progress. My Experience with GitHub Copilot I built a DSA Mentor skill that gives Copilot the full context of what a lecture should contain: topic identification, the brute force to optimal approach structure, complexity analysis requirements, and the YouTube search step. Without Copilot, writing the dsaMentor.js orchestration logic and getting the agent to consistently produce structured markdown output would have taken significantly longer. I then use Copilot cli

2026-06-06 原文 →
AI 资讯

A Beginner-Friendly Mental Model for Bitcoin Transactions

Bitcoin can look simple from the outside: paste an address, choose an amount, send. Under that simple interface are several concepts that are useful for developers and technical beginners to understand. This post is not trading advice and does not discuss price. It is a practical mental model for what is happening when someone sends Bitcoin. 1. A wallet does not "hold coins" the way an app balance does Many beginners imagine a wallet as a container full of coins. That is close enough for casual conversation, but it can be misleading. A Bitcoin wallet manages keys and helps create transactions. The Bitcoin network tracks spendable outputs on the ledger. When you send BTC, the wallet constructs a transaction that spends previous outputs and creates new outputs. You do not need to master every detail on day one, but the high-level idea matters: control of keys controls the ability to spend. 2. An address is a destination, not an identity A Bitcoin address is where funds can be sent. It is not a username and it is not automatically tied to a person in the way a social profile is. Before sending, beginners should check the address carefully. A small copy-paste mistake can be permanent. Malware can also replace clipboard contents, so visually checking the beginning and ending characters is a useful habit. For larger transfers, a tiny test transaction can reduce risk. 3. Fees are about block space Bitcoin transactions compete for limited block space. A fee is not a tip to a company. It is part of the transaction economics that helps miners decide which transactions to include. When the network is busy, low-fee transactions may wait longer. When the network is quieter, confirmations may happen faster. The beginner lesson is simple: do not assume "sent" means "fully settled." Check confirmations and understand that fee choice can affect waiting time. 4. The mempool is a waiting area Before a transaction is confirmed in a block, it may sit in the mempool, which is a pool of u

2026-06-05 原文 →
AI 资讯

Leetcode 150 | Day 2: Remove Element - Naive vs. Optimized

Leetcode 27: Remove Element Leetcode 27 asks us to remove a specific value from an array. The value to be removed is passed in as a parameter to the function along with the array. Just as we did in Day 1, we will cover a naive approach and an optimized approach and discuss the trade-offs between them. I think in the end there's a pretty clear winner. Let's get started. For both approaches we will use the following values: nums = [1, 3, 3, 2, 4] val = 3 Approach 1: Naive (For Loop + Splice) This approach uses a for loop and leverages .splice() for removals. Solution: var removeElement = function ( nums , val ) { let k = 0 ; for ( let i = 0 ; i < nums . length ; i ++ ) { if ( nums [ i ] === val ) { nums . splice ( i , 1 ); i -- ; } else { k ++ ; } } return k ; }; We begin by initializing a variable k to 0. We then enter the for loop. The condition is standard: create a variable i initialized to 0, continue looping while i is less than nums.length to avoid going past the end of the array, and increment by 1 each time through. Each iteration checks one condition: whether nums[i] is equal to val . If true, we call .splice() on the array. The arguments we pass to splice are i and 1 . i is the index at which we want to start removing, and 1 tells splice to remove only that one element. We then decrement i . The reason for this took me some time to wrap my brain around, so I have included a visual below to make it concrete. The core issue is this: when splice removes an element, every element to the right shifts one index to the left. Without i-- , the loop would increment i on the next iteration and skip right over the element that just shifted in. i-- counteracts that by stepping i back, so after the loop increments it, i lands exactly where the shifted element now sits. If nums[i] !== val , we skip the splice and increment k instead. At the end we return k , which holds the count of elements remaining after all occurrences of val have been removed. Time complexity: O(n²)

2026-06-04 原文 →
AI 资讯

F# vs C# 3 — Conclusions

What can I say. Anyone claiming that F# is good mostly for finance and data processing and C# for everything else, has probably never written a single line of practical F# code. In previous two parts of the article, I tried to demonstrate that with F# you can achieve the same goals as with C#, but with less verbose, repetitive, structural code. How it started. At some point, developers realized that global state with unrestricted data access causes many side effects, producing insecure, error-prone, and hard-to-maintain code as software grows larger. That is when the idea emerged to bring data and the code operating on it together into a single unit, restricting direct access to the unit’s internal state and making software more secure and predictable. This is how data encapsulation was born. Alongside encapsulation, abstraction was introduced — the process of hiding how behavior works. Encapsulation ( hiding data ) and abstraction ( hiding behavior ) remain two foundational pillars of Object-Oriented Programming. And that is how OOP has worked ever since — developers bring data and behavior together ( classes ) and define abstractions for them ( interfaces ). For example, for C# developers — including myself — this has become a daily routine. And we rarely question it, because OOP languages like C# leave us little choice but to structure code this way. But if you ask yourself whether this repetitive routine is always necessary, the answer is — no. You don’t need OOP concepts to build stateless, streamlined request–response, data-processing pipelines, because in such systems there is no long-lived state to hide and protect. You have a request, and almost immediately you have a response. After that, everything is gone. That is what I tried to demonstrate in the first two parts of this article by applying FP concepts. And even if you have a classical desktop application, you don’t always need to approach it in an OOP way. Functional programming handles side effects no

2026-06-03 原文 →
AI 资讯

Leetcode 150 | Day 1: Merge Sorted Array - Naive vs. Optimized

There's been no shortage of debate lately about whether grinding Leetcode still makes sense in the age of AI. I think it does. AI is a powerful tool, but it was built by humans; which means it inherited our strengths, our blind spots, and our biases. Leaning on it entirely without understanding what's happening under the hood is a risk. A mentor once told me: those who refuse to use AI are not hireable. But neither are those who rely on it entirely. Learning deeply is how you stay on the right side of that line. This is my journey into just that - learning deeply. Day 1 Leetcode 88: Merge Sorted Array This is an interesting problem. You begin with 4 pieces of data — 2 arrays and 2 integers: nums1 : a sorted array whose length equals nums1.length + nums2.length . The first m elements are valid numbers; the remaining indexes hold 0 s as placeholders. nums2 : a sorted array containing only valid numbers, with a length of n . m : the count of valid numbers in nums1. n : the count of valid numbers in nums2. The objective is to merge both arrays into sorted order in place . Since nums1 is already sized to hold every valid element from both arrays, it's where the final sorted result will live. Approach 1: Naive (Splice + Sort) This solution is 2 lines of code. That's it. It's a testament to how much ES6 advanced JavaScript. nums1 . splice ( m , n , ... nums2 ); nums1 . sort (( a , b ) => a - b ); Here's how it works. We start by calling .splice() on nums1. While .splice() has many use cases, here's what each argument is doing in this context: m : the index where we start deleting elements. Since m is the count of valid numbers in nums1, starting at index m puts us right at the first placeholder 0 — exactly where we want to be. n : the number of elements to delete. Since n equals the length of nums2, we're deleting exactly as many placeholders as we have values to insert. ...nums2 : the values we want to insert in place of the deleted elements. The ... is the spread operato

2026-06-02 原文 →
AI 资讯

A .NET Dinosaur in Web3. Day 18 - Automated Market Maker

🏦 Day 6 of 7: Building a Mini Uniswap in 80 Lines of Solidity Imagine a vending machine. It has 1,000 coffee beans and 1,000 coins. No menu, no cashier — just one iron rule: the product of the two numbers inside must never decrease. That's it! This is how Uniswap works — and this is what I built on Day 6, coming from .NET. Here's how, why it's elegant, and where you can step on a rake. Why an Order Book Doesn't Work on a Blockchain Traditional exchanges — Binance, NYSE, any CEX — run on an order book . Market makers post bids and asks. A matching engine pairs them. Millions of updates per second, all in a centralised database. In a blockchain, this is impossible. Transactions take 12 seconds. Every state change costs gas. Storing millions of constantly changing orders would eat all the profit before a single trade completes. Uniswap's solution: replace the order book with a liquidity pool — a smart contract holding two tokens — and replace the matching engine with pure math. Just a formula — below. x · y = k — The Formula That Broke Finance The Constant Product Invariant : x · y = k Where x is the reserve of Token0, y is the reserve of Token1, and k is a constant that must never decrease during swaps. When a trader sells Token0 into the pool, x increases. To keep k constant, y must decrease — the contract sends out Token1. The price is determined automatically by the ratio of reserves. Live example with numbers: Pool: 1,000 Token0, 1,000 Token1. k = 1,000,000. Trader sells 100 Token0: amountOut = (reserveOut × amountIn) / (reserveIn + amountIn) amountOut = (1000 × 100) / (1000 + 100) amountOut = 100,000 / 1,100 amountOut ≈ 90.9 Token1 The trader gets ~90.9, not 100. That gap is slippage — and it's not a bug. It's the formula protecting the pool. The more you buy relative to pool size, the worse your price gets. Naturally. Mathematically. After the swap: pool has 1,100 Token0 and ~909.1 Token1. k ≈ 1,000,000. Invariant holds. The Contract: SimpleAMM Three functions.

2026-05-31 原文 →
AI 资讯

2487. Remove Nodes From Linked List

In this post i'm gone explain liked list an famous leetcode problem that is " Remove Nodes from linked list ". Problem Statement: You are given the head of a linked list. Remove every node which has a node with a greater value anywhere to the right side of it. Return the head of the modified linked list. Example 1: Input: head = [5,2,13,3,8] Output: [13,8] Explanation: The nodes that should be removed are 5, 2 and 3. Node 13 is to the right of node 5. Node 13 is to the right of node 2. Node 8 is to the right of node 3. Explanation: In this problem statement state that remove the nodes which have the right side (any place) element greater than. let's understand with given example. Node 13 is the right side of the 5,2 nodes thats why 2,5 should be remove. Node 8 is the right side of 3 node thats why 3 should be remove. final result would be [13,8] Solution of the problem: `/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } */ /** * @param {ListNode} head * @return {ListNode} */ const reverList = function(head){ let prev = null; let curr = head; let next = null; while(curr!=null){ next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } var removeNodes = function(head) { // reverse list let reversList = reverList(head); let maxNode = reversList; let prevNode = reversList; let currNode = reversList.next; // removed list while(currNode != null){ if(maxNode.val > currNode.val){ currNode = currNode.next; }else{ maxNode = currNode; prevNode.next = currNode; prevNode = prevNode.next; currNode = currNode.next; } } prevNode.next = null; // reverse list return reverList(reversList); };` If you have any query or suggestions leave your expression👨🏿‍💻🙌.

2026-05-31 原文 →
AI 资讯

로봇 두 대가 말 없이 협업? 피규어 AI 암묵적 협업 기술의 비밀

로봇 두 대가 말 한마디 없이 방을 정리했다, 그런데 진짜 질문은 '어떻게'가 아니다 협업의 정의가 바뀌고 있다. 인간끼리도 아니고, 인간과 로봇도 아니라, 로봇과 로봇 사이에서. TL;DR : 피규어 AI의 휴머노이드 두 대가 언어 없이 2분 만에 침실 정리에 성공했다. 기술 자체보다 흥미로운 것은, 이 '눈치'가 어떻게 만들어졌는가이다. 로봇 협업이 인간 협업의 방식을 모방한 게 아니라, 아예 다른 방식으로 진화하고 있다는 신호다. 로봇 산업에는 잘 알려지지 않은 규칙이 하나 있다. 로봇을 한 대 잘 만드는 것보다, 두 대가 함께 작동하게 만드는 것이 기하급수적으로 어렵다는 것. 보스턴 다이내믹스는 수십 년 동안 혼자 뛰고, 혼자 문을 열고, 혼자 계단을 오르는 로봇을 만들어왔다. 테슬라의 옵티머스는 혼자 부품을 집고, 혼자 배터리를 나른다. 그런데 피규어 AI는 올해 다른 질문을 던졌다. "두 대가 서로 말을 하지 않아도, 협력할 수 있을까?" 그리고 최근 그 답이 나왔다. 2분이었다. 먼저, '눈치'라는 단어를 다시 생각해야 한다 우리가 일상에서 쓰는 '눈치'는 상당히 복잡한 인지 활동이다. 상대방의 행동을 보면서, 다음 행동을 예측하고, 내 행동을 조율하고, 충돌을 피하고, 빈틈을 채우는 것. 인간은 이걸 언어 없이, 심지어 시선 교환만으로 해낸다. 오랜 시간을 함께한 팀에서, 숙련된 주방의 요리사들 사이에서, 그리고 가족 사이에서. 그런데 이 능력은 학습된 것이지, 타고난 것이 아니다. 아이들은 눈치가 없다. 신입 직원도 눈치가 없다. 수백 번의 상호작용과 실수와 교정을 거쳐야 비로소 '눈치'가 생긴다. 피규어 AI의 휴머노이드 두 대는 이 과정을 어떻게 압축했을까. 보도에 따르면 이들은 사전에 언어 명령이나 역할 분담 지시 없이, 상대 로봇의 행동을 실시간으로 인식하고 자신의 다음 동작을 결정했다. 공간을 나눠 쓰고, 같은 물건에 손을 뻗지 않고, 한쪽이 멈추면 다른 쪽이 채웠다. 이것을 연구자들은 '암묵적 협업(implicit collaboration)'이라고 부른다. 쉽게 말하면, 로봇이 눈치를 배웠다는 뜻이다. 두 대가 함께 움직인다는 것의 기술적 의미 단일 로봇의 작동 원리는 비교적 단순하게 설명할 수 있다. 센서가 환경을 인식하고, 모델이 행동을 결정하고, 액추에이터가 실행한다. 루프가 하나다. 두 대가 함께 움직이는 순간, 루프가 두 개가 아니라 세 개가 된다. 로봇 A의 루프, 로봇 B의 루프, 그리고 A와 B가 서로를 환경으로 인식하면서 생기는 상호작용 루프. 이 세 번째 루프가 문제다. A의 행동이 B의 환경을 바꾸고, 그 변화가 다시 B의 행동을 바꾸고, 그 행동이 또 A의 환경을 바꾼다. 루프가 루프를 먹는 구조다. 이것을 중앙에서 통제하는 방식은 예전부터 존재했다. 공장 자동화에서 쓰이는 PLC(프로그래머블 로직 컨트롤러) 방식이 대표적이다. A는 1번 작업, B는 2번 작업, 충돌 시 A가 우선 — 이런 식으로 모든 경우의 수를 미리 프로그래밍한다. 정해진 공간, 정해진 물건, 정해진 순서. 공장에서는 작동한다. 일상에서는 작동하지 않는다. 침실은 공장이 아니다. 물건의 위치가 매번 다르고, 침대 정리와 바닥 정리가 동시에 일어나야 할 수도 있고, 하나가 예상치 못한 물건을 발견하면 계획 전체가 바뀐다. 규칙 기반의 중앙 통제로는 불가능하다. 피규어 AI가 선택한 방향은 분산 의사결정이었다. 각 로봇이 독립적으로 환경을 인식하고, 상대 로봇의 현재 상태를 하나의 입력값으로 받아들이면서, 스스로 다음 행동을 결정하는 방식이다. 중앙 관제탑이 없다. 각자가 판단하되, 서로를 인식한다. 이것이 인간의 눈치와 구조적으로 가장 유사한 접근이다. 2분이라는 숫자가 중요한 이유 2분. 이 숫자를 처음 들으면 "겨우 2분?"이라고 생각할 수 있다. 그런데 맥락을 알면 반응이 바뀐다. 로봇이 단독으로 침실을 정리하는 데 걸리는 시간과 비교해보자. 현재 가장 발전한 단일 휴머노이드 로봇들의 가사 작업 수행 속도는, 같은 작업을 인간이 하는 것보다 보통 3배에서 10배 느리다. 동작이 느린 것도 있

2026-05-30 原文 →